cd3628a255
Phase 2 of frontend_tasks.md - close feature gaps between domains: - Asset user-assignment popover, ported from shot's EditableTaskStatus, wired through columns.ts and AssetBrowser.vue. - Asset column-locking toggle: two-pane frozen-column layout ported into AssetsDataTable.vue (adapted for asset's page-scroll layout, which has no bounded-height container like shot's). - Task table row-actions menu (View Details + Reassign only - no Delete/Edit, since no backend support exists for either). - Real select-task/create-task behavior on asset and shot detail panels: clicking a task swaps in the actual TaskDetailPanel in place; "Add Task" opens a task-type picker that creates real tasks via the existing createAssetTask/createShotTask services. - create-note/upload-reference/publish-version implemented via a task-picker that deep-links into TaskDetailPanel's Notes/ Attachments/Submissions tabs (new initialTab prop), reusing the already-working task-level components instead of building three new bespoke forms. Also fixed shot's pre-existing dead "Add Note"/ "Upload Reference" buttons the same way. - Consolidated ProjectMembersManager.vue and ProjectMemberManagement.vue into one component, combining remove-confirmation and approved-user filtering with toast feedback and the shared Select/Dialog UI kit. - Wired ProjectDetailView's "Manage Members" to navigate to the project's Settings > Team tab. Also fixed a bug in this session's own new code: TaskBrowser.vue's row-click handler is a no-op by design, so the new row-actions menu needed to emit row-double-click (which actually opens the panel) instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
99 lines
11 KiB
Markdown
99 lines
11 KiB
Markdown
# Frontend Improvement Tasks
|
||
|
||
Derived from `frontend_report.md`. Checklist form for tracking progress — check items off as they land. Ordered by phase (do Phase 1 before Phase 2, etc.); within a phase, order doesn't matter much.
|
||
|
||
---
|
||
|
||
## Phase 1 — Truth-in-UI & dead code ✅ (done)
|
||
|
||
- [x] Wire `views/DashboardView.vue` stats to real API data where an endpoint exists (projects, active projects, overdue tasks, total users, pending approvals, API keys, developer stats, pending reviews, admin system activity). Added `services/developer.ts` and `services/review.ts` wrappers.
|
||
- [ ] Replace fixed-lookup episode progress with real computed progress — `components/episode/EpisodeCard.vue:117-128` and `components/episode/EpisodeList.vue:267-278` — **deferred**: backend has no `completed_shots`/`progress` field yet (`backend/schemas/episode.py`, `backend/routers/episodes.py`)
|
||
- [ ] Fix task-status usage counts always showing 0 — `components/settings/CustomTaskStatusManager.vue:275-295` — **deferred**: needs a new `GET /projects/{id}/task-statuses/counts` backend endpoint
|
||
- [x] Register the missing route: `/projects/:projectId/technical-specs` in `router/index.ts`
|
||
- [x] Delete confirmed-dead files (or finish wiring them in):
|
||
- [x] `components/shot/ShotColumnVisibilityControl.vue` — deleted
|
||
- [x] `components/asset/ColumnVisibilityControl.vue` — deleted
|
||
- [x] `components/project/ShotsTable.vue` — deleted
|
||
- [x] `components/examples/FileUploadExample.vue` — deleted
|
||
- [x] `views/GlobalSettingsView.vue` — deleted
|
||
- [x] `views/HomeView.vue` — deleted
|
||
- [x] `components/asset/AssetDeleteConfirmDialog.vue` — fixed (raw divs → shared `Alert` component) and wired into `AssetBrowser.vue`, mirroring `ShotBrowser.vue`'s pattern
|
||
- [x] `components/activity/ActivityFeed.vue` — wired into `ProjectOverviewView.vue` in place of "coming soon" text; `TaskActivityTimeline.vue` — deleted (no `taskId` available at that call site)
|
||
- [x] Replace native `confirm()`/`alert()` with styled dialogs:
|
||
- [x] `components/task/NoteItem.vue:178` → `AlertDialog`
|
||
- [x] `components/task/TaskAttachments.vue:201` → `AlertDialog`
|
||
- [x] `components/layout/UserMenu.vue` keyboard-shortcuts `alert()` → `Dialog`
|
||
- [x] Remove leftover debug logging (all 8 files/line-ranges)
|
||
- [x] Removed Google OAuth stub buttons (`LoginView.vue`, `RegisterView.vue`) — no OAuth backend exists, so the buttons were pure dead ends
|
||
- [ ] `/developer/api-keys`, `/developer/projects`, `/developer/tasks`, `/developer/analytics`, `views/ReviewsView.vue` — **left as-is**: their empty states are honest ("No API keys" etc.), not misleading, so out of scope for a truth-in-UI pass. Only fixed the one dead action button on `APIKeysView.vue` (removed `action-text`/`@action` since it did nothing).
|
||
- [x] Removed dead-end UserMenu items (`/settings/preferences`, `/help`, notifications toggle) and the `/developer/docs` dead link (`AppSidebar.vue`, `DashboardView.vue`) — no real destination existed for any of them
|
||
|
||
**Bonus fixes surfaced during verification (approved mid-implementation):**
|
||
- Fixed two pre-existing backend bugs that 500'd once real data was wired up: `backend/routers/reviews.py` (`joinedload("reviewer")` string → `joinedload(Review.reviewer)`) and `backend/utils/activity.py` (wrong `models.submission` import path → `models.task`).
|
||
- Fixed a pre-existing bug shared by both `ShotDeleteConfirmDialog.vue` and `AssetDeleteConfirmDialog.vue`: their `watch(() => props.open, ...)` lacked `{ immediate: true }`, so the impact-summary section never rendered since the dialog only mounts once already open. Deletion itself worked fine either way — this was purely cosmetic, but it was the whole point of the "impact summary" safety feature.
|
||
|
||
## Phase 2 — Close feature gaps (asset vs. shot parity) ✅ (done)
|
||
|
||
- [x] Add user-assignment popover to `components/asset/EditableTaskStatus.vue` — ported from the shot version; wired through `asset/columns.ts` and `AssetBrowser.vue`
|
||
- [x] Add column-locking toggle to `components/asset/AssetTableToolbar.vue` — two-pane frozen-column layout ported into `AssetsDataTable.vue` (adapted for asset's page-scroll layout, no vertical scroll-sync needed unlike shot's bounded-height container)
|
||
- [x] Add row-actions ("…") menu to `components/task/columns.ts` — "View Details" + "Reassign" (no Delete/Edit — no backend `deleteTask`/task-edit-form exists)
|
||
- [x] Implement the asset detail-panel actions in `AssetBrowser.vue`/`AssetDetailPanel.vue`: create task (task-type picker), select task (opens `TaskDetailPanel` in-place), create note/upload reference/publish version (task picker → deep-links into `TaskDetailPanel`'s Notes/Attachments/Submissions tabs via new `initialTab` prop)
|
||
- [x] Implement the same for `ShotBrowser.vue`/`ShotDetailPanel.vue` (also fixed the pre-existing dead "Add Note"/"Upload Reference" buttons there)
|
||
- [x] Consolidate `components/project/ProjectMembersManager.vue` and `components/project/ProjectMemberManagement.vue` into one component (kept `ProjectMemberManagement.vue`, deleted the other) — combined remove-confirmation + approved-user filtering + real avatars from one with toast feedback + shared `Select`/`Dialog` UI-kit from the other
|
||
- [x] Wire the consolidated member-management component into `ProjectDetailView.vue:149-151` — navigates to the project Settings "Team" tab (mirrors the existing `manageTechnicalSpecs` pattern) rather than a duplicate dialog
|
||
|
||
**Bugs found and fixed during verification (approved mid-implementation):**
|
||
- `GET /assets/{id}` never returned `task_details` (schema didn't even declare the field) — unlike `GET /shots/{id}`, which already did. Broke the asset detail panel's task list and, transitively, every new create-task/note/reference/version feature. Fixed in `backend/schemas/asset.py` + `backend/routers/assets.py`.
|
||
- `TaskBrowser.vue`'s `handleRowClick` is a no-op by design (single click reserved for selection) — the new row-actions menu's "View Details"/"Reassign" needed to emit `row-double-click` instead, which is what actually opens the panel.
|
||
|
||
## Phase 3 — Unify controls
|
||
|
||
- [ ] Extract `ColumnToggleList` component (built on `DropdownMenuCheckboxItem`, not hand-rolled div+Check) and point at it from:
|
||
- [ ] `components/ui/sidebar/SidebarColumnSwitch.vue`
|
||
- [ ] `components/shot/ShotTableToolbar.vue`
|
||
- [ ] `components/asset/AssetTableToolbar.vue`
|
||
- [ ] `components/task/TaskTableToolbar.vue`
|
||
- [ ] Extract shared `EntityTableToolbar` (search, column-visibility trigger, detail-panel toggle, clear-filters) to de-duplicate the three toolbar files
|
||
- [ ] Extract `SegmentedToggle` component for the three hand-built view-mode switches (shot grid/list/table, asset grid/list, task all/shots/assets)
|
||
- [ ] Standardize delete confirmation on the shot pattern (`Dialog` + `Alert` + impact summary + type-to-confirm) for any cascading delete; fix asset's dialog to match or consciously keep it lighter
|
||
- [ ] Swap hand-rolled checkbox-divs for real `Checkbox`/`DropdownMenuCheckboxItem` in:
|
||
- [ ] `SidebarColumnSwitch.vue`
|
||
- [ ] `ShotTableToolbar.vue`
|
||
- [ ] `AssetTableToolbar.vue`
|
||
- [ ] `TaskTableToolbar.vue`
|
||
- [ ] `ShotTaskStatusFilter.vue`
|
||
- [ ] `asset/TaskStatusFilter.vue`
|
||
- [ ] Replace ad hoc `size="sm" class="h-8 w-8 p-0"` with `size="icon-sm"` across toolbar/browser icon buttons
|
||
- [ ] Decide one convention (icon+label vs. icon-only+tooltip) for primary "create" CTAs and apply consistently (shot/asset create buttons currently lack tooltips project/episode create buttons have)
|
||
- [ ] Standardize row-actions/bulk-actions on `DropdownMenu`/`DropdownMenuItem`; replace ad hoc `<button>` list in `components/task/TaskBulkActionsMenu.vue`
|
||
- [ ] Extract `DetailPanelShell` (header/close button, loading state, error state, Tabs scaffold, slide-in transition) for `ShotDetailPanel.vue`, `AssetDetailPanel.vue`, `TaskDetailPanel.vue` to share; add missing error state to Task's panel
|
||
|
||
## Phase 4 — Architecture & tooling investment
|
||
|
||
- [ ] Add a shared `useAsyncAction`-style composable (`isLoading`/`error`/`run(fn)`) and adopt it across `stores/*.ts` to cut repeated try/catch/finally boilerplate
|
||
- [ ] Replace `stores/taskStatuses.ts`'s polling-based in-flight request de-dup (100ms `setInterval` loop, lines 96-117) with promise memoization
|
||
- [ ] Extend a similar TTL/cache strategy to `stores/assets.ts`, `stores/tasks.ts`, `stores/projects.ts`, `stores/episodes.ts` (currently no caching — every view re-fetches on mount)
|
||
- [ ] De-duplicate `assets.ts`'s optimistic-update/rollback logic between single (`lines 156-234`) and bulk (`lines 236-356`) task-status updates into one parameterized function
|
||
- [ ] Add `markRaw()` around icon components stored in reactive state — `stores/projects.ts` `assignProjectIcon`
|
||
- [ ] Audit `deep: true` watchers, especially `views/ProjectsView.vue:770` (watches the full, non-`markRaw`'d projects array)
|
||
- [ ] Fix N+1 project-member fetch: hoist `getProjectMembers()` call out of `EditableTaskStatus.vue` (mounted per row × task-type column) into a shared store/cache or parent-passed prop
|
||
- [ ] Add table virtualization (e.g. `@tanstack/vue-virtual`) to `ShotsDataTable.vue`, `AssetsDataTable.vue`, `TasksDataTable.vue`
|
||
- [ ] Introduce a shared `EmptyState` component and standardize on `Skeleton` for loading states (currently: 5 files use `Skeleton`, 62 use ad hoc spinners; 31 files hand-roll empty-state text)
|
||
- [ ] Add toast-on-error for currently-silent secondary loads: episodes/task-types/task-statuses/project-context in `ShotBrowser.vue` (lines 474-508), `stores/notifications.ts:fetchStats`, router auth-init failure (`router/index.ts:190-196`)
|
||
- [ ] Centralize a `usePermission()`/`can()` composable to consolidate role/admin checks currently duplicated across ~20 components outside the router guard
|
||
- [ ] Consider splitting the largest files into smaller pieces: `views/project/ShotDetailView.vue` (1658 lines), `views/admin/DeletedItemsManagementView.vue` (1279 lines), and evaluate a shared "entity browser" composable for `ShotBrowser.vue`/`AssetBrowser.vue`'s ~70% structural overlap
|
||
- [ ] Move ad hoc domain types out of `services/*.ts` into `types/` for discoverability (currently only `auth.ts`, `notification.ts`, `activity.ts` live in `types/`)
|
||
|
||
## Phase 5 — Testing & quality gates
|
||
|
||
- [ ] Add Vitest + Vue Test Utils
|
||
- [ ] Write first tests for the highest-risk untested logic: `stores/assets.ts` optimistic-update/rollback, `stores/auth.ts` token lifecycle
|
||
- [ ] Add an ESLint config (flag `any`, unused locals, enforce consistent import/style rules)
|
||
- [ ] Re-enable `noUnusedLocals` in `tsconfig.json` (currently explicitly disabled)
|
||
- [ ] Introduce a typed `ApiError` helper to replace ad hoc `err.response?.data?.detail` access at the 104 `catch (err: any)` sites (fix incrementally as files are touched, not all at once)
|
||
- [ ] Accessibility fixes: remove checkbox-inside-`SelectItem` anti-pattern (also fixes the double-toggle bug), add keyboard support to hand-rolled clickable `<div>`s (`SubmissionCard.vue`, `EditableTaskStatus.vue`)
|
||
|
||
---
|
||
|
||
*Full context, rationale, and file-by-file findings for every item above are in `frontend_report.md`.*
|