feat: US-010 — Projects sidebar tree view and project detail routing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -181,8 +181,8 @@
|
||||
"Verify in browser using dev-browser skill"
|
||||
],
|
||||
"priority": 10,
|
||||
"passes": false,
|
||||
"notes": ""
|
||||
"passes": true,
|
||||
"notes": "Completed: ProjectSidebar reworked to show projects grouped by client (Collapsible groups), 'Internal / No Client' group for orphan projects, real-time search filter, archive toggle (Switch), context menu (Edit Client via Dialog+Select, Archive/Unarchive, Delete with AlertDialog), click selects project via search params, active project highlighted. ProjectDetail placeholder component. projects.update now accepts nullable clientId. shadcn/ui: dialog, select, switch installed."
|
||||
},
|
||||
{
|
||||
"id": "US-011",
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
- electron-store@8 (CJS) used for app settings; use lazy init pattern `getStore()` like `getDb()` to avoid calling before app ready
|
||||
- ESLint uses `eslint-import-resolver-typescript` to resolve `@/*` aliases; configured in `.eslintrc.json` under `settings.import/resolver`
|
||||
- App settings (sidebar state, etc.) exposed via `settings` tRPC sub-router for type-safe renderer access
|
||||
- `z.string().nullable().optional()` in tRPC inputs enables three-state semantics: undefined = don't change, null = clear, string = set value
|
||||
- TanStack Router `validateSearch` with Zod schema for passing selected-item IDs via URL search params (e.g., `?projectId=...`)
|
||||
---
|
||||
|
||||
## 2026-02-19 - US-002
|
||||
@@ -158,3 +160,24 @@
|
||||
- `useCallback` ref pattern (`ref={callbackRef}`) is used for auto-focus + select on mount without useEffect
|
||||
- The two-stage delete flow (try simple delete first → if error, show cascade option) maps well to the backend's `clients.delete` (guards) + `clients.deleteWithCascade` (force) pattern
|
||||
---
|
||||
|
||||
## 2026-02-19 - US-010
|
||||
- What was implemented:
|
||||
- Rewrote `ProjectSidebar` from a client-hierarchy tree to a project-centric sidebar grouped by client
|
||||
- Projects grouped by `clientId` using Collapsible headers; projects without a client appear under "Internal / No Client"
|
||||
- Search input filters projects by name in real-time (auto-expands all groups when searching)
|
||||
- Show/hide archived projects via Switch toggle (queries `projects.list` with `includeArchived`)
|
||||
- Context menu per project (DropdownMenu): Edit Client (Dialog + Select to assign/change/remove client), Archive/Unarchive, Delete (AlertDialog)
|
||||
- Clicking a project sets `projectId` in search params → renders ProjectDetail placeholder in right pane
|
||||
- Active project highlighted with `bg-sidebar-accent`
|
||||
- Updated `projects.update` tRPC procedure to accept `clientId: z.string().nullable().optional()` (allows unlinking from client)
|
||||
- Created placeholder `ProjectDetail` component (full implementation deferred to US-013)
|
||||
- Installed shadcn/ui: dialog, select, switch
|
||||
- Files changed: `src/renderer/components/projects/ProjectSidebar.tsx`, `src/renderer/routes/projects.tsx`, `src/renderer/components/projects/ProjectDetail.tsx` (new), `src/main/router/index.ts`, `src/renderer/components/ui/dialog.tsx` (new), `src/renderer/components/ui/select.tsx` (new), `src/renderer/components/ui/switch.tsx` (new), `scripts/ralph/prd.json`, `scripts/ralph/progress.txt`
|
||||
- **Learnings for future iterations:**
|
||||
- TanStack Router `validateSearch` with Zod schema is the cleanest way to pass selected-item IDs via URL search params without creating nested routes
|
||||
- `Route.useNavigate()` returns a typed navigate fn; use `void navigate({ search: { ... } })` to avoid unhandled promise warnings
|
||||
- For project grouping, query both `projects.list` and `clients.list` separately then join in-memory via a Map — avoids complex SQL joins for display-only data
|
||||
- `projects.update` with `clientId: z.string().nullable().optional()` allows three states: undefined (don't change), null (unlink), string (assign)
|
||||
- Auto-expanding all groups during search (`effectiveExpanded` computed from grouped keys) gives a better UX than forcing users to manually expand
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user