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>
11 KiB
11 KiB
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)
- Wire
views/DashboardView.vuestats 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). Addedservices/developer.tsandservices/review.tswrappers. - Replace fixed-lookup episode progress with real computed progress —
components/episode/EpisodeCard.vue:117-128andcomponents/episode/EpisodeList.vue:267-278— deferred: backend has nocompleted_shots/progressfield 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 newGET /projects/{id}/task-statuses/countsbackend endpoint - Register the missing route:
/projects/:projectId/technical-specsinrouter/index.ts - Delete confirmed-dead files (or finish wiring them in):
components/shot/ShotColumnVisibilityControl.vue— deletedcomponents/asset/ColumnVisibilityControl.vue— deletedcomponents/project/ShotsTable.vue— deletedcomponents/examples/FileUploadExample.vue— deletedviews/GlobalSettingsView.vue— deletedviews/HomeView.vue— deletedcomponents/asset/AssetDeleteConfirmDialog.vue— fixed (raw divs → sharedAlertcomponent) and wired intoAssetBrowser.vue, mirroringShotBrowser.vue's patterncomponents/activity/ActivityFeed.vue— wired intoProjectOverviewView.vuein place of "coming soon" text;TaskActivityTimeline.vue— deleted (notaskIdavailable at that call site)
- Replace native
confirm()/alert()with styled dialogs:components/task/NoteItem.vue:178→AlertDialogcomponents/task/TaskAttachments.vue:201→AlertDialogcomponents/layout/UserMenu.vuekeyboard-shortcutsalert()→Dialog
- Remove leftover debug logging (all 8 files/line-ranges)
- 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 onAPIKeysView.vue(removedaction-text/@actionsince it did nothing).- Removed dead-end UserMenu items (
/settings/preferences,/help, notifications toggle) and the/developer/docsdead 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)) andbackend/utils/activity.py(wrongmodels.submissionimport path →models.task). - Fixed a pre-existing bug shared by both
ShotDeleteConfirmDialog.vueandAssetDeleteConfirmDialog.vue: theirwatch(() => 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)
- Add user-assignment popover to
components/asset/EditableTaskStatus.vue— ported from the shot version; wired throughasset/columns.tsandAssetBrowser.vue - Add column-locking toggle to
components/asset/AssetTableToolbar.vue— two-pane frozen-column layout ported intoAssetsDataTable.vue(adapted for asset's page-scroll layout, no vertical scroll-sync needed unlike shot's bounded-height container) - Add row-actions ("…") menu to
components/task/columns.ts— "View Details" + "Reassign" (no Delete/Edit — no backenddeleteTask/task-edit-form exists) - Implement the asset detail-panel actions in
AssetBrowser.vue/AssetDetailPanel.vue: create task (task-type picker), select task (opensTaskDetailPanelin-place), create note/upload reference/publish version (task picker → deep-links intoTaskDetailPanel's Notes/Attachments/Submissions tabs via newinitialTabprop) - Implement the same for
ShotBrowser.vue/ShotDetailPanel.vue(also fixed the pre-existing dead "Add Note"/"Upload Reference" buttons there) - Consolidate
components/project/ProjectMembersManager.vueandcomponents/project/ProjectMemberManagement.vueinto one component (keptProjectMemberManagement.vue, deleted the other) — combined remove-confirmation + approved-user filtering + real avatars from one with toast feedback + sharedSelect/DialogUI-kit from the other - Wire the consolidated member-management component into
ProjectDetailView.vue:149-151— navigates to the project Settings "Team" tab (mirrors the existingmanageTechnicalSpecspattern) rather than a duplicate dialog
Bugs found and fixed during verification (approved mid-implementation):
GET /assets/{id}never returnedtask_details(schema didn't even declare the field) — unlikeGET /shots/{id}, which already did. Broke the asset detail panel's task list and, transitively, every new create-task/note/reference/version feature. Fixed inbackend/schemas/asset.py+backend/routers/assets.py.TaskBrowser.vue'shandleRowClickis a no-op by design (single click reserved for selection) — the new row-actions menu's "View Details"/"Reassign" needed to emitrow-double-clickinstead, which is what actually opens the panel.
Phase 3 — Unify controls
- Extract
ColumnToggleListcomponent (built onDropdownMenuCheckboxItem, not hand-rolled div+Check) and point at it from:components/ui/sidebar/SidebarColumnSwitch.vuecomponents/shot/ShotTableToolbar.vuecomponents/asset/AssetTableToolbar.vuecomponents/task/TaskTableToolbar.vue
- Extract shared
EntityTableToolbar(search, column-visibility trigger, detail-panel toggle, clear-filters) to de-duplicate the three toolbar files - Extract
SegmentedTogglecomponent 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/DropdownMenuCheckboxItemin:SidebarColumnSwitch.vueShotTableToolbar.vueAssetTableToolbar.vueTaskTableToolbar.vueShotTaskStatusFilter.vueasset/TaskStatusFilter.vue
- Replace ad hoc
size="sm" class="h-8 w-8 p-0"withsize="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 incomponents/task/TaskBulkActionsMenu.vue - Extract
DetailPanelShell(header/close button, loading state, error state, Tabs scaffold, slide-in transition) forShotDetailPanel.vue,AssetDetailPanel.vue,TaskDetailPanel.vueto 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 acrossstores/*.tsto cut repeated try/catch/finally boilerplate - Replace
stores/taskStatuses.ts's polling-based in-flight request de-dup (100mssetIntervalloop, 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.tsassignProjectIcon - Audit
deep: truewatchers, especiallyviews/ProjectsView.vue:770(watches the full, non-markRaw'd projects array) - Fix N+1 project-member fetch: hoist
getProjectMembers()call out ofEditableTaskStatus.vue(mounted per row × task-type column) into a shared store/cache or parent-passed prop - Add table virtualization (e.g.
@tanstack/vue-virtual) toShotsDataTable.vue,AssetsDataTable.vue,TasksDataTable.vue - Introduce a shared
EmptyStatecomponent and standardize onSkeletonfor loading states (currently: 5 files useSkeleton, 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 forShotBrowser.vue/AssetBrowser.vue's ~70% structural overlap - Move ad hoc domain types out of
services/*.tsintotypes/for discoverability (currently onlyauth.ts,notification.ts,activity.tslive intypes/)
Phase 5 — Testing & quality gates
- Add Vitest + Vue Test Utils
- Write first tests for the highest-risk untested logic:
stores/assets.tsoptimistic-update/rollback,stores/auth.tstoken lifecycle - Add an ESLint config (flag
any, unused locals, enforce consistent import/style rules) - Re-enable
noUnusedLocalsintsconfig.json(currently explicitly disabled) - Introduce a typed
ApiErrorhelper to replace ad hocerr.response?.data?.detailaccess at the 104catch (err: any)sites (fix incrementally as files are touched, not all at once) - Accessibility fixes: remove checkbox-inside-
SelectItemanti-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.