fix(web-react): restore TopBar, panel system, full-screen settings, correct theme/settings placement - #123
Conversation
Two-package monorepo for the reusable AI chat UI: - jcode-ui-core: framework-agnostic types (Message/ToolCall/Approval/ThreadItem), ChatRuntime abstraction + ExternalStoreRuntime (wraps any Redux-shaped store), MockRuntime (for demos/tests), ToolRendererRegistry (plugin seam), and headless React primitives (Thread with virtualization + auto-follow, MessageView, Composer, ToolCallView, ApprovalBlock, AskUserBlock). - jcode-ui: styled components wrapping the primitives with token-driven Tailwind 4 styling, the marked+highlight.js+DOMPurify markdown pipeline, and 9 default tool renderers (terminal/file-viewer/diff/search/todo/skill/team/browser-shot/generic). Both packages typecheck and build clean. Core dist + CSS bundle verified. Root pnpm-workspace.yaml added; .gitignore updated for node_modules/ and dist/.
- ChatDemo: scripted mock-runtime playground component (the 'website footprint') that streams a full conversation through message/tool/approval item kinds. - /chat-ui page: hero, live demo, feature grid, quick-start code sample. - site/docs/chat-ui/: runtime, primitives, tool-renderers, theming pages. - SiteNav + routing wired. Site typechecks and builds clean (ChatUIPage bundles at 350KB gzip — highlight.js + marked dominate, expected for a live demo). - jcode-ui core dep switched to file: so the isolated site workspace resolves it.
…ct shell Replaces the Vue app's runtime layer + shell with a React equivalent that consumes the jcode-ui component library: - lib/ : framework-agnostic ports (api.ts 384-line client, apiBase.ts dual-host contract, authToken.ts, useDesktop.ts Tauri bridge, ws.ts singleton client, types.ts full backend contract). Nearly verbatim from web/src/composables. - app/store.ts : RTK store split across 4 slices (chat/session/model/ui) with async thunks (sendMessage/stopAgent/resolveApproval/submitAskUser/editMessage). - app/runtime.ts : createExternalStoreRuntime adapter — the single seam between RTK and jcode-ui's RuntimeState. - app/wsBridge.ts : WS events → Redux dispatches (replaces Vue App.vue coupling). - components/ : product shell (Sidebar, ChatView, ProjectHeader, GoalBanner, AutomationsView, ChannelsView, CommandPalette, AuthGate, SetupView). typechecks + builds clean (626 modules, 421KB gzip bundle — code-splitting is a follow-up). Splits the 1.2k-line Vue chat store into focused slices per the migration assessment. The dual-host (browser/Tauri) contract is preserved.
- Makefile: add build-web-react (builds core → jcode-ui → CSS → web-react →
dist-react), FRONTEND var to select web/web-react, lint-react target.
Tolerates pnpm ERR_PNPM_IGNORED_BUILDS (esbuild/@parcel/watcher) so the build
chain is non-fragile.
- pnpm-workspace.yaml: onlyBuiltDependencies for esbuild + @parcel/watcher.
- .npmrc: auto-install-peers for the monorepo.
- AGENTS.md: document the Vue→React migration, web-react/, packages/, and the
build-web-react target; mark web/ as production-during-migration.
- packages/jcode-ui{,-core}/: README.md, LICENSE, .npmignore, publishConfig
(access public), files array — npm pack dry-run verified (styles.css + dist
included, src excluded).
Verified: make build-web-react end-to-end green; all 4 TS projects typecheck
(jcode-ui-core, jcode-ui, web-react, site); Go backend builds (embed intact);
Tauri frontendDist still points at the Vue dist (React is parallel).
…replay + separated chat-ui docs Runtime fixes (found via headless-browser testing against the live Go backend): - externalStore.ts: cache the normalized RuntimeState keyed on the host state reference so getState() returns a stable identity between dispatches. Without this, useSyncExternalStore infinite-looped (Maximum update depth) and crashed every page that rendered <Thread>. This was the root cause of the blank app. - context.tsx: trust the runtime's snapshot stability (remove the redundant and buggy double-cache); useRuntimeState/useRuntimeSelector now pass runtime.getState directly. - Thread.tsx VirtualizedThread: the scroll container resolved to height 0 inside flex parents, so the virtualizer rendered 0 rows. Restructured to flex:1 + min-height:0 so the height resolves through the chain. Verified the demo now streams its scripted conversation. web-react (product app): - loadSession thunk: replay a session's JSONL history into the timeline (was a TODO — the app booted to an empty chat). Walks entries, rebuilds messages + tool calls, matches tool_call_id, falls back to most-recent session on 404. - App.tsx boot: load current session, fall back to most-recent if empty. - toolInfo.ts: ported extractToolDisplayInfo (mirrors backend, for replay). - Sidebar openSession now loads the session via the thunk. - vite.config.ts: pin port 5173 (matches Tauri devUrl). site (component library docs + showcase): - Separated chat-ui docs from jcode product docs. New /chat-ui/docs/* route with its own pipeline (chatUiDocs.ts), nav tree, ChatUiDocsLayout, index, and DocPage. The sidebar now lists ONLY jcode-ui docs — no mixing with the jcode product docs (Agent/Plan Mode/Browser). Back-link to the chat-ui landing. - components.md: new component reference page with an assistant-ui→jcode-ui mapping table + props tables for every component (closes the assistant-ui feature-parity gap). - ChatDemo: rewrote the layout to flex/flex-col + min-h-0 so the virtualized Thread gets a concrete height (was rendering empty). Verified end-to-end with headless Chrome: - web-react: boots, loads session timeline (real history), streams a live prompt (model replied), tool cards render (✓ shell/read/edit +N/-M), Stop button swaps correctly, theme tokens applied, no JS errors. - site /chat-ui: ChatDemo streams the full scripted conversation (message→tool →approval) with virtualization; docs index + sub-pages render standalone. Build artifacts (jcode-new binary, *.tsbuildinfo) gitignored.
…ui parity); wire ⌘K
Closes the assistant-ui component-catalog gaps found in the parity audit. Every
assistant-ui component now has a jcode-ui equivalent, documented in components.md
with a full mapping table (✅ library / 🟡 product-level / field-driven).
New components (jcode-ui):
- Reasoning: collapsible model thinking block ('Thought for Ns'), markdown,
driven by message.reasoning. Mirrors assistant-ui Reasoning.
- Sources: citation chip list with snippet popovers, driven by
message.sources (MessageSource[]). Mirrors assistant-ui Sources.
- Attachment + AttachmentList: standalone image-attachment thumbnails (also
embedded in ChatInput). Mirrors assistant-ui Attachment.
Message now renders Reasoning (before body) + Sources (after body) automatically
when those fields are present. Added reasoning/sources/MessageSource to the core
Message type.
components.md: rewrote the assistant-ui→jcode-ui mapping to cover ALL 16 catalog
entries (Thread, ThreadList, Composer, Attachment, Markdown, DiffViewer, Image,
Context Display, Message Timing, Reasoning, Sources, Tool Fallback, Tool Group,
Assistant Modal/Sidebar, Model Selector, makeAssistantToolUI) with status +
notes. Added reference sections for Reasoning/Sources/Attachment with props.
web-react:
- App.tsx: wired global keyboard shortcuts (⌘K command palette, ⌘N new chat,
Esc closes overlays) — was missing entirely.
- main.tsx: dev-only window.__jcodeStore exposure for testing (stripped in prod).
- vite-env.d.ts: added (vite/client types for import.meta.env).
Demo (site/playground): the scripted conversation now ends with a message that
has reasoning + sources, so the ChatUIPage live demo showcases those components.
Verified end-to-end (headless Chrome):
- web-react: all 6 views render (ChatView, Automations w/ real data, Channels,
SetupView, AuthGate, CommandPalette via ⌘K + store toggle). No JS errors.
- site: all 8 pages render without regression (Home/Desktop/CLI/Showcase/Docs/
Chat-UI/Chat-UI Docs/Privacy).
- Demo single-play: Reasoning ('Thought process') + Sources (2 chips) render on
the final assistant message; production build bundles them.
…cts it) Tauri 2 strictly validates the config schema and rejects unknown fields. The override config had a $comment field for documentation, which crashed desktop-react-dev on startup: Error: Additional properties are not allowed (`$comment` was unexpected) Removed the $comment (and the redundant $schema). The build block alone is the only override needed; everything else is inherited from tauri.conf.json via deep merge. Verified: make desktop-react-dev now boots the Tauri window + Go sidecar + Vite dev server end-to-end.
…le + Automations/Channels parity Closes the major feature gaps vs the Vue app. Each ported file was read in full from the Vue source and typechecks individually. ChatInput.tsx (product composer, ~1.2k lines): - Full port of the Vue 2.2k-line composer: autosizing textarea, send/queue/stop (IME-safe), slash-command menu, MODE picker (approval/plan/full_access), MODEL picker (current/favorites/recent/all-providers with capability dots + context limit + manage-models dialog), EFFORT picker, '+' menu (attach images, slash insert, Goal arming), image attachments (paste + file picker + thumbnails), type-ahead queue chips, ⌘L focus, click-outside. ChatView now uses this product ChatInput instead of the library's minimal one. SettingsDialog.tsx (~1.5k lines): - Full port of the Vue 2.7k-line settings: 8 tabs (Providers/Models/MCP/Skills/ Appearance/Browser/Remote/Usage). Providers tab fully ported (CRUD + catalog + advanced config + custom models). MCP has OAuth-login polling. Browser has site-permissions editor. Usage has totals + trend chart. Opened via ⌘, and the header gear button. useTheme.ts + ThemeToggle.tsx: - Theme system ported (system/light/dark + 7 named themes, useSyncExternalStore, localStorage persistence, applies data-theme + .dark class). Toggle button in the header (sun/moon flip + swatch dropdown). AutomationsView.tsx: full CRUD (create/edit form with schedule/mode/project, run history with filter, templates picker, enable/disable, run-now, delete). ChannelsView.tsx: WeChat QR-login flow (login → QR → 2s poll → online → logout) + enable/disable + BLE card. ProjectHeader: added settings gear + ThemeToggle. App.tsx: renders SettingsDialog, ⌘, shortcut. Verified via headless Chrome: model+mode pickers render, Settings opens with all 8 tabs + real provider data, theme toggle flips .dark class, Automations shows real automation + templates + create, Channels shows WeChat card. No JS errors. typecheck + production build pass. Also: untracked the accidentally-committed internal/web/dist-react build output and gitignored it.
…+ correct theme/settings placement Fixes the shell-layout regressions vs the Vue app. Each piece was compared against the Vue source before implementing. TopBar.tsx (NEW): the floating top-right panel menu (absolute top:6 right:14, matching Vue exactly). Button = RectangleStackIcon + caret + live status dot (running/connected/disconnected priority). Dropdown: Plan(⇧⌘P)/Files(⇧⌘E)/ Changes(⇧⌘G)/Terminal(⌘`) with inline diff stat on Changes. Was entirely missing. RightPanel.tsx (NEW): the right-side panel with Plan/Files/Changes tabs. Plan = TaskList (todos from store); Files = file tree (api.files); Changes = diff viewer (api.diff). Close button + tab switcher. Was missing. TerminalPanel.tsx (NEW): bottom-docked xterm.js terminal. Creates a PTY, opens the PTY WebSocket (jcode-auth subprotocol), attaches FitAddon + WebLinksAddon, reads theme colors from tokens, handles resize + theme changes. Was missing. App.tsx (rewritten Shell): panel system (rightPanelOpen/rightPanelTab/ bottomPanel/bottomPanelHeight state + togglePanel logic + resize handle). Renders TopBar (chat view only, like Vue), Sidebar, main (chat + bottom terminal panel), RightPanel. Panel keyboard shortcuts wired (⇧⌘P/E/G, ⌘`). Removed the incorrect ProjectHeader — Vue has no header bar (TopBar carries the chrome). ChatView.tsx: removed ProjectHeader (the chat canvas has no header in Vue). SettingsDialog.tsx: rewritten chrome from small centered modal → FULL-SCREEN overlay (fixed inset-0, opaque bg, left nav rail + right content panel — matches Vue's settings shell). All 8 tab implementations preserved. Sidebar.tsx: moved settings gear + theme toggle to the FOOTER (Vue's placement), not the header. Added compact mode to ThemeToggle. Verified via headless Chrome: - TopBar at top:6/right:14 with 'Panels menu' label + status dot ✓ - Panel menu opens, Files click shows RightPanel ✓ - ⌘` opens xterm terminal (canvas present) ✓ - Settings (⌘,) is full-screen 1280x840 with left rail ✓ - Sidebar footer has settings + theme; header has neither ✓ - Channels view renders ✓ - typecheck + production build pass
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (120)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…orrect theme/settings placement (#123)
Summary
Fixes the shell-layout regressions vs the Vue app that were missed in the initial React migration. Each piece was compared against the Vue source line-by-line before implementing.
Problems fixed (from feedback)
What's new
Verification (headless Chrome)
🤖 Generated with ZCode