Files
kite/.planning/milestones/v0.2-phases/10-ux-interaction/10-08-PLAN.md
T
curo1305andClaude Sonnet 4.6 123ae5b29b chore: archive v0.2 phase directories to milestones/v0.2-phases/
Moves phases 08–11 execution artifacts from .planning/phases/ to
.planning/milestones/v0.2-phases/ to keep .planning/phases/ clean
for the next milestone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 14:34:52 +02:00

17 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
10-ux-interaction 08 execute 1
10-02
10-03
10-05
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/views/admin/__tests__/AdminAuditView.skeleton.test.js
frontend/src/views/admin/__tests__/AdminUsersView.skeleton.test.js
true
UX-04
UX-01
UX-12
truths artifacts key_links
AdminAuditView shows >=5 skeleton <tr> rows during loading
AdminUsersView shows >=5 skeleton <tr> 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)
path provides
frontend/src/views/admin/AdminAuditView.vue Audit view with skeleton + EmptyState + BreadcrumbBar
path provides
frontend/src/views/admin/AdminUsersView.vue Users view with skeleton + BreadcrumbBar
path provides
frontend/src/views/SettingsView.vue Settings view with BreadcrumbBar reflecting active tab
from to via pattern
Each admin view BreadcrumbBar.vue static segments computed <BreadcrumbBar
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 <BreadcrumbBar> 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

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@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 <tbody> when loading. The existing loading spinner block is replaced.

EmptyState wiring (RESEARCH.md Component Inventory #3):

  • AdminAuditView empty entries: <EmptyState icon="clipboardList" headline="No entries found" subtext="Try adjusting your filters or date range."> with #cta button Clear filters
  • SharedView empty shared docs: <EmptyState icon="inbox" headline="Nothing shared with you yet" subtext="When someone shares a document with you, it will appear here." />
  • CloudStorageView empty connections: <EmptyState icon="cloud" headline="No cloud storage connected" subtext="Connect Google Drive, OneDrive, Nextcloud, or a WebDAV server in Settings."> with #cta router-link to /settings
Task 1: Promote AdminAuditView + AdminUsersView skeleton test stubs frontend/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 <tr> rows when loading=true` - mount AdminAuditView with loading mocked to true, find `<tbody>` and assert findAll('tr').length >= 8
2. `skeleton rows have exactly 5 <td> cells matching column count` - assert each skeleton row has 5 `<td>` children
3. `Loading audit log text is absent when loading=true` - assert wrapper.text() does NOT include 'Loading audit log'
4. `renders <EmptyState icon="clipboardList" headline="No entries found"> 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 <tr> rows when loading=true` - assert >= 5
2. `skeleton rows have exactly 6 <td> 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.vue frontend/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: ```
Clear filters ``` 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 `<BreadcrumbBar :segments="[{ label: 'Users' }]" :show-root="false" class="mb-4" />` at the top of the template root.
3. Replace the existing loading spinner block with skeleton table rows: 5 rows x 6 `<td>` cells per row, classes per <interfaces> 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 `<nav>` with empty `<ol>` - acceptable. Alternatively keep the existing page heading and skip BreadcrumbBar if it would visually duplicate. Read the file: if there is already a clear `<h1>Admin Overview</h1>` heading, skip; otherwise add the BreadcrumbBar.

SettingsView.vue:
Read the file to find the `activeTab` state and its display labels. Add a computed `breadcrumbSegments` that returns `[{ label: 'Settings' }, { label: activeTabLabel }]` where `activeTabLabel` maps the current tab id to its user-facing label. Add `<BreadcrumbBar :segments="breadcrumbSegments" :show-root="false" class="mb-4" />` at the top of the template root.

SharedView.vue:
Add `import EmptyState from '../components/ui/EmptyState.vue'` and `import BreadcrumbBar from '../components/ui/BreadcrumbBar.vue'`. Register if Options API. At top of template add `<BreadcrumbBar :segments="[{ label: 'Shared with me' }]" :show-root="false" class="mb-4" />`. Replace the inline empty `<div v-else-if="sharedDocs.length === 0" class="text-center py-12 text-gray-400">...</div>` with:
```
<EmptyState
  v-else-if="sharedDocs.length === 0"
  icon="inbox"
  headline="Nothing shared with you yet"
  subtext="When someone shares a document with you, it will appear here."
/>
```

CloudStorageView.vue:
Add `import EmptyState` + `BreadcrumbBar`. Register if Options API. At top of template add `<BreadcrumbBar :segments="[{ label: 'Cloud Storage' }]" :show-root="false" class="mb-4" />`. Replace the inline empty div with:
```
<EmptyState
  v-else-if="connections.length === 0"
  icon="cloud"
  headline="No cloud storage connected"
  subtext="Connect Google Drive, OneDrive, Nextcloud, or a WebDAV server in Settings."
>
  <template #cta>
    <router-link to="/settings" class="mt-3 inline-block text-sm text-indigo-600 hover:underline">
      Go to Settings
    </router-link>
  </template>
</EmptyState>
```

All six files: preserve existing functionality untouched aside from the additions above.
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 `

<success_criteria> 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. </success_criteria>

Create `.planning/phases/10-ux-interaction/10-08-SUMMARY.md` when done.