Skip to content

Replace admin UI with a React + Vite + tRPC single-page app#452

Open
arabold wants to merge 4 commits into
mainfrom
feat/admin-ui-redesign
Open

Replace admin UI with a React + Vite + tRPC single-page app#452
arabold wants to merge 4 commits into
mainfrom
feat/admin-ui-redesign

Conversation

@arabold

@arabold arabold commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Rebuilds the web admin dashboard from scratch, replacing the old HTMX/Alpine
server-rendered UI with a client-side React + Vite SPA driven entirely by
the existing typed tRPC API. It still ships in the same single binary
(built to public/, served statically with an index.html catch-all for
client-side routes) — no new runtime, no meta-framework.

What changed

New UI (src/web/client/) — a sidebar + topbar app shell with light/dark/auto
theming, built from a shared, reusable component library (no per-page duplication):

  • Overview — KPIs, system-health panel, active jobs
  • Libraries — table with favicons, status, versions, row actions
  • Library Detail — stored scrape config + a chunk explorer (browse the
    version's stored chunks as rendered Markdown, with per-chunk metadata)
  • Jobs & Queue — summary stats, failed-job recovery (retry / edit & retry),
    live updates via the events subscription
  • Search Playground — real search results rendered as Markdown
  • Settings — read-only view of the running configuration

Backend (composed into the merged appRouter):

  • Export an AppRouter type for end-to-end client typing
  • getSystemHealth — honest snapshot of the running config (services, worker
    mode + maxConcurrency, embeddings, MCP endpoints, auth)
  • listVersionChunks / getVersionStats — power the chunk explorer
  • Accept an empty-string version as "unversioned" in scrape/refresh input
  • Enable the tRPC API whenever the web interface is enabled (was off for the
    standalone web command)

Cleanup — removed the entire old HTMX UI and its now-dead dependencies
(alpine, htmx, flowbite, idiomorph, kitajs) plus the unused Tailwind/PostCSS
stack; flipped the default JSX runtime to React; extended Biome to lint .tsx.

Verification

typecheck ✓ · lint (biome, incl. .tsx) ✓ · build ✓ · 1899 tests pass.
Manually QA'd against a real store: every screen renders live data, theme toggle,
Add-library / Add-version drawer, refresh, and Search all exercised end to end.

Follow-ups

Tracked in docs/admin-ui-backlog.md, including issues
#449 (atomic removeLibrary), #450 (per-chunk token counts), and #451
(favicon-at-scrape). Notable deferrals: the Overview activity time-series (no
history recorded yet) shows a "coming soon" empty state.

🤖 Generated with Claude Code

Rebuild the web admin dashboard from scratch, replacing the old HTMX/Alpine
server-rendered UI with a client-side React SPA. It ships in the same single
binary (built to public/, served statically with an index.html catch-all for
client routes) and is driven entirely by the existing typed tRPC API.

New UI (src/web/client): a sidebar + topbar app shell with light/dark/auto
theming and a shared, reusable component library, plus screens for Overview,
Libraries, Library Detail with a chunk explorer, Jobs & Queue (live via event
subscriptions), a Search playground, and Settings.

Backend (composed into the merged appRouter):
- Export an AppRouter type for end-to-end client typing.
- getSystemHealth: honest snapshot of the running configuration (services,
  worker mode + maxConcurrency, embeddings, MCP endpoints, auth).
- listVersionChunks / getVersionStats: power the chunk explorer.
- Treat an empty-string version as "unversioned" in scrape/refresh input
  instead of rejecting it.
- Enable the tRPC API whenever the web interface is enabled.

Cleanup: remove the entire old HTMX UI and its now-dead dependencies (alpine,
htmx, flowbite, idiomorph, kitajs) plus the unused Tailwind/PostCSS stack;
flip the default JSX runtime to React; extend Biome to lint .tsx.

Follow-ups are tracked in docs/admin-ui-backlog.md and issues #449, #450, #451.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 21, 2026 21:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Rebuilds the admin web dashboard as a React + Vite SPA served from the existing single binary (public/ static hosting + index.html SPA fallback), and reshapes the backend tRPC surface to fully support the new UI (system health, chunk explorer, version handling, and always-on API when web is enabled). This also removes the legacy HTMX/Alpine server-rendered UI and its dependency stack.

Changes:

  • Replace the legacy server-rendered admin UI with a client-side React + Vite SPA under src/web/client/.
  • Add/compose new tRPC procedures + types to power the SPA (system health snapshot, chunk explorer endpoints, empty-string “unversioned” version support, unified AppRouter export).
  • Remove old UI routes/components/styles and Tailwind/PostCSS/HTMX/Alpine-related dependencies and configuration.

Reviewed changes

Copilot reviewed 120 out of 124 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
vite.config.web.ts Switch Vite build to React SPA, building into project-root public/.
tsconfig.json Flip JSX runtime defaults to React and remove kitajs HTML typing/plugin usage.
src/web/web.ts Remove legacy standalone Fastify web server setup for HTMX UI.
src/web/utils/versionCheck.test.ts Remove legacy version-check tests from old UI path.
src/web/styles/main.css Remove Tailwind/Flowbite/Alpine-era CSS entrypoint.
src/web/routes/stats.tsx Remove legacy HTMX stats endpoint.
src/web/routes/libraries/list.tsx Remove legacy HTMX libraries list + delete/refresh routes.
src/web/routes/jobs/new.tsx Remove legacy HTMX “new job” form + scrape submission endpoint.
src/web/routes/jobs/list.tsx Remove legacy HTMX jobs list endpoint.
src/web/routes/jobs/clear-completed.tsx Remove legacy HTMX clear-completed jobs endpoint.
src/web/routes/jobs/cancel.tsx Remove legacy HTMX cancel-job endpoint.
src/web/routes/index.tsx Remove legacy server-rendered root HTML shell.
src/web/routes/events.ts Remove legacy SSE events endpoint (replaced by tRPC WS subscriptions).
src/web/EventClient.ts Remove legacy SSE client implementation.
src/web/components/VersionBadge.tsx Remove legacy kitajs HTML component.
src/web/components/Tooltip.tsx Remove legacy Alpine-based tooltip component.
src/web/components/Toast.tsx Remove legacy Alpine/Flowbite toast component.
src/web/components/StatusBadge.tsx Remove legacy status badge component.
src/web/components/SearchResultSkeletonItem.tsx Remove legacy search loading skeleton component.
src/web/components/SearchResultList.tsx Remove legacy search result list component.
src/web/components/SearchResultItem.tsx Remove legacy server-side markdown rendering + DOMPurify path.
src/web/components/SearchResultItem.test.ts Remove tests tied to deleted server-rendered search component.
src/web/components/ScrapeForm.tsx Remove legacy HTMX scrape form wrapper.
src/web/components/ProgressBar.tsx Remove legacy progress bar component.
src/web/components/PrimaryButton.tsx Remove legacy primary button component.
src/web/components/LoadingSpinner.tsx Remove legacy loading spinner component.
src/web/components/LibrarySearchCard.tsx Remove legacy HTMX library search form card.
src/web/components/LibraryList.tsx Remove legacy library list component.
src/web/components/LibraryItem.tsx Remove legacy library list row/card component.
src/web/components/LibraryDetailCard.tsx Remove legacy library detail card component.
src/web/components/JobList.tsx Remove legacy job list component (including HTMX OOB swap).
src/web/components/JobItem.tsx Remove legacy job row component (Alpine confirm/cancel flow).
src/web/components/AnalyticsCards.tsx Remove legacy KPI cards component.
src/web/components/Alert.tsx Remove legacy Flowbite alert component.
src/web/components/AddVersionButton.tsx Remove legacy HTMX add-version button component.
src/web/components/AddJobButton.tsx Remove legacy HTMX add-job button component.
src/web/client/utils/versionCheck.ts Add SPA-side version normalization/comparison helpers for update checks.
src/web/client/pages/LibraryDetail.tsx Add SPA Library Detail page with chunk explorer + scrape config panel.
src/web/client/pages/library-detail/VersionTabs.tsx Add Library Detail version tab switcher component.
src/web/client/pages/library-detail/format.ts Add library-detail formatting/derivation helpers (status aggregation, labels, counts).
src/web/client/pages/jobs/types.ts Add client-side Job type derived from AppRouter outputs.
src/web/client/pages/jobs/JobCard.tsx Add SPA job card for running/queued/cancelling jobs.
src/web/client/pages/jobs/format.ts Add jobs page formatting helpers (elapsed/relative/progress).
src/web/client/pages/jobs/FailedJobCard.tsx Add SPA failed-job card with retry and edit-and-retry actions.
src/web/client/main.tsx Bootstrap React app, router, tRPC (HTTP + WS), and shared styles.
src/web/client/index.html Add Vite entry HTML shell with #root mount.
src/web/client/hooks/useUpdateCheck.ts Add GitHub latest-release check hook powering sidebar “Update available”.
src/web/client/hooks/useTheme.ts Add persisted light/dark/auto theme store via useSyncExternalStore.
src/web/client/CONVENTIONS.md Document SPA architecture, conventions, and hook/component usage guidance.
src/web/client/components/Topbar.tsx Add SPA topbar with route title/breadcrumb, add-library, theme toggle.
src/web/client/components/Toast.tsx Add SPA toast provider + hook for app-wide notifications.
src/web/client/components/ThemeToggle.tsx Add theme toggle button cycling auto/light/dark.
src/web/client/components/Textarea.tsx Add shared textarea component matching design system.
src/web/client/components/Table.tsx Add shared table primitives matching design system.
src/web/client/components/StatusDot.tsx Add shared status indicator dot component.
src/web/client/components/Spinner.tsx Add shared spinner/loading components.
src/web/client/components/Sparkline.tsx Add shared sparkline chart component.
src/web/client/components/Sidebar.tsx Add SPA sidebar with nav, live counts, and system status footer.
src/web/client/components/SegmentedControl.tsx Add shared segmented control component.
src/web/client/components/ProgressBar.tsx Add shared progress bar component.
src/web/client/components/Pill.tsx Add shared status pill component.
src/web/client/components/Modal.tsx Add shared modal primitive used by confirm dialog and others.
src/web/client/components/Markdown.tsx Add safe markdown renderer for chunks/search (no raw HTML).
src/web/client/components/LibIcon.tsx Add library icon monogram + best-effort favicon loading.
src/web/client/components/Input.tsx Add shared input component with optional icon/label/hint.
src/web/client/components/EmptyState.tsx Add shared empty state component for “no data” views.
src/web/client/components/Drawer.tsx Add shared drawer primitive for add/edit documentation flows.
src/web/client/components/ConfirmDialog.tsx Add app-wide confirm dialog provider + promise-based API.
src/web/client/components/Chip.tsx Add shared chip/tag component.
src/web/client/components/Checkbox.tsx Add shared checkbox component with label/hint.
src/web/client/components/Card.tsx Add shared card/surface component.
src/web/client/components/Button.tsx Add shared button component variants/sizes.
src/web/client/components/AreaChart.tsx Add hand-rolled area chart component for Overview activity panel.
src/web/client/components/AppProviders.tsx Compose overlay providers (toast/confirm/drawer) for the SPA.
src/web/client/App.tsx Add SPA shell layout and route table.
src/web/client/api/trpc.ts Add typed tRPC React Query client bound to merged AppRouter.
src/web/client/api/hooks.ts Add thin, centralized SPA hooks wrapping tRPC procedures.
src/store/types.ts Add chunk explorer DTOs (chunk list items + stats + pagination types).
src/store/trpc/router.ts Add listVersionChunks + getVersionStats procedures to data router.
src/store/trpc/router.test.ts Add integration tests for chunk explorer procedures via real store/router.
src/store/trpc/interfaces.ts Extend IDocumentManagement with chunk explorer APIs.
src/store/DocumentManagementService.ts Implement chunk explorer methods with VersionRef normalization.
src/store/DocumentManagementService.test.ts Add unit tests for new DocumentManagementService chunk explorer methods.
src/store/DocumentManagementClient.ts Add client-side implementations of new chunk explorer APIs.
src/services/webService.ts Remove legacy web-service route registration (HTMX UI).
src/services/trpcService.ts Switch HTTP+WS tRPC mounts to shared canonical appRouter + unified context.
src/services/systemInfo.ts Add startup configuration snapshot model + builder for system health reporting.
src/services/systemInfo.test.ts Add tests for buildSystemInfo.
src/services/systemHealthRouter.ts Add getSystemHealth tRPC router (startup snapshot + cheap live state).
src/services/systemHealthRouter.test.ts Add tests for system health router behavior.
src/services/appRouter.ts Add canonical merged AppRouter composition + context factory.
src/pipeline/trpc/router.ts Accept empty/whitespace version as unversioned in pipeline procedures.
src/pipeline/trpc/router.test.ts Add regression tests for empty-string version handling.
src/events/types.ts Remove SSE-specific event name/payload types now that SSE endpoint is gone.
src/events/index.ts Update exports to remove SSE-specific event types.
src/cli/commands/web.ts Enable tRPC API when running the web command (SPA requires /api).
src/app/AppServer.ts Serve SPA from public/ and add index.html catch-all for client-side routes; unify tRPC router/context.
postcss.config.cjs Remove Tailwind/PostCSS config.
package.json Remove HTMX/Alpine/Tailwind deps; add React/React Router/tRPC React Query deps.
docs/admin-ui-backlog.md Add follow-up backlog documenting deferrals and known gaps post-rebuild.
biome.json Extend lint/format to .tsx and add SPA-specific rule overrides.
.gitignore Ignore built SPA artifacts under public/.
.claude/launch.json Add run/preview configuration for launching the built app.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread vite.config.web.ts Outdated
Comment thread src/app/AppServer.ts
Comment thread biome.json Outdated
Comment thread biome.json Outdated
arabold and others added 3 commits July 21, 2026 14:54
Remove the temporary Biome override that disabled four rules for the admin
client, and fix the underlying code instead:

- noLabelWithoutControl: the scope / scrape-mode / custom-headers group labels
  in the documentation drawer are now `.form-label` spans (the composite
  controls carry their own aria-label) rather than control-less `<label>`s.
- useSemanticElements: SegmentedControl renders a `<fieldset>` (with the seg
  track styles reset); the Libraries row is now a real react-router `<Link>`
  (semantic navigation + native keyboard support) instead of a
  role="button" div.
- noArrayIndexKey: drawer header rows carry a stable id; Search results key on
  url + content prefix.
- useExhaustiveDependencies: drop the unused `mode` dep from the drawer reset
  effect; reset the chunk-explorer page offset during render (per React's "you
  might not need an effect") instead of an effect whose body read neither dep.

Also dedupe the one genuinely-identical cross-page helper (`displayUrl`) into
src/web/client/utils/format.ts; the relative-time formatters intentionally
differ per page and stay local.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ublicDir

From the Copilot review of PR #452:
- Cache the built index.html in-memory after the first read in the SPA shell
  handler, instead of re-reading it from disk on every deep-link/refresh.
- Set Vite `publicDir: false` — it pointed at the output dir (public/), which
  triggered a publicDir===outDir warning and a redundant copy step; the
  favicons/manifest it "copied" already live in public/ and are untouched.

The review's two other comments (Biome disabling a11y / exhaustive-deps rules
for the client) were already resolved in 506c7dc, which removed that override
and fixed the underlying code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants