Commit Graph

21 Commits

Author SHA1 Message Date
ZhenYi
9b966789fd fix(room): resolve mention IDs to display names when rendering messages
- Pass members/repos/aiConfigs lists to MessageContentWithMentions
- Add resolveName() that looks up ID → display name per mention type
- RoomMessageBubble now resolves user/repository/AI mention UIDs to real names
2026-04-18 00:10:12 +08:00
ZhenYi
a9fc6f9937 feat(room): redesign MentionPopover with modern UI/UX
Visual improvements:
- Glassmorphism backdrop blur and refined shadows
- Color-coded categories: user(sky), repository(violet), AI(emerald)
- Gradient backgrounds and smooth transitions
- Custom avatar icons for each mention type

Interaction enhancements:
- Search text highlighting with yellow background
- Auto-scroll selected item into view
- Selection indicator dot and left border accent
- Keyboard navigation (↑↓) with visual feedback

Components:
- CategoryHeader: icon + label with color theme
- SuggestionItem: avatar + highlighted text + category badge
- LoadingSkeleton: Shimmer loading state
- EmptyState: Illustrated empty/loading states

Uses ScrollArea, Avatar, Skeleton from design system
2026-04-18 00:02:09 +08:00
ZhenYi
aacd9572d1 fix(room): replace useMemo+categories with plain const to fix SWC parser error 2026-04-17 23:53:31 +08:00
ZhenYi
9246a9e6ab fix(room): move eslint-disable comment inside array to fix SWC syntax error 2026-04-17 23:52:27 +08:00
ZhenYi
f9a3b51406 perf(room): optimize MentionPopover with caching, stable refs, and loading states
- Position caching: skip recalculation when text+cursor unchanged
- TempDiv reuse: cached DOM element on textarea, created once
- Stable refs pattern: avoid stale closures in keyboard handler
- Auto-selection: reset to first item on category/list change
- Loading states: reposLoading + aiConfigsLoading wired from context
2026-04-17 23:48:26 +08:00
ZhenYi
26682973e7 feat(room): redesign mention system with AST-based format
Backend:
- Add MENTION_TAG_RE matching new `<mention type="..." id="...">label</mention>` format
- Extend extract_mentions() and resolve_mentions() to parse new format (legacy backward-compatible)

Frontend:
- New src/lib/mention-ast.ts: AST types (TextNode, MentionNode, AiActionNode),
  parse() and serialize() functions for AST↔HTML conversion
- MentionPopover: load @repository: from project repos, @ai: from room_ai configs
  (not room members); output new HTML format with ID instead of label
- MessageMentions: use AST parse() for rendering (falls back to legacy parser)
- ChatInputArea: insertMention now produces `<mention type="user" id="...">label</mention>`
- RoomParticipantsPanel: onMention passes member UUID to insertMention
- RoomContext: add projectRepos and roomAiConfigs for mention data sources
2026-04-17 23:43:26 +08:00
ZhenYi
6431709669 fix(room): show model name instead of UID in settings panel
- Load model list on settings panel mount so names are always available.
- SelectValue now displays the selected model's name by looking up
  availableModels, falling back to UID if name not found.
- Existing AI configs list also shows model name instead of raw UID.
2026-04-17 23:17:56 +08:00
ZhenYi
5ff45770ec fix(room): fix model/ai list response parsing in RoomSettingsPanel
The SDK wraps API responses as { data: { code, message, data: [...] } }.
Code was incorrectly accessing resp.data['200'] which doesn't exist.
Fix to use resp.data.data to reach the actual array.
2026-04-17 23:15:14 +08:00
ZhenYi
7152346be8 fix(room): make reaction Popover controlled so it closes after select 2026-04-17 22:16:40 +08:00
ZhenYi
a1ddb5d5bc fix(room): add HTTP batch reactions endpoint and clean up dead code
Backend:
- Add reaction_batch handler: GET /api/rooms/{room_id}/messages/reactions/batch?message_ids=...
- Register route in libs/api/room/mod.rs
- Backend already had message_reactions_batch service method, just needed HTTP exposure

Frontend:
- Add ReactionListData import to room-context.tsx
- Fix thisLoadReactions client type (was using broken NonNullable<ReturnType<>>)
- Remove unused oldRoomId variable
- Delete unused useRoomWs.ts hook (RoomWsClient has no on/off methods)
- Remove unused EmojiPicker function and old manual overlay picker from RoomMessageBubble
- Remove unused savedToken variable in room-ws-client
2026-04-17 22:12:10 +08:00
ZhenYi
2f1ed69b31 fix(room): restore useState import removed in refactor 2026-04-17 22:02:55 +08:00
ZhenYi
ef1adb663d fix(room): replace manual emoji picker positioning with Popover
Manual getBoundingClientRect positioning caused the picker to appear at
the far right of the room and shift content. Replaced with shadcn
Popover which handles anchor positioning, flipping, and portal rendering
automatically.
2026-04-17 21:50:50 +08:00
ZhenYi
bab675cf60 perf(room): increase virtualizer overscan to 30 for smoother scrolling 2026-04-17 21:31:36 +08:00
ZhenYi
5cd4c66445 perf(room): simplify scroll handler and stabilize callback refs
- Remove useTransition/useDeferredValue from RoomMessageList
- Wrap component in memo to prevent unnecessary re-renders
- Use requestAnimationFrame to defer scroll state updates
- Remove isUserScrolling state (no longer needed)
- Simplify auto-scroll effect: sync distance check + RAF deferred scroll
- Add replyMap memo to decouple reply lookup from row computation
- Stabilize handleEditConfirm to depend on editingMessage?.id only
- Remove Performance Stats panel (RoomPerformanceMonitor)
2026-04-17 21:28:58 +08:00
ZhenYi
991d86237b fix: remove stale onRenderedCountChange prop from RoomMessageList usage 2026-04-17 21:23:03 +08:00
ZhenYi
70381006cf chore(room): remove Performance Stats panel
Unused debug overlay that was tracking virtualized row counts.
2026-04-17 21:21:59 +08:00
ZhenYi
cf5c728286 fix(room): fix scrolling lag, N+1 queries, and multiple WS token requests
Frontend:
- P0: Replace constant estimateSize(40px) with content-based estimation
  using line count and reply presence for accurate virtual list scroll
- P1: Replace Shadow DOM custom elements with styled spans for @mentions,
  eliminating expensive attachShadow calls per mention instance
- P1: Remove per-message ResizeObserver (one per bubble), replace with
  static inline toolbar layout to avoid observer overhead
- P2: Fix WS token re-fetch on every room switch by preserving token
  across navigation and not clearing activeRoomIdRef on cleanup

Backend:
- P1: Fix reaction check+insert race condition by moving into transaction
  instead of separate query + on-conflict insert
- P2: Fix N+1 queries in get_mention_notifications with batch fetch
  for users and rooms using IN clauses
- P2: Update room_last_activity in broadcast_stream_chunk to prevent
  idle room cleanup during active AI streaming
- P3: Use enum comparison instead of to_string() in room_member_leave
2026-04-17 21:08:40 +08:00
ZhenYi
60d8c3a617 fix(room): resolve remaining defects from second review
- reaction.rs: query before insert to detect new vs duplicate reactions,
  only publish Redis event when a reaction was actually added
- room.rs: delete Redis seq key on room deletion to prevent seq
  collision on re-creation
- message.rs: use Redis-atomic next_room_message_seq_internal for
  concurrent safety; look up sender display name once for both
  mention notifications and response body; add warn log when
  should_ai_respond fails instead of silent unwrap_or(false)
- ws_universal.rs: re-check room access permission when re-subscribing
  dead streams after error to prevent revoked permissions being bypassed
- RoomChatPanel.tsx: truncate reply preview content to 80 chars
- RoomMessageList.tsx: remove redundant inline style on message row div
2026-04-17 20:28:45 +08:00
ZhenYi
7416f37cec fix(room): prevent double-send, log resubscribe errors, dim pending messages
- sendMessage: guard with sendingRef to prevent concurrent in-flight
  sends (was missing — rapid clicks could create duplicate messages)
- resubscribeAll: log at warn level instead of silently swallowing,
  so operators can observe auth expiry or persistent failure patterns
- RoomMessageBubble: apply opacity-60 when isPending or isFailed,
  and hide action toolbar for pending messages (can't react/act on
  unconfirmed messages)
2026-04-16 19:29:34 +08:00
ZhenYi
c89f01b718 feat(room): improve robustness — optimistic send, atomic seq, jitter reconnect
Backend:
- Atomic seq assignment via Redis Lua script: INCR + GET run atomically
  inside a Lua script, preventing duplicate seqs under concurrent requests.
  DB reconciliation only triggers on cross-server handoff (rare path).
- Broadcast channel capacity: 10,000 → 100,000 to prevent message drops
  under high-throughput rooms.

Frontend:
- Optimistic sendMessage: adds message to UI immediately (marked
  isOptimistic=true) so user sees it instantly. Replaces with
  server-confirmed message on success, marks as isOptimisticError on
  failure. Fire-and-forget to IndexedDB for persistence.
- Seq-based dedup in onRoomMessage: replaces optimistic message by
  matching seq, preventing duplicates when WS arrives before REST confirm.
- Reconnect jitter: replaced deterministic backoff with full jitter
  (random within backoff window), preventing thundering herd on server
  restart.
- Visual WS status dot in room header: green=connected, amber
  (pulsing)=connecting, red=error/disconnected.
- isPending check extended to cover both old 'temp-' prefix and new
  isOptimistic flag, showing 'Sending...' / 'Failed' badges.
2026-04-16 19:23:06 +08:00
ZhenYi
93cfff9738 init 2026-04-15 09:08:09 +08:00