Skip to content

refactor(web): one view registry drives the shell (PR 3) - #501

Merged
huyplb merged 1 commit into
mainfrom
refactor/web-feature-registry
Oct 10, 2026
Merged

huyplb merged 1 commit into
mainfrom
refactor/web-feature-registry

Conversation

@huyplb

@huyplb huyplb commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

PR 3 of the feature-architecture schedule. Nothing a user sees changes.

Before

A workspace view was wired in five places: the ActiveView union, viewLoaders.ts, App.tsx (lazy constants, a redirect effect, a ternary chain), the rail's id→view/icon/test-id maps, and uiStore's persisted-view list.

After

  • app/features/viewIds.ts: the ids. It has no imports, so uiStore validates a persisted view without loading the registry.
  • app/features/featureRegistry.ts: WORKSPACE_VIEWS: Record<ActiveView, …>, so TypeScript refuses a missing entry. Each entry holds:
    • its rail button (label and permission from COMMUNITY_NAV, or its own)
    • allowed and fallback
    • its lazy load
    • inside prefetch
  • App.tsx renders WORKSPACE_VIEWS[activeView]; ActivityRail uses railItems; main.tsx and the rail prefetch through prefetchView. viewLoaders.ts is deleted.
  • Each feature's lazy entry is view.ts (access, utilities, workflow, sql-editor, lokee-weave), never its barrel. sql-editor also has viewPane.ts, so Monaco still loads alongside the view rather than after it.
  • The test-ID extractor also reads app/features/*.ts, where the rail's IDs now live as data. The catalog has the same 1717 IDs.

Tests

featureRegistry.test.ts (10), A/B-checked:

  • every id is defined, shown directly or loaded
  • nav ids exist in COMMUNITY_NAV
  • each lazy entry is a real root-level view* file
  • rail order, labels and test IDs for owner, viewer and partial roles
  • every redirect: editor-only → Editor; no editor → Compare or Home; Utils and Snapshots → Home

Checks

  • typecheck 0, ESLint clean, first load within the 170 KB budget.
  • Full suite passes.
  • Live e2e against the dev server on this branch: 36 passed, 1 skipped (smoke, lazy-loading, schema-browse, sql-editor-sqlite, access-assistant-sqlite, admin-policy, workspaces).

🤖 Generated with Claude Code


Note

Low Risk
Behavior-preserving shell refactor with dedicated tests for rail items and redirects; server-side authorization is unchanged.

Overview
Introduces a single workspace view registry (viewIds.ts + featureRegistry.ts) so rail buttons, lazy loaders, prefetch (inside for Monaco), and permission redirects live in one typed WORKSPACE_VIEWS map instead of scattered across App.tsx, ActivityRail, and deleted viewLoaders.ts.

App.tsx builds one lazy component per view from the registry and renders via redirectFor + a generic View wrapper, replacing the long activeView ternary chain and inline redirect useEffect. ActivityRail calls railItems(can) instead of local nav/icon/test-id maps. Features gain root view.ts (and sql-editor viewPane.ts) lazy entries; Compare moves into SyncWorkspace.tsx, settings into SettingsView.tsx.

uiStore imports ActiveView / isActiveView from viewIds (no registry load on persist). E2E test IDs for rail workspace buttons are attributed to featureRegistry in the extractor and docs. featureRegistry.test.ts locks rail order, visibility, and redirects to match the old shell.

Reviewed by Cursor Bugbot for commit 2e6fc5c. Bugbot is set up for automated code reviews on this repo. Configure here.

… view entry

PR 3 of the feature-architecture series. What a user sees is unchanged:
the rail's order, labels and test IDs, and every permission redirect, are
pinned by tests against what the hand-wired shell did.

- app/features/viewIds.ts: the view ids (no imports, so the UI store can
  validate a persisted view cheaply); ActiveView derives from it.
- app/features/featureRegistry.ts: WORKSPACE_VIEWS, typed
  Record<ActiveView, …> so a missing entry does not compile: rail button,
  who may see it, the fallback, the lazy entry, what to prefetch inside.
  railItems / redirectFor / prefetchView read it.
- App.tsx renders WORKSPACE_VIEWS[activeView]; its five lazy constants,
  the hand-written redirect effect and the ternary chain are gone.
- ActivityRail takes its buttons from railItems; viewLoaders.ts is gone.
- Each feature's lazy entry is view.ts (sql-editor also viewPane.ts, so
  Monaco still loads alongside the view); Settings and Compare get small
  view wrappers in the app layer.
- The test-ID extractor also reads app/features/*.ts, where the rail's
  IDs now live as data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 0ed88397-0112-4c9f-863b-e7a6ec06116c)

@huyplb
huyplb merged commit d10dc3d into main Oct 10, 2026
13 checks passed
@huyplb
huyplb deleted the refactor/web-feature-registry branch October 10, 2026 16:32
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.

1 participant