feat(web): add v2 interface built on shadcn/ui as an opt-in preference - #401
feat(web): add v2 interface built on shadcn/ui as an opt-in preference#401YSamed wants to merge 24 commits into
Conversation
Introduce a full shadcn-based preview surface in the web app: new login/signup v2 pages, an AppShell v2 with sidebar/navigation, and a projects v2 page with toolbar filters and create-project dialog wired to existing services. This also adds vendored shadcn primitives, theme bridge/reference/v4 styles, new routes, shared project-list filtering logic, and alias/lint config updates needed to support the new component structure. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a full AppShell v2 surface across workspace, project, analytics, and detail pages, including new v2 routes, header context wiring, and sidebar/navigation updates. Introduces reusable shadcn-based toolbars, dialogs, and UI primitives (charts, tables, tabs, toggles, popovers, progress) to support filtering, view management, and work-item creation/edit flows. Also updates supporting shared helpers and bumps web charting deps to enable the new analytics/chart components. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reworks the v2 sidebar to better match the new app layout: navigation is split into primary and workspace sections, and a translated Favorites section now renders the workspace favorites tree in the sidebar. It also updates `NavMain` and `NavProjects` to use cleaner collapsible triggers with inline chevrons, and removes extra project-menu complexity (hover actions, dropdown, and "more" truncation) so all projects and their subpages are directly accessible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reworks the v2 Projects and Notifications pages into fully responsive, shadcn-based experiences with richer controls: body-level projects toolbar (search/filter chips/view toggle/scope segments), grid+table project views, better loading/error/empty states, and a master-detail inbox with unread tab, search, mobile sheet detail, and inline action handling. Adds a new shadcn NotificationSnoozeMenu, introduces a shared project refresh event to keep sidebar/project lists in sync after mutations, passes workspace members into project creation/toolbar to avoid duplicate fetches, and fixes project access filtering to use the project network value. Also expands EN/AZ i18n strings for the new UI and makes V2 home stickies follow theme changes in real time. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add repo guidance for the v2 web surface in `CLAUDE.md` and `apps/web/README.md`, pointing contributors to the shadcn/ui docs, source repo, and AdminCN reference before changing v2 components. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces shared `useProjectIssuesController` and `useProjectCyclesController` hooks, then rewires both legacy and v2 pages to use the same data/filter/grouping logic so behavior stays aligned across designs. Adds a full v2 work-items experience (filters/display menus, bulk actions, row/context actions, inline editing, board/calendar/gantt/spreadsheet layouts) plus expanded v2 cycles and views toolbars. Also adds new shadcn primitives (alert dialog, calendar, checkbox, command, context menu, scroll area, sonner, etc.), wires v2 toast support, pre-bundles lazy-only deps in Vite to avoid runtime dynamic-import failures, and fixes project list view defaults to table-first. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaced v2 usage of the legacy create modal with the new shadcn work-item dialog, adding richer fields (including parent selection), inline label creation, improved responsive layout, and safer submit/close behavior so failed saves keep the composer open with errors visible. Added a shared helper to attach cycle/module relations after creation using partial-success handling, with toast warnings when relation links fail. Updated workspace views and toolbar to support in-page work item creation, improved list/table accessibility and responsiveness, localized static view/display labels, and refined default v2 display state and column ordering (including state). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces shared v2 primitives (`PageHeading`, `ListPageSkeleton`, `DetailPageSkeleton`, `ProjectListToolbar`) and migrates pages to use them, moving list controls out of the shell header and into consistent in-page toolbars. Updates archives, drafts, analytics, profile, issue detail, and project list pages with richer loading/error/empty states, improved accessibility labels, and responsive table layouts; also replaces `project-search-toolbar`, adds a shadcn-based work-item subscribe button, updates nav-user actions/sign-out flow, and expands EN/AZ translations to cover the new UI copy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Builds a complete v2 settings surface across account, workspace, and project scopes, including new reusable settings shell/panel primitives and dedicated sections for profile, preferences, security, notifications, members, tokens, exports, automations, labels, and states. Adds new `/app-v2/settings` routes (including account and per-project paths), wires project-level settings entry points in navigation, and keeps settings navigation inside the v2 shell. Also standardizes several v2 page section/scope controls by replacing Tabs usage with ToggleGroup-based segmented controls for consistent behavior and styling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces Turkish (`tr`) as a supported UI language end-to-end: parser config, i18n bootstrap, docs, dynamic key notes, and a full Turkish translation catalog, alongside many new/normalized English keys. The v2 sidebar navigation now uses translated labels via `t()`. For the v2 shell preview, switches from the `shadcn-v4` class to a new scoped `shadcn-app` class so shadcn border defaults apply without forcing the stock v4 palette. This keeps Devlane theme tokens (including pink), aligns portalled dropdown borders, and updates related style/docs comments to clarify intended usage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces a shared `AuthPageShellV2` and new v2 auth/onboarding flows: forgot/reset password, set password, invite accept/sign-up, and create workspace. Adds reusable password-field primitives (strength, match, show/hide) and refactors signup/login to reuse them and remove duplicated layout logic. Routes are wired for all new `*-v2` pages, including protected v2 routes with a configurable `signInPath` so expired sessions redirect to `/login-v2` instead of v1 pages. Also updates related links and adds shared auth hero localization keys in English and Turkish. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces a global InterfaceContext (persisted in localStorage) and an InterfaceGate that automatically redirects v1 routes to v2 when users opt into the new interface. Adds bidirectional path mappers for static and workspace routes, preserving query strings and navigation state. Exposes the interface toggle in both settings UIs (legacy and shadcn v2 account preferences) and adds matching EN/TR translations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Switches the v2 AppShell wrapper from `shadcn-app` to `shadcn-v4` on both `document.body` and `SidebarProvider`. This makes the preview use the stock upstream shadcn new-york-v4 palette consistently, and updates the inline docs to clarify that this intentionally bypasses Devlane’s token bridge/theme picker (including pink) for pixel-faithful comparison. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nder src/v2
v2 used to be a second route tree under /:workspaceSlug/app-v2, reached by
bouncing v1 URLs through a 350-line path mapper. Both interfaces now answer to
the same URLs: routes/index.tsx declares each path once and picks the element
with <Variant v1={...} v2={...} />, which reads the stored interface preference.
Switching no longer navigates — the page re-renders in place.
Routing:
- Drop lib/interfaceRedirect.ts, components/InterfaceGate.tsx and every *-v2
path (login-v2, invite-v2, the whole app-v2 subtree).
- v2 links now use the shipped URL shapes; a project's work items live at
/projects/:id/issues, and v2 redirects /board to issues?layout=board.
- Both shells mount on the :workspaceSlug route and render an <Outlet />, so
child routes are shared.
Isolation:
- Move the entire v2 interface under src/v2/, mirroring src/: a v2 page carries
the same filename and export name as the v1 page it replaces
(v2/pages/IssueListPage.tsx <-> pages/IssueListPage.tsx). components.json now
aliases @/v2/components.
- Restore every v1 file to its pre-v2 state, including IssueListPage and
CyclesPage; the controllers they had been refactored into move to
src/v2/hooks. The only v2-aware line left in v1 is <InterfaceSwitch /> in
SettingsPage, implemented in routes/InterfaceSwitch.tsx.
- Add a no-restricted-imports rule: nothing outside src/v2 and src/routes may
import from src/v2.
- v2 styles become their own Tailwind entry imported by the v2 shells, so the
global index.css stays untouched and a v1 reader never downloads them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Expose structured activity metadata from the API (`verb`, `field`, `old_value`, `new_value`) for non-free-text issue activity rows, then render localized activity text on the client via a new `describeActivity` helper in both v1 and v2 settings activity panels. Add the related i18n keys/translations (en/tr/az), including notification row labels/descriptions and activity field/action phrases. Also move scoped shadcn border-color defaults into `@layer base` so utility `border-*` colors in v2 are no longer unintentionally overridden. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Improve the v2 navigation experience by rendering a v2-specific Suspense fallback and adding an animated page-enter transition in the v2 AppShell. Also import `tw-animate-css` (and add it to dependencies) so shadcn animation utility classes like `animate-in`, `fade-in-*`, and `slide-in-*` actually work in Tailwind v4. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cap the popover panels at the available height the popper reports and stack the work item grouping toggles vertically so the three full-sentence labels no longer spill out of the panel. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 196 files, which is 96 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (196)
You can disable this status message by setting the 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 |
|
Out of draft and ready for review. All three checks are green. Context and the design rationale live in discussion #400 — #400 — including screenshots and the two open questions (should v2 stay opt-in, and what the long-term plan for v1 is). Neither question blocks review: v2 is off by default, and v1 is unchanged apart from a single One note for reviewers: CodeRabbit skipped its automated pass because the PR has 173 files and its limit is 100. 148 of those files are new files under Happy to split this into a series of smaller PRs (primitives and shell first, then pages in batches) if that reviews better — just say the word. |
Adjusts v2 cycle/work-item filter and display popovers to use explicit ScrollArea height calculations instead of flex growth. This prevents Radix ScrollArea viewports from expanding to full content height (and not scrolling) when constrained by available popover space, while accounting for headers and borders in each panel.
Adds shared v2 list UX primitives (filter menu/chips, sort menu) and wires them into epics, modules, pages, views, intake, drafts, archives, and projects with URL/localStorage-backed preferences. Introduces create dialogs for cycles, epics, modules, pages, and project views, plus project issues/workspace view persistence helpers and last-opened workspace view routing in the sidebar. Also updates v2 shell/sidebar visuals (dithered logo, toolbar/layout refinements), adds optional mock-data infrastructure for v2 development, and significantly refreshes the v2 profile page layout and interactions. Translation keys were expanded in en/tr/az to support the new controls, dialogs, and profile copy.
The v2 mock data module and its hook were never imported by any page. They also broke CI: the underscore-prefixed parameters tripped @typescript-eslint/no-unused-vars, which has no argsIgnorePattern in this repo's ESLint config. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Prevents v2 UI state from being overwritten during initial hydration and route changes by gating writes until localStorage/URL restores have actually landed. This adds restore-tracking guards for saved view display settings, project issue display state, and workspace URL-sync state (including StrictMode double-effect behavior). It also makes the v2 shell read the sidebar cookie for `defaultOpen` so collapse state persists correctly in the SPA.
Adds a new v2 accent color system with persisted presets (default, blue, violet, green, orange, rose) and CSS token overrides that only recolor primary actions and focus rings in both light and dark modes. Updates the v2 account preferences UI to separate appearance into mode + accent controls, wires accent state into the AppShell (including portal content), and adds new i18n strings for EN/TR/AZ.
Feature summary
Adds a second Devlane web interface ("v2") built on shadcn/ui, which a user opts into from Settings. Both interfaces answer the same URLs, so a link shared between users opens in whichever interface each of them prefers.
Linked issues / discussion
Design discussion: #400
User-facing behavior
Settings gains an interface switch. Flipping it to v2 stores
devlane-interface-versionin localStorage and re-renders the app with the shadcn-based shell, navigation, and pages — same routes, same data, same permissions. Flipping it back restores v1 exactly. Nothing about v2 is visible to a user who hasn't opted in.The v2 surface covers workspace home, projects, work items (list, detail, creation), epics, cycles, modules, views, pages, drafts, archives, intake, analytics, notifications, settings, and the full auth flow (login, sign-up, invite accept, forgot/reset/set password). Turkish is available alongside English.
What changed
API (
apps/api/)internal/handler/user.go—GetActivitynow also returnsverb,field,old_value, andnew_valuefor activity rows that have no free-text comment, so the client can compose the sentence in the user's own language instead of rendering a pre-built Englishdescription.descriptionis still sent and unchanged; the added fields are additive and existing consumers are unaffected.UI (
apps/web/)src/v2/**— the entire v2 interface (148 of the 174 changed files): ~40 shadcn/ui primitives undersrc/v2/components/ui, plus contexts, hooks, layout shell, domain components, and ~31 pages.src/v2/mirrorssrc/, so a v2 page carries the same filename and export name as the v1 page it replaces.src/routes/index.tsx— each path is still declared once; the element is chosen by<Variant v1={…} v2={…} />(src/routes/InterfaceVariant.tsx), which reads the preference fromsrc/v2/contexts/InterfaceContext. Setup and instance-admin stay v1-only.src/routes/InterfaceSwitch.tsx— the Settings toggle. Its single call site insrc/pages/SettingsPage.tsxis the only v2-aware line in any v1 file.eslint.config.js— forbids importing fromsrc/v2outsidesrc/v2/andsrc/routes/, so the isolation is enforced by the build rather than by convention.i18next-parser.config.cjsplus English and Turkish resources.components.json(new-york, slate, lucide,@/v2/components/ui),tsconfigpath aliases, and the@alias invite.config.ts.AGENTS.mddocuments the v2 design direction and its reference sources;CLAUDE.mdgains a section describing the isolation rules above.Database
No schema changes.
Why this design
Refactoring the existing UI in place would mean touching every page of a UI that people already use, with regressions landing directly on them and no way back. Shipping v2 as a parallel, opt-in surface means v1 is bit-for-bit what it would be without this PR, the two can be compared side by side by the same user on the same URL, and the work can land incrementally instead of as one flag day.
Making it a preference rather than a
/v2/route prefix was the other significant choice: a route prefix forks every URL in the product, breaks links pasted between users on different interfaces, and would have required v2 copies of the route tree. Keying off a stored preference keeps one route table and one set of URLs.The ESLint boundary matters more than it looks: without it, a v1 file importing one v2 component would quietly make v2's CSS and dependencies part of the v1 bundle, and the isolation claim above would stop being true within a release or two.
Test plan
npm run validate— web typecheck,eslint --max-warnings=0, andprettier --checkall pass;go vet ./...passes.go test ./...was not run locally (the suite needs Docker for testcontainers-postgres, which isn't available on this machine); CI covers it, and this PR changes one Go file.Screenshots / recording
Out of scope (follow-ups)
Rollout notes
Opt-in and off by default — no flag day, and no action needed at deploy time. The API and UI can deploy in either order: the added activity fields are additive, and the v2 client falls back to
descriptionwhen they're absent.AI assistance
Claude Code— and AI-assisted commits include aCo-Authored-By:trailerChecklist
internal/config/config.go— none added--no-verifybypass