diff --git a/.planning/phases/10-ux-interaction/10-UAT.md b/.planning/phases/10-ux-interaction/10-UAT.md index 510db1c..5480170 100644 --- a/.planning/phases/10-ux-interaction/10-UAT.md +++ b/.planning/phases/10-ux-interaction/10-UAT.md @@ -1,5 +1,5 @@ --- -status: complete +status: diagnosed phase: 10-ux-interaction source: 10-01-SUMMARY.md, 10-02-SUMMARY.md, 10-03-SUMMARY.md, 10-04-SUMMARY.md, 10-06-SUMMARY.md, 10-07-SUMMARY.md, 10-08-SUMMARY.md, 10-09-SUMMARY.md, 10-10-SUMMARY.md, 10-11-SUMMARY.md, 10-12-SUMMARY.md started: 2026-06-16T00:00:00Z @@ -127,9 +127,12 @@ blocked: 0 reason: "User reported: Local storage too fast to see any loading. Nextcloud sidebar section does nothing until folder loads — no skeleton or feedback visible during load." severity: major test: 4 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "TreeItem.vue lines 48-52 render
Loading…
instead of animate-pulse shimmer rows. The loading state ref is tracked correctly but the visual treatment does not match the shimmer pattern used elsewhere in AppSidebar." + artifacts: + - path: "frontend/src/components/ui/TreeItem.vue" + issue: "v-if='loading' branch renders plain text instead of animated skeleton rows (lines 48-52)" + missing: + - "Replace plain Loading… div with 3 shimmer rows using animate-pulse pattern matching AppSidebar lines 60-64" debug_session: "" - truth: "Admin views show admin-specific layout (no user sidebar) with breadcrumb bar" @@ -137,9 +140,12 @@ blocked: 0 reason: "User reported: Admin views still show the normal user sidebar." severity: major test: 8 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "App.vue renders in a v-else branch with no admin exemption. When /admin/* routes render, Vue Router places AdminLayout.vue into but AppSidebar is outside it — unconditionally rendered for all non-auth routes. Both sidebars appear simultaneously." + artifacts: + - path: "frontend/src/App.vue" + issue: "v-else branch (lines 3-8) renders without checking route.meta.requiresAdmin" + missing: + - "Add third branch in App.vue: when route.matched.some(r => r.meta.requiresAdmin), render only with no AppSidebar" debug_session: "" - truth: "Pressing '/' while in the file manager (with search bar visible) focuses the search input" @@ -147,9 +153,14 @@ blocked: 0 reason: "User reported: pressing '/' does nothing when search bar is visible inside a folder." severity: major test: 11 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "Shared root cause with tests 12 and 13: ref='routeViewRef' on in App.vue resolves to the RouterView component proxy, not the FileManagerView instance. RouterView.setup() never calls expose(), so routeViewRef.value has no focusSearch/triggerUpload/startNewFolder properties. All calls silently no-op via optional chaining ?." + artifacts: + - path: "frontend/src/App.vue" + issue: "ref='routeViewRef' on (line 6); shortcut handlers use routeViewRef.value?.focusSearch?.() etc. (lines 37, 43, 46) which are unreachable" + - path: "frontend/src/views/FileManagerView.vue" + issue: "defineExpose({ focusSearch, triggerUpload, startNewFolder }) is correct (lines 190-196) but unreachable via routeViewRef" + missing: + - "Replace routeViewRef approach with router.currentRoute.value.matched[0].instances.default to reach actual FileManagerView instance, or use a Pinia store / event bus for keyboard action dispatch" debug_session: "" - truth: "Pressing 'U' while in the file manager opens the file-picker dialog" @@ -157,9 +168,12 @@ blocked: 0 reason: "User reported: pressing U does not open the file picker." severity: major test: 12 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "Same root cause as test 11: routeViewRef resolves to RouterView proxy, not FileManagerView. triggerUpload?.() is a no-op." + artifacts: + - path: "frontend/src/App.vue" + issue: "routeViewRef.value?.triggerUpload?.() (line 43) silently no-ops" + missing: + - "Fixed by the same routeViewRef fix as test 11" debug_session: "" - truth: "Pressing 'N' while in the file manager triggers the new-folder inline input" @@ -167,9 +181,12 @@ blocked: 0 reason: "User reported: pressing N does not trigger new folder input." severity: major test: 13 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "Same root cause as test 11: routeViewRef resolves to RouterView proxy, not FileManagerView. startNewFolder?.() is a no-op." + artifacts: + - path: "frontend/src/App.vue" + issue: "routeViewRef.value?.startNewFolder?.() (line 46) silently no-ops" + missing: + - "Fixed by the same routeViewRef fix as test 11" debug_session: "" - truth: "After pressing Escape to clear search, the search field remains functional for new queries" @@ -177,9 +194,14 @@ blocked: 0 reason: "User reported: field clears on Escape but search no longer works afterwards — cannot type a new query." severity: major test: 14 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "SearchBar.vue uses type='search' on the input (line 6) and handles @keydown.escape without .prevent. Browsers treat Escape on type='search' as native clear+blur — the field loses focus and the user cannot type without clicking first. Event also bubbles to App.vue global handler (no .stop) causing a redundant clearSearch call." + artifacts: + - path: "frontend/src/components/documents/SearchBar.vue" + issue: "@keydown.escape handler (line 11) lacks .prevent and .stop — browser native blur fires after Vue handler" + - path: "frontend/src/App.vue" + issue: "Global Escape handler (line 39) may fire redundantly after input blurs" + missing: + - "Change @keydown.escape to @keydown.escape.prevent.stop in SearchBar.vue to suppress native blur and prevent bubbling" debug_session: "" - truth: "Dropping a file from OS onto the drag overlay starts the upload" @@ -187,9 +209,14 @@ blocked: 0 reason: "User reported: overlay appears but dropping the file does not start the upload." severity: major test: 15 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "OsDragOverlay registers window 'drop' listener in bubble phase. StorageBrowser registers @drop.prevent on every folder row (line 79), which consumes the native drop event before it bubbles to window. OsDragOverlay has pointer-events-none so drops land on underlying DOM elements (folder rows) which intercept them first. The window listener never fires." + artifacts: + - path: "frontend/src/components/layout/OsDragOverlay.vue" + issue: "window.addEventListener('drop', this.onDrop) registered in bubble phase (line 56) — consumed by folder rows first" + - path: "frontend/src/components/storage/StorageBrowser.vue" + issue: "@drop.prevent on folder rows (line 79) intercepts OS drops; onDropDocOnFolder guard (line 364) exits early for OS drags (draggingFile is null)" + missing: + - "Register OsDragOverlay window listener in capture phase: window.addEventListener('drop', this.onDrop, true) so it runs before element-level handlers" debug_session: "" - truth: "Search bar and sorting controls are visible at the root level of the file manager and cloud file browser (currently hidden behind breadcrumb.length > 0 guard)" @@ -197,7 +224,10 @@ blocked: 0 reason: "User reported: search bar and sorting controls not visible at the root of the cloud and local file browser." severity: major test: 5 - root_cause: "" - artifacts: [] - missing: [] + root_cause: "StorageBrowser.vue line 287: showSearch computed is props.mode === 'local' && props.breadcrumb.length > 0. Both conditions must be true — breadcrumb is [] at root so showSearch is false there; cloud mode also always false because mode guard requires 'local'. SearchBar (line 12) and SortControls (line 14) both share v-if='showSearch' so both disappear." + artifacts: + - path: "frontend/src/components/storage/StorageBrowser.vue" + issue: "showSearch computed (line 287) has breadcrumb.length > 0 and mode === 'local' guards; both incorrect" + missing: + - "Change showSearch to computed(() => props.mode === 'local' || props.mode === 'cloud') — remove breadcrumb depth guard entirely" debug_session: ""