rows during loading"
- "AdminUsersView shows >=5 skeleton
rows during loading"
- "AdminAuditView empty state uses EmptyState icon=clipboardList with a Clear filters CTA"
- "SharedView empty state uses EmptyState icon=inbox"
- "CloudStorageView empty state uses EmptyState icon=cloud with a Settings router-link CTA"
- "Each admin view + SettingsView renders a BreadcrumbBar with the static segments per the wiring table (D-13)"
artifacts:
- path: "frontend/src/views/admin/AdminAuditView.vue"
provides: "Audit view with skeleton + EmptyState + BreadcrumbBar"
- path: "frontend/src/views/admin/AdminUsersView.vue"
provides: "Users view with skeleton + BreadcrumbBar"
- path: "frontend/src/views/SettingsView.vue"
provides: "Settings view with BreadcrumbBar reflecting active tab"
key_links:
- from: "Each admin view"
to: "BreadcrumbBar.vue"
via: "static segments computed"
pattern: "
Wire UX-04 (skeleton table rows in admin tables), the remaining UX-01 (EmptyState in SharedView, CloudStorageView, AdminAuditView), and the admin/settings parts of UX-12 (BreadcrumbBar static segments) across the admin views, SettingsView, SharedView, and CloudStorageView.
Per D-13: each view computes its own segments array. Admin/settings/topics views use `showRoot=false` so they do NOT show a "Home" button.
Output:
- AdminUsersView, AdminAuditView, AdminQuotasView, AdminAiView, AdminOverviewView: each gains a `` block at the top
- AdminUsersView + AdminAuditView: skeleton table rows replace loading spinner
- AdminAuditView empty state replaced with EmptyState
- SettingsView: BreadcrumbBar with `Settings > {activeTab}` static segments
- SharedView: EmptyState replaces inline empty div + BreadcrumbBar
- CloudStorageView: EmptyState replaces inline empty div with Settings #cta + BreadcrumbBar
- Two admin skeleton stub files promoted to real tests
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
@CLAUDE.md
@.planning/phases/10-ux-interaction/10-CONTEXT.md
@.planning/phases/10-ux-interaction/10-RESEARCH.md
@.planning/phases/10-ux-interaction/10-PATTERNS.md
@frontend/src/views/admin/AdminAuditView.vue
@frontend/src/views/admin/AdminUsersView.vue
@frontend/src/views/admin/AdminQuotasView.vue
@frontend/src/views/admin/AdminAiView.vue
@frontend/src/views/admin/AdminOverviewView.vue
@frontend/src/views/SettingsView.vue
@frontend/src/views/SharedView.vue
@frontend/src/views/CloudStorageView.vue
@frontend/src/components/ui/BreadcrumbBar.vue
@frontend/src/components/ui/EmptyState.vue
BreadcrumbBar per-view wiring table (from RESEARCH.md):
| View | segments | showRoot |
|------|----------|----------|
| AdminOverviewView | `[]` | false |
| AdminUsersView | `[{ label: 'Users' }]` | false |
| AdminQuotasView | `[{ label: 'Quotas' }]` | false |
| AdminAiView | `[{ label: 'AI Config' }]` | false |
| AdminAuditView | `[{ label: 'Audit Log' }]` | false |
| SettingsView | `[{ label: 'Settings' }, { label: activeTabLabel }]` | false |
| SharedView | `[{ label: 'Shared with me' }]` | false |
| CloudStorageView | `[{ label: 'Cloud Storage' }]` | false |
SettingsView active tab labels: map tab id to display label (existing tabs in SettingsView.vue - read the file to find the mapping; typical tabs: 'Account', 'Cloud Storage', 'Preferences').
Skeleton table row pattern (RESEARCH.md Pitfall 7 admin variant):
AdminAuditView (5 cols: Timestamp | User | Email | Action | IP) - 8 rows.
AdminUsersView (6 cols: Email | Handle | Role | Status | Created | Actions) - 5 rows.
Skeleton rows render inside the existing `` when loading. The existing loading spinner block is replaced.
EmptyState wiring (RESEARCH.md Component Inventory #3):
- AdminAuditView empty entries: `` with #cta button `Clear filters`
- SharedView empty shared docs: ``
- CloudStorageView empty connections: `` with #cta router-link to /settings
Task 1: Promote AdminAuditView + AdminUsersView skeleton test stubsfrontend/src/views/admin/__tests__/AdminAuditView.skeleton.test.js, frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js
- The two stub files (Wave 0 outputs)
- frontend/src/views/admin/AdminAuditView.vue + AdminUsersView.vue (current state)
Replace the `.todo` entries with real assertions:
AdminAuditView.skeleton.test.js (5 tests):
1. `renders 8 skeleton
rows when loading=true` - mount AdminAuditView with loading mocked to true, find `
` and assert findAll('tr').length >= 8
2. `skeleton rows have exactly 5
cells matching column count` - assert each skeleton row has 5 `
` children
3. `Loading audit log text is absent when loading=true` - assert wrapper.text() does NOT include 'Loading audit log'
4. `renders when entries empty and not loading` - assert EmptyState stub is found with those props
5. `EmptyState includes a Clear filters CTA button` - assert the rendered EmptyState slot contains 'Clear filters'
AdminUsersView.skeleton.test.js (3 tests):
1. `renders 5 skeleton
rows when loading=true` - assert >= 5
2. `skeleton rows have exactly 6
cells` - assert each row has 6 cells
3. `Loading users text is absent when loading=true` - assert wrapper.text() excludes 'Loading users'
Use setActivePinia(createPinia()) and override store state. Stub child components via global.stubs: { BreadcrumbBar: true, EmptyState: true, AppIcon: true }.
Replace `it.todo(...)` entries in both files with the real tests defined above. Tests fail until Task 2-3 update the views.
cd frontend && npm run test -- --run AdminAuditView.skeleton; cd frontend && npm run test -- --run AdminUsersView.skeleton
Expected: 5 + 3 = 8 tests RED.
- AdminAuditView.skeleton.test.js contains 5 real `it(...)` blocks (no `.todo`)
- AdminUsersView.skeleton.test.js contains 3 real `it(...)` blocks
- All 8 tests are RED before Task 2
8 RED skeleton tests in place.Task 2: Update AdminAuditView.vue and AdminUsersView.vuefrontend/src/views/admin/AdminAuditView.vue, frontend/src/views/admin/AdminUsersView.vue
- Both view files (current state - read in full to learn the loading block + table structure + filter state)
- The two failing test files from Task 1
- frontend/src/components/ui/BreadcrumbBar.vue
- frontend/src/components/ui/EmptyState.vue
- .planning/phases/10-ux-interaction/10-PATTERNS.md sections for AdminAuditView.vue and AdminUsersView.vue
AdminAuditView.vue changes:
1. Add imports: `import BreadcrumbBar from '../../components/ui/BreadcrumbBar.vue'` and `import EmptyState from '../../components/ui/EmptyState.vue'`. Register both in `components: { ... }` (Options API) or rely on import resolution (script setup).
2. At the very top of the `` root (before any existing content), add:
``
3. Replace the existing loading block (the `
......Loading audit log...
`) with skeleton table rows. The new structure: when `loading` is true, the `` renders 8 skeleton rows. When `entries.length === 0` and not loading, render the `` block. When entries exist, render the existing real rows. Concretely:
```
```
Remove the outer loading `
` panel that contained Loading audit log spinner.
4. If `clearFilters` does not already exist as a function/method, add one that resets the filter state to defaults (read the filter refs/data and set them back to their initial values).
AdminUsersView.vue changes:
1. Add `import BreadcrumbBar from '../../components/ui/BreadcrumbBar.vue'`. Register if Options API.
2. Add `` at the top of the template root.
3. Replace the existing loading spinner block with skeleton table rows: 5 rows x 6 `
` cells per row, classes per section.
Preserve all other functionality (filters, action buttons, sort, pagination, modals).
cd frontend && npm run test -- --run AdminAuditView.skeleton; cd frontend && npm run test -- --run AdminUsersView.skeleton
Expected: all 8 tests GREEN.
- `grep -E "BreadcrumbBar" frontend/src/views/admin/AdminAuditView.vue` returns >= 2 (import + usage)
- `grep -E "BreadcrumbBar" frontend/src/views/admin/AdminUsersView.vue` returns >= 2
- `grep -E "icon=\"clipboardList\"" frontend/src/views/admin/AdminAuditView.vue` returns 1
- `grep -E "animate-pulse" frontend/src/views/admin/AdminAuditView.vue` returns >= 5
- `grep -E "animate-pulse" frontend/src/views/admin/AdminUsersView.vue` returns >= 5
- `grep -v '^#' frontend/src/views/admin/AdminAuditView.vue | grep -c "Loading audit log"` returns 0
- `grep -v '^#' frontend/src/views/admin/AdminUsersView.vue | grep -c "Loading users"` returns 0
- Both skeleton tests pass
AuditView + UsersView updated; skeletons green; BreadcrumbBar in place.Task 3: BreadcrumbBar in remaining admin views + SettingsView; EmptyState in SharedView + CloudStorageView
frontend/src/views/admin/AdminQuotasView.vue,
frontend/src/views/admin/AdminAiView.vue,
frontend/src/views/admin/AdminOverviewView.vue,
frontend/src/views/SettingsView.vue,
frontend/src/views/SharedView.vue,
frontend/src/views/CloudStorageView.vue
- All six view files (current state)
- frontend/src/components/ui/BreadcrumbBar.vue + EmptyState.vue
- .planning/phases/10-ux-interaction/10-PATTERNS.md sections for SharedView and CloudStorageView (target EmptyState blocks)
AdminQuotasView.vue: Add `import BreadcrumbBar` (register if Options API). Add `` at top of template. No other changes.
AdminAiView.vue: Same pattern with segments `[{ label: 'AI Config' }]`.
AdminOverviewView.vue: Same pattern with `:segments="[]" :show-root="false"`. The empty segments block renders a `cd frontend && npm run test -- --run
Expected: full suite passes; no regression in any existing test.
- `grep -E "= 2 (computed + binding)
- `grep -E "All 6 views wired with BreadcrumbBar + EmptyState; full test suite green.
- `cd frontend && npm run test -- --run AdminAuditView.skeleton` exits 0
- `cd frontend && npm run test -- --run AdminUsersView.skeleton` exits 0
- `cd frontend && npm run test -- --run` (full suite) exits 0
- Every admin view + SettingsView + SharedView + CloudStorageView contains exactly one `
Every admin section + SettingsView shows a `Section name` breadcrumb at the top with no "Home" prefix. AdminAuditView + AdminUsersView display animated skeleton tables during load. AdminAuditView's "no entries" state renders the EmptyState with a Clear filters button. SharedView and CloudStorageView render proper EmptyState components with appropriate icons (inbox / cloud) and Settings link where applicable.