Commit Graph

87 Commits

Author SHA1 Message Date
ZhenYi
1deea4c671 fix(frontend): resolve TypeScript type errors in repository pages
- commits.tsx: fix Unix timestamp (time_secs) not multiplied by 1000
- RoomMessageSearch.tsx: add explicit generic type for resp.data
- RoomPinPanel.tsx: make sender_id optional (string | null)
- message-list.tsx: remove unused index variable in map
- repository-context.tsx: use correct RepoInfo field names
- use-audio-recording.ts: use audioStream state instead of undefined var
- universal-ws.ts: rename unused id to _id
2026-04-27 16:39:43 +08:00
ZhenYi
09645d8641 fix: resolve multiple bugs across backend and frontend
Security fixes:
- Remove WS token from plaintext log output (ws_universal.rs)
- Replace weak LCG PRNG with rand::thread_rng() for access key generation
- Add project membership check to issue triage endpoint (prevent unauthorized AI usage)
- Validate deepLinkUrl to prevent javascript: navigation (XSS defense-in-depth)

Data integrity fixes:
- Fix UUID truncation in AI model sync (as_u128() as i64 -> timestamp_millis)
- Wrap PR cascade delete in database transaction
- Add missing cascade deletes for room_message_reaction, room_message_edit_history, room_notifications
- Fix N+1 query for last_commit_times (single grouped query instead of per-repo)

Panic prevention:
- Replace unwrap() with safe fallbacks in health/metrics endpoints (email, git-hook apps)
- Replace unwrap() in access key scopes serialization
- Replace expect() in tool executor result map with synthetic error
- Replace expect() in log level parsing with default fallback

Logic bugs:
- Fix users_online metric double-decrement (decrement only when count reaches 0)
- Fix Map iteration + deletion bug in universal-ws.ts onclose handler
- Fix stale audioStream reference in catch block (use local stream variable)
- Add missing reInit event cleanup in carousel.tsx
- Fix email retry backoff integer overflow ((1 << i) as u64 -> 1u64 << i)

React fixes:
- Use message.id instead of index as key in message-list
- Add audio stream cleanup on unmount in use-audio-recording
2026-04-27 13:54:21 +08:00
ZhenYi
1e975c0837 fix: regex injection in message search + semaphore expect panic
- Escape regex special chars in highlightText to prevent ReDoS
- Replace semaphore.acquire().expect() with graceful skip
- Add toast error feedback for search failures
- Remove unsafe (resp.data as any) bypass
2026-04-27 11:12:26 +08:00
ZhenYi
bdb5393835 fix: resolve 30+ bugs from security audit
Critical:
- CORS: replace allow_any_origin + credentials with env-configured origins
- XSS: escape HTML before dangerouslySetInnerHTML in search results
- Path traversal: sanitize storage keys to reject ".." components
- Auth missing: add Session requirement to git init/open/is-repo endpoints
- Transaction: wrap issue cascade delete in DB transaction

High:
- Mutex poisoning: replace unwrap() with poison-recovering guards
- Drop tokio::spawn: use runtime handle or fallback thread for lock release
- Redis KEYS: replace with non-blocking SCAN for typing events
- SSH panic: handle missing stdin/stdout/stderr gracefully
- LFS auth: remove x-user-uid header injection vector, generate per-request tokens

Medium:
- Memory leak: remove Box::leak in provider normalization
- Race conditions: query closed count directly instead of subtraction
- Silent failures: add tracing::warn for AI tasks, room events, activity logs
- Frontend nav: sync activeRoomId when initialRoomId prop changes
- Duplicate nav: remove redundant setActiveRoom in delete handler
- Callback conflict: skip undefined values in updateCallbacks merge
- Stale closure: use wsClient state instead of wsClientRef.current in useMemo

Low:
- Captcha: validate captcha not empty before login submission
- Broadcast capacity: reduce from 100K to 1000
- Error handling: add try/catch for removeMember and updateMemberRole
- Loading state: show placeholder instead of null in RepositoryContextProvider
- WebSocket: add heartbeat ping and jitter to reconnect backoff
2026-04-27 10:57:23 +08:00
ZhenYi
a26551343c fix(frontend): refresh WS token after connection failures and handle AI/repo events
Clear wsToken on auth-related close codes (3000-4999), connection
timeout, and after 3 consecutive reconnect failures so the next connect
attempt fetches a fresh token. Add onRoomAiUpdated and onRepoChanged
callbacks that re-fetch AI configs and repo list when pushed via WS.
Fix AI member list to never display raw UUID.
2026-04-26 23:59:07 +08:00
ZhenYi
c8eba28e7a feat(frontend): add repo type to mention autocomplete system
Add 'repo' to MentionType across all editor types, include repos in the
@ trigger pool, add repo badge (green chip), Repos section in the
mention dropdown, and MentionBadge styles. Wire projectRepos from
room context into IMEditor mentionItems.
2026-04-26 23:58:59 +08:00
ZhenYi
99ebfc14a7 fix(frontend): scrollToIndex smooth option uses behavior property
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
TanStack Virtual uses 'behavior' for scroll animation, not 'smooth'.
2026-04-26 13:31:11 +08:00
ZhenYi
0939aa240b fix(frontend): ordered chunk rendering + initial scroll-to-bottom
- OrderedStreamChunks renders think/answer interleaved per arrival order
- parseSavedChunks parses stored __chunks__ JSON on page refresh
- Tool call chunks hidden from frontend display
- Fix streaming join('') instead of join('\n') to avoid per-token newlines
- Fix MessageList scroll-to-bottom using virtualizer.scrollToIndex
- Remove unused streamingContent/streamingThinkingContent state
- Add retryable error patterns for HTTP connection issues
2026-04-26 13:10:51 +08:00
ZhenYi
61210da7a1 feat(frontend): typing indicator with AI/human split, page visibility reconnect
- TypingUsers state split by sender_type: AI vs human typing
- AI typing shows "{Name} is thinking..." with accent color
- Human typing shows "{Name} is typing..." with muted style
- AI typing relies on backend 60s TTL stop (no client-side 4s fallback)
- Add Page Visibility API to reconnect WS on tab become visible
- Add debug logs for typing flow tracing
- Pass sender_type through WS room.typing event routing
2026-04-25 22:45:11 +08:00
ZhenYi
963e3ee299 chore: update vite.config.ts and IMEditor dependencies 2026-04-25 20:09:50 +08:00
ZhenYi
73ba6329ea fix(frontend): prevent typing.stop on editor init, add typing display
- MessageInput: ignore empty text in handleEditorUpdate to avoid
  TipTap's onUpdate("") on init clearing the typing state
- DiscordChatPanel: show typing indicator when other users are typing
- room-context: wire onTypingStart/Stop into ws callbacks
2026-04-25 20:09:03 +08:00
ZhenYi
99bc4eeb80 chore: API and frontend UI adjustments
- API: issue label bulk add, search messages, room WS push, openapi
- Frontend: notify page, issue detail AI triage banner, search page,
  repository settings, preferences, PR components, file browser
- Room: DiscordChannelSidebar, RoomPinPanel, RoomMessageActions,
  RoomThreadPanel, MessageContent, repository-context
- Frontend SDK regenerated from openapi.json
2026-04-25 09:54:05 +08:00
ZhenYi
dfa5f7664a feat: add notification drawer, command registry, keyboard shortcuts, hooks
New components:
- NotificationDrawer: global bell button with unread badge + Sheet drawer
- CommandPalette: Cmd+K / Ctrl+Alt+F command palette with real API data
- KeyboardShortcutsSheet: ? shortcut reference sheet
- GlobalNavigationShortcuts: g+n/i/r/m two-key navigation
- useNotification: real-time notification management hook
- useCommandRegistry: global command registration hook
- useKeyboardShortcut: keyboard shortcut formatting hook
- useTypingIndicator: unified typing indicator hook
- LinkPreview / CodeBlock / CodeReference: code-aware chat rendering
- ContentRenderer: unified content rendering
- MiniChat: compact inline chat component
- MentionBadge: @mention badge renderer

New libs:
- libs/api/agent/issue_triage.rs: AI issue triage API endpoint
- libs/service/agent/issue_triage.rs: AI triage service
- src/lib/mention.ts: mention parsing and rendering
- src/lib/link-unfurl.ts: URL pattern detection
- src/lib/code-lang-detect.ts: code language detection
- src/lib/code-ref-parser.ts: line-level code reference parsing
2026-04-25 09:53:49 +08:00
ZhenYi
7620f2f281 feat(command): use real API data for navigation, fix notification button
CommandPalette: replace workspaceProjects with getCurrentUserProjects
(no workspace dependency so it works outside WorkspaceProvider).
Repos fetched per-project to preserve correct /repository/ns/repo
routes. Keyboard shortcut correctly matches Ctrl+Alt+F / Cmd+Ctrl+F.

sidebar-user: fix notification button layout — bell icon and label
now on the same row instead of separate stacked elements.
2026-04-25 09:53:12 +08:00
ZhenYi
616c0c0e88 fix(room): scroll-to-bottom logic and AI sender display name
- Remove duplicate smooth scroll effect from DiscordChatPanel; handle
  all scroll logic in MessageList instead
- MessageList: track isInitialLoadRef to instant-jump to bottom on
  first load (no animation), and only auto-scroll for new messages
  when user is already near the bottom
- sender.ts: getSenderDisplayName rejects UUID values and falls back
  to 'AI' for AI messages; getSenderModelId uses display_name
2026-04-25 09:52:58 +08:00
ZhenYi
261989fca3 feat(frontend): TipTap mention nodes with keyboard nav and sectioned dropdown
- MentionNode.tsx: custom TipTap atom node for @/#//mentions
- MentionView.tsx: colored inline labels by type (user=blue, ai=indigo, special=orange)
- IMEditor.tsx: register MentionNode, ↑↓/Enter/Tab/Esc keyboard nav,
  sectioned dropdown (@ groups Notify/AI/Members, # channels, / commands),
  serialize AST to @[type🆔label] on send
- MessageInput.tsx: wire roomAiConfigs into mentionItems, AST serialization
- MessageBubble.tsx: default expanded text (showFullText=true), AI messages never collapsed
2026-04-24 13:16:59 +08:00
ZhenYi
6aca08b8ab feat(room-ui): typing indicator, quick reactions, message grouping, @here/@channel, drag-drop categories, REST category loading
- DiscordChatPanel: typing indicator with animated dots and user names
- MessageActions: quick emoji bar (👍❤️😂🎉😮) on hover
- MessageList: group consecutive messages from same sender within 5min
- MessageInput/IMEditor: @here/@channel special mention suggestions
- DiscordChannelSidebar: useDroppable on category headers for drag-drop,
  empty categories now render, rooms/categories loaded via REST API
- room-context: typingUsers state, REST roomList/categoryList, category
  merge into rooms
2026-04-24 00:04:46 +08:00
ZhenYi
59640c6f44 feat(ws-client): add TypingStart/TypingStop protocol types and client handlers
ws-protocol.ts: TypingStartPayload/TypingStopPayload interfaces,
WsEventPayload union types.

room-ws-client.ts: onTypingStart/onTypingStop callbacks, sendTyping()
method, event dispatch for typing.start/typing_start.

editor/types.ts: special_here/special_channel MentionType + description
field on MentionItem.
2026-04-24 00:04:36 +08:00
ZhenYi
a705bdc938 fix(frontend): various UI display and type corrections
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- workspaces/[id]: Member type fix
- projects/[id]: display adjustments
- platform/sessions: session display improvements
- env.ts: env type corrections
- src/: frontend page and types updates
2026-04-22 10:31:33 +08:00
ZhenYi
4d3afc5e71 fix(frontend): Discord UI polish, room streaming and kanban improvements
- DiscordChatPanel: update threading layout, message list padding
- DiscordMemberList: role colors, online status indicators
- RoomThreadPanel, MessageBubble, MessageInput: UI refinements
- IMEditor: editor state improvements
- KanbanCard, KanbanColumn: card layout, column styling
- room-context.tsx, room-ws-client.ts, ws-protocol.ts: streaming
- pull-request-detail.tsx: PR review improvements
- Add RoomPinPanel component
2026-04-21 22:31:48 +08:00
ZhenYi
a527428b2d fix(frontend): room streaming, dedup, reactions, uploads, and render perf
- room-context: dedup by id not seq (streaming seq=0); single atomic
  setStreamingContent with delta detection; preserve reactions from WS
- MessageBubble: fix avatar lookup (members before IIFE); handleReaction
  deps (no message.reactions); add reactions to wsMessageToUiMessage
- MessageInput: memoize mentionItems; fix upload path with VITE_API_BASE_URL
- IMEditor: warn on upload failure instead of silent swallow
- RoomSettingsPanel: sync form on room switch; loadModels before useEffect
- DiscordChatPanel: extract inline callbacks to useCallback stable refs
2026-04-21 13:43:38 +08:00
ZhenYi
43e2d26ea2 feat(frontend): channel sidebar toggle, member list default closed, fix accent-fg colors
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 19:33:14 +08:00
ZhenYi
e43d9fc8bf feat(frontend): add attachment_ids to message creation flow and types 2026-04-20 19:33:09 +08:00
ZhenYi
7736869fc4 feat(frontend): integrate ThemeSwitcher, restore custom palette on page load 2026-04-20 19:33:04 +08:00
ZhenYi
ce29eb3062 feat(frontend): Discord design system tokens and palette variables 2026-04-20 19:32:59 +08:00
ZhenYi
4d5c62e46a feat: add project tools (repos, issues, boards, arxiv, curl, members) and ThemeSwitcher component 2026-04-20 19:31:44 +08:00
ZhenYi
6f6f57f062 feat(frontend): add push notification hooks, image compression, and update room/chat components 2026-04-20 15:45:47 +08:00
ZhenYi
c4d4b2ecf5 fix(room): fix channel sidebar clickability and polish UI
- Fix DraggableRow: remove opacity-0 wrapper that was hiding
  RoomButton; drag handles now work without blocking clicks
- Move "+ Add Category" to bottom of channel list
- Reduce channel item padding (6px → 4px) for compact look
- Shrink # hash icon to 12px
- Add explicit text-align: left to channel names
- Reduce Add Category button/input to 10px font
2026-04-19 20:47:07 +08:00
ZhenYi
b73cc8d421 refactor(room): Discord-style UI redesign for channel sidebar and member list
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 01:12:38 +08:00
ZhenYi
76ca5fb1dd fix(frontend): wire up message search button in DiscordChatPanel
- Add showSearch state and RoomMessageSearch panel (420px slide-in)
- Search button now toggles panel and highlights when active
- Clicking a search result scrolls to the message and closes panel
- Add msg-{id} anchors on message containers for scroll-into-view
2026-04-18 21:13:03 +08:00
ZhenYi
a09f66b779 refactor(room): WebSocket queue and message editor improvements
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- Enhance ws_universal.rs with queue message support
- Add queue types and producer improvements
- Simplify MessageBubble.tsx rendering logic
- Refactor IMEditor.tsx with improved message handling
- Update DiscordChatPanel.tsx with message enhancements
2026-04-18 19:29:36 +08:00
ZhenYi
821b0e998d refactor(room): Discord layout and room WebSocket client refactor
- Refactor room-context.tsx with improved WebSocket state management
- Enhance room-ws-client.ts with reconnect logic and message handling
- Update Discord layout components with message editor improvements
- Add WebSocket universal endpoint support in ws_universal.rs
2026-04-18 19:05:21 +08:00
ZhenYi
0cccec33b2 feat(frontend): invitations page with project and workspace support
- Add /invitations route with dedicated page and sidebar button
- Display both project invitations (accept/decline) and workspace invitations (accept only)
- Merge and sort both invitation types by most recent first
- Export new SDK functions: workspaceMyInvitations, workspaceAcceptInvitationBySlug
2026-04-18 19:05:14 +08:00
ZhenYi
00a5369fe1 feat(frontend): Discord layout + AI Studio theme + Room Settings
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Frontend:
- Add Discord-style 3-column layout (server icons / channel sidebar / chat)
- AI Studio design system: new CSS token palette (--room-* vars)
- Replace all hardcoded Discord colors with CSS variable tokens
- Add RoomSettingsPanel (name, visibility, AI model management)
- Settings + Member list panels mutually exclusive (don't overlap)
- AI models shown at top of member list with green accent
- Fix TS errors: TipTap SuggestionOptions, unused imports, StarterKit options
- Remove MentionInput, MentionPopover, old room components (废弃代码清理)

Backend:
- RoomAiResponse returns model_name from agents.model JOIN
- room_ai_list and room_ai_upsert fetch model name for each config
- AiConfigData ws-protocol interface updated with model_name

Note: RoomSettingsPanel UI still uses shadcn defaults (未完全迁移到AI Studio)
2026-04-18 16:59:36 +08:00
ZhenYi
aac32b1b92 fix(frontend): block selectionchange during MentionInput DOM updates
Root cause: when MentionInput updates innerHTML to reflect value changes,
the browser resets the selection to position 0. The selectionchange event
handler reads this wrong cursor position and sets ms.cursorOffset=0,
breaking mentionState calculation for the popover.

Fix:
- MentionInput sets window.__mentionBlockSelection=true before innerHTML
- Clears it via requestAnimationFrame after caret is restored
- selectionchange handler skips cursor reading when flag is set
2026-04-18 11:49:03 +08:00
ZhenYi
53b0b03716 fix(frontend): use selectionchange event for cursor tracking instead of per-render
The per-render tracking effect was reading DOM cursor position before
the browser had finished positioning the caret after innerHTML updates,
causing ms.cursorOffset to be set to the old position and overwriting
the deferred correct value.

Switch to document.selectionchange event which:
- Fires only when the user actually moves the cursor (arrow keys, mouse clicks)
- Does NOT fire during programmatic DOM updates
- Uses focusNode/focusOffset directly from the selection API

This completely eliminates the timing race between render effects and
programmatic cursor updates.
2026-04-18 11:42:43 +08:00
ZhenYi
4330325bfc fix(frontend): skip tracking effect update when caret is at end of text
Root cause: after onCategoryEnter sets value="@ai:", the MentionInput sync
effect sets innerHTML with the new content. The browser caret may be at
position 2 (not moved from the user's perspective), but prevCursorRef was
4. The tracking effect read DOM caret=2 and overwrote ms.setCursorOffset(4)
→ cursor jumped to position 2.

Fix: skip tracking effect update when:
- count (DOM caret) is at end of text (ms.value.length), AND
- prevCursorRef was also at end of text
This means the caret hasn't actually moved from the user's POV (just
positioned by the browser after innerHTML), so don't update state.
2026-04-18 11:39:16 +08:00
ZhenYi
126ffda4fe fix(frontend): skip cursor tracking effect during deferred cursor updates
Root cause: when onCategoryEnter scheduled a deferred setCursorOffset,
the tracking effect ran BEFORE setTimeout and read the OLD DOM cursor
position (still "@a" → position 2), overwriting the new cursor position
of 4 in a subsequent render.

Fix: add skipCursorTrackingRef flag. Set it before setTimeout fires,
clear it when setTimeout executes. The tracking effect checks the flag
and skips its update during the flush window.

Same fix applied to insertCategory imperative handle.
2026-04-18 11:27:37 +08:00
ZhenYi
fb09553b79 fix(frontend): defer cursor offset update in onCategoryEnter
When @category is selected, ms.setCursorOffset and ms.setValue were called
in the same event loop tick — the cursor sync effect later read the DOM
before the new mention value flushed, restoring the old caret position.

Defer ms.setCursorOffset via setTimeout so it fires after the DOM
reconciliation. Same fix applied to insertCategory imperative handle.
2026-04-18 11:24:01 +08:00
ZhenYi
5103d99a00 fix(frontend): rewrite MentionInput sync to prevent onChange overwriting mention draft
The root cause: handleMentionSelect set draft to mention HTML, but the
subsequent MentionInput.onInput event fired with plain text (after the
programmatic DOM insert) and overwrote the draft.

Solution: replace pendingSyncRef trick with a clean isUserInputRef flag.
- useEffect: if getPlainText(el) === value, DOM already correct (skip).
  Mark isUserInputRef = false so next useEffect skips caret restore.
- handleInput: always set isUserInputRef = true before calling onChange.

This eliminates the pendingSyncRef/__mentionSkipSync global flag mess
entirely.
2026-04-18 11:20:48 +08:00
ZhenYi
4ace651c6f fix(frontend): pass selected item to doInsert on Enter key and fix list keys
- handleSelectRef.current() was called without argument → suggestion was
  undefined → suggestion.type threw. Now passes the selected item.
- key prop moved to outer map wrapper div so React can diff the list
  correctly. Inner SuggestionItem/CategoryHeader no longer need keys.
2026-04-18 11:16:04 +08:00
ZhenYi
989a4117db fix(frontend): fix useMemo deps syntax and replace stale ref reads in render body
useMemo received deps as trailing comma-separated args instead of array.
Replace all render-body reads of mentionStateRef.current with reactive
mentionState from useMemo. Keep ref for event listener closures only.
2026-04-18 11:14:10 +08:00
ZhenYi
434a3595eb fix(frontend): mention popover respects shouldBelow for above/below placement
ShouldBelow was computed but ignored — popover always rendered below the
cursor. Now uses shouldBelow correctly to render above when insufficient
space below. Also removes unused cRect clone measurement.
2026-04-18 11:11:39 +08:00
ZhenYi
3a164f6dcc fix(frontend): restore missing useMemo import in MentionPopover 2026-04-18 11:09:53 +08:00
ZhenYi
a834564c0f fix(frontend): show mention popover when @ is typed
Effect watches mentionState and toggles showMentionPopover accordingly.
Without this, ms.setShowMentionPopover was never called in onChange,
so the popover never appeared.
2026-04-18 11:09:17 +08:00
ZhenYi
8d3ecca0bc fix(frontend): restore missing cn import in RoomChatPanel 2026-04-18 11:07:15 +08:00
ZhenYi
f152aaeed9 fix(frontend): 4 mention chain bugs — cursor tracking, caret placement, undefined refs
- Fix undefined setDraftAndNotify (replaced with onDraftChangeRef + ms.setValue)
- Add DOM→ms.cursorOffset tracking on every render via TreeWalker
- Fix mention insertion caret placement: skip MentionInput sync-effect caret
  restoration when parent sets value (via __mentionSkipSync window flag)
- Remove unused _draftTick state

Bug #1: setDraftAndNotify referenced but never defined → runtime crash
Bug #2: ms.cursorOffset never updated from DOM → popover always at wrong position
Bug #3: mention insertion saved pre-insertion caret, restored on longer HTML → cursor inside mention tag
Bug #4: _draftTick declared but state value never read → dead code
2026-04-18 01:34:22 +08:00
ZhenYi
168fdc4da8 refactor(frontend): rewrite mention system with clean state architecture
Replace module-level refs and circular dependencies with a centralized
mention state hook (useMentionState) and shared types (mention-types).

- Introduce mention-types.ts for shared types (avoid circular deps)
- Introduce mention-state.ts with useMentionState hook (replace global refs)
- Rewrite MentionInput as contenteditable with AST-based mention rendering
- Rewrite MentionPopover to use props-only communication (no module refs)
- Fix MessageMentions import cycle (mention-types instead of MentionPopover)
- Wire ChatInputArea to useMentionState with proper cursor handling
2026-04-18 01:26:35 +08:00
ZhenYi
d2935f3ddc fix(frontend): repair MentionInput contenteditable implementation
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- MentionInput: use forwarded ref, internal state ref, pendingSyncRef
  flag to prevent value↔DOM sync cycles; getContentText walks both
  text nodes and non-editable mention spans to preserve mention length
- RoomChatPanel: replace cursorRef with getCaretOffset()/setCaretOffset()
  helpers, remove stale cursorRef.current references throughout
- MentionPopover: update textareaRef type to HTMLDivElement,
  handleSelect uses TreeWalker to read from contenteditable div,
  positioning effect always uses TreeWalker for text measurement
2026-04-18 01:17:04 +08:00
ZhenYi
b7328e22f3 feat(frontend): render mentions as styled buttons in input and messages
Some checks are pending
CI / Frontend Build (push) Blocked by required conditions
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
- MentionInput: contenteditable div that renders all mention types as
  emoji+label pill spans (🤖 AI, 👤 User, 📦 Repo, 🔔 Notify)
- Single-backspace deletes entire mention at cursor (detects caret
  at mention start boundary)
- Ctrl+Enter sends, plain Enter swallowed, Shift+Enter inserts newline
- Placeholder CSS via data-placeholder attribute
- MessageMentions: emoji button rendering extended to all mention types
  (user, repository, notify) with click-to-insert support
- Rich input synced via cursorRef (no stale-state re-renders)
2026-04-18 01:06:39 +08:00