Truth-in-UI cleanup: wire real dashboard data, fix delete/dialog gaps

Phase 1 of frontend_tasks.md - stop showing fabricated/broken UI:

- Dashboard now fetches real stats (projects, tasks, users, pending
  approvals, API keys, developer stats, pending reviews, admin
  activity) instead of hardcoded numbers. Added services/developer.ts
  and services/review.ts wrappers for previously-unused backend
  endpoints.
- Wired ActivityFeed into every project's Overview page in place of
  the "coming soon" placeholder.
- Registered the missing /projects/:id/technical-specs route (view
  and service already existed, just unreachable).
- Fixed AssetDeleteConfirmDialog's raw styled divs to use the shared
  Alert component and wired it into AssetBrowser, matching
  ShotBrowser's impact-summary + type-to-confirm safety pattern
  (asset deletion was previously less safe than shot deletion).
- Fixed a shared bug in both delete dialogs where the impact-summary
  section never rendered (watch on the open prop needed
  { immediate: true }).
- Replaced native confirm()/alert() with styled AlertDialog/Dialog in
  NoteItem, TaskAttachments, and UserMenu's keyboard-shortcuts item.
- Removed dead-end UI: Google OAuth stub buttons, UserMenu items
  pointing at non-existent routes, the /developer/docs dead link, and
  the no-op action button on the API Keys placeholder page.
- Removed leftover debug console logging across 8 files.

Added frontend_report.md (full audit) and frontend_tasks.md (phased
checklist) as the reference for this and future phases.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 04:47:26 +08:00
parent c63a71883b
commit cd2efe3587
25 changed files with 639 additions and 331 deletions
@@ -102,49 +102,31 @@ const tabs = computed<Tab[]>(() => [
// Determine active tab based on current route
const activeTab = computed(() => {
const currentPath = route.path;
// Debug logging
console.log('ProjectTabs - Current path:', currentPath);
console.log('ProjectTabs - Project ID:', props.projectId);
if (currentPath === `/projects/${props.projectId}`) {
console.log('ProjectTabs - Active tab: overview');
return "overview";
} else if (currentPath.startsWith(`/projects/${props.projectId}/shots`)) {
console.log('ProjectTabs - Active tab: shots');
return "shots";
} else if (currentPath.startsWith(`/projects/${props.projectId}/assets`)) {
console.log('ProjectTabs - Active tab: assets');
return "assets";
} else if (currentPath.startsWith(`/projects/${props.projectId}/tasks`)) {
console.log('ProjectTabs - Active tab: tasks');
return "tasks";
} else if (
currentPath.startsWith(`/projects/${props.projectId}/settings`)
) {
console.log('ProjectTabs - Active tab: settings');
return "settings";
}
console.log('ProjectTabs - Active tab: overview (default)');
return "overview";
});
// Set active tab and navigate
const setActiveTab = (tabId: string) => {
const tab = tabs.value.find((t) => t.id === tabId);
console.log('ProjectTabs - Setting active tab:', tabId);
console.log('ProjectTabs - Tab found:', tab);
console.log('ProjectTabs - Current route path:', route.path);
console.log('ProjectTabs - Target route:', tab?.route);
if (tab) {
console.log('ProjectTabs - Navigating to:', tab.route);
router.push(tab.route).catch(err => {
console.error('ProjectTabs - Navigation error:', err);
router.push(tab.route).catch(() => {
// Navigation aborted (e.g. duplicate route) — safe to ignore
});
} else {
console.log('ProjectTabs - Tab not found');
}
};