Replace admin UI with a React + Vite + tRPC single-page app#452
Open
arabold wants to merge 4 commits into
Open
Replace admin UI with a React + Vite + tRPC single-page app#452arabold wants to merge 4 commits into
arabold wants to merge 4 commits into
Conversation
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>
There was a problem hiding this comment.
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
AppRouterexport). - 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.
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 anindex.htmlcatch-all forclient-side routes) — no new runtime, no meta-framework.
What changed
New UI (
src/web/client/) — a sidebar + topbar app shell with light/dark/autotheming, built from a shared, reusable component library (no per-page duplication):
version's stored chunks as rendered Markdown, with per-chunk metadata)
live updates via the
eventssubscriptionsearchresults rendered as MarkdownBackend (composed into the merged
appRouter):AppRoutertype for end-to-end client typinggetSystemHealth— honest snapshot of the running config (services, workermode +
maxConcurrency, embeddings, MCP endpoints, auth)listVersionChunks/getVersionStats— power the chunk explorerversionas "unversioned" in scrape/refresh inputstandalone
webcommand)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