docs(05-07): complete cloud storage frontend UI plan — SUMMARY and STATE
- useCloudConnectionsStore, 3-tab SettingsView, SettingsCloudTab, CloudCredentialModal - 61 Vitest tests passing, Vite build exits 0 - Fixed pre-existing build failure (top-level await) via build.target=esnext
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
---
|
||||
phase: 05-cloud-storage-backends
|
||||
plan: 07
|
||||
subsystem: ui
|
||||
tags: [cloud-storage, vue3, pinia, vitest, settings, webdav, oauth, tailwind]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 05-cloud-storage-backends
|
||||
plan: 06
|
||||
provides: "backend/api/cloud.py with all 7 endpoints (list, disconnect, OAuth initiate/callback, WebDAV connect, status update) — consumed by frontend API client"
|
||||
|
||||
provides:
|
||||
- "frontend/src/stores/cloudConnections.js: useCloudConnectionsStore with connections/loading/error state and fetchConnections, disconnect, disconnectAll actions"
|
||||
- "frontend/src/api/client.js: listCloudConnections, disconnectCloud, connectWebDav, updateDefaultStorage API functions"
|
||||
- "frontend/src/views/SettingsView.vue: 3-tab layout (Preferences/AI Configuration/Cloud Storage) with OAuth callback handling and success/error toast"
|
||||
- "frontend/src/components/settings/SettingsCloudTab.vue: all 4 provider rows with status badges, action buttons, REQUIRES_REAUTH banner, disconnect-all"
|
||||
- "frontend/src/components/cloud/CloudCredentialModal.vue: WebDAV/Nextcloud credential modal with authMethod radio toggle"
|
||||
- "frontend/src/components/settings/SettingsPreferencesTab.vue and SettingsAiTab.vue: extracted from original SettingsView"
|
||||
affects: [05-08]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Pinia composition API store pattern: defineStore with ref() state, async actions — matches existing folders.js pattern"
|
||||
- "vi.mock for Pinia store in component tests: mock the store module directly (no @pinia/testing) — same approach as folders.test.js"
|
||||
- "OAuth callback via URL query params: window.location.search parsed in onMounted; router.replace cleans params after read"
|
||||
- "OAuth initiation via window.location.href redirect: no fetch call needed — FastAPI handles the OAuth code exchange"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- frontend/src/stores/cloudConnections.js
|
||||
- frontend/src/stores/__tests__/cloudConnections.test.js
|
||||
- frontend/src/components/settings/SettingsPreferencesTab.vue
|
||||
- frontend/src/components/settings/SettingsAiTab.vue
|
||||
- frontend/src/components/settings/SettingsCloudTab.vue
|
||||
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
|
||||
- frontend/src/components/cloud/CloudCredentialModal.vue
|
||||
modified:
|
||||
- frontend/src/api/client.js
|
||||
- frontend/src/views/SettingsView.vue
|
||||
- frontend/package.json
|
||||
- frontend/vite.config.js
|
||||
|
||||
key-decisions:
|
||||
- "Used vi.mock for store in component tests instead of @pinia/testing (not installed, not in package.json). Mock returns a plain object matching the store's public API — avoids dependency on @pinia/testing while satisfying CLAUDE.md testing requirement (W4)"
|
||||
- "Fixed pre-existing Vite build failure (top-level await in main.js) by adding build.target='esnext' to vite.config.js — esnext natively supports top-level await, cleanest fix with no code changes needed"
|
||||
- "REQUIRES_REAUTH row renders both Reconnect and Remove buttons per UI-SPEC Surface 2; Remove button triggers same ConfirmBlock pattern as ACTIVE/ERROR rows"
|
||||
|
||||
patterns-established:
|
||||
- "Cloud provider row pattern: 4 providers always shown; connectionFor(providerKey) returns store connection or null; status badge + action button vary by status"
|
||||
- "Inline ConfirmBlock: confirmRemoveId ref tracks which row is in confirm mode; v-if/v-else renders either the action button or ConfirmBlock inline"
|
||||
- "SettingsView OAuth callback: onMounted reads URLSearchParams, sets activeTab='cloud', router.replace clears params, success auto-dismisses via setTimeout(5000)"
|
||||
|
||||
requirements-completed:
|
||||
- CLOUD-01
|
||||
- CLOUD-03
|
||||
- CLOUD-04
|
||||
- CLOUD-05
|
||||
- CLOUD-06
|
||||
|
||||
# Metrics
|
||||
duration: 14min
|
||||
completed: 2026-05-29
|
||||
---
|
||||
|
||||
# Phase 5 Plan 07: Cloud Storage Frontend UI Summary
|
||||
|
||||
**Pinia cloudConnections store, 3-tab SettingsView with OAuth callback handling, SettingsCloudTab with 4 provider rows and status badges, and CloudCredentialModal for WebDAV/Nextcloud credential input**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 14 min
|
||||
- **Started:** 2026-05-29T06:01:00Z
|
||||
- **Completed:** 2026-05-29T06:15:23Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 11
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Created `useCloudConnectionsStore` Pinia store with `connections`, `loading`, `error` state and `fetchConnections()`, `disconnect(id)`, `disconnectAll()` actions — follows same composition API pattern as `useFoldersStore`
|
||||
- Added 4 cloud API functions to `frontend/src/api/client.js`: `listCloudConnections`, `disconnectCloud`, `connectWebDav`, `updateDefaultStorage`
|
||||
- Rewrote `SettingsView.vue` to a 3-tab layout (Preferences / AI Configuration / Cloud Storage) mirroring `AdminView.vue` tab strip verbatim; `onMounted` reads `?cloud_connected=` and `?cloud_error=` query params and shows toast/banner accordingly
|
||||
- Built `SettingsCloudTab.vue` showing all 4 providers (Google Drive, OneDrive, Nextcloud, WebDAV server) with inline status badges, per-status action buttons, `REQUIRES_REAUTH` yellow banner, inline `ConfirmBlock` for remove confirmation, and "Disconnect all" action
|
||||
- Built `CloudCredentialModal.vue` with server URL, username, `authMethod` radio (app_password / account_password), and password fields; escape/overlay-click dismiss; spinner during save
|
||||
- Extracted `SettingsPreferencesTab.vue` and `SettingsAiTab.vue` from the original flat `SettingsView`
|
||||
|
||||
## Task Commits
|
||||
|
||||
1. **Task 1: cloudConnections store + API client** - `612d542` (feat)
|
||||
2. **Task 2: 3-tab SettingsView + all components** - `63a6829` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `frontend/src/stores/cloudConnections.js` — Pinia store for cloud connections state
|
||||
- `frontend/src/stores/__tests__/cloudConnections.test.js` — 4 Vitest unit tests (W4)
|
||||
- `frontend/src/api/client.js` — Added cloud storage section (listCloudConnections, disconnectCloud, connectWebDav, updateDefaultStorage)
|
||||
- `frontend/src/views/SettingsView.vue` — Rewritten as 3-tab layout with OAuth callback handling
|
||||
- `frontend/src/components/settings/SettingsPreferencesTab.vue` — Extracted from SettingsView
|
||||
- `frontend/src/components/settings/SettingsAiTab.vue` — Extracted from SettingsView
|
||||
- `frontend/src/components/settings/SettingsCloudTab.vue` — Provider card list with status badges, action buttons, modals
|
||||
- `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js` — 2 mount tests (W4)
|
||||
- `frontend/src/components/cloud/CloudCredentialModal.vue` — WebDAV/Nextcloud credential modal
|
||||
- `frontend/package.json` — Added `"test": "vitest run"` script
|
||||
- `frontend/vite.config.js` — Added `build.target: 'esnext'` to fix pre-existing top-level await build failure
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- `@pinia/testing` is not installed and not in `package.json`. Used `vi.mock('../../../stores/cloudConnections.js', ...)` to mock the store in `SettingsCloudTab.test.js` — same approach as `folders.test.js` uses `vi.mock` for the API. No dependency installation needed.
|
||||
- Pre-existing `npm run build` failure (top-level `await router.isReady()` in `main.js` incompatible with default esbuild targets). Fix: `build.target = 'esnext'` in `vite.config.js` — esnext natively supports module-level await. Zero code change to `main.js`.
|
||||
- OAuth initiation for Google Drive and OneDrive uses `window.location.href = /api/cloud/oauth/initiate/{provider}` — no fetch call — matching the backend FastAPI `RedirectResponse` pattern.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Fixed pre-existing Vite build failure (top-level await)**
|
||||
- **Found during:** Task 2 verification (`npm run build`)
|
||||
- **Issue:** `main.js` uses `await router.isReady()` at module top-level, which esbuild's default target (`chrome87`/`es2020`) does not support. This caused every build to fail with "Top-level await is not available in the configured target environment".
|
||||
- **Fix:** Added `build: { target: 'esnext' }` to `frontend/vite.config.js`. No code changes to `main.js` required.
|
||||
- **Files modified:** `frontend/vite.config.js`
|
||||
- **Verification:** `npm run build` exits 0, bundle output 185 kB.
|
||||
- **Committed in:** `63a6829` (Task 2 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (Rule 1 — pre-existing bug)
|
||||
**Impact on plan:** Fix was required for the plan's success criteria (`npm run build` exits 0). No scope creep.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- `@pinia/testing` package is not installed — the plan's `SettingsCloudTab.test.js` spec used `createTestingPinia` from it. Resolved by using `vi.mock` on the store module (the same pattern already established in `folders.test.js`). No package install required.
|
||||
- `npm run test` script did not exist in `package.json` — the plan required running tests via `npm run test`. Added `"test": "vitest run"` to the scripts block.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None. All 4 provider rows are wired to the live `useCloudConnectionsStore` — `fetchConnections()` is called in `onMounted`. The "Not connected" state is the correct zero-state display (per UI-SPEC: "all 4 providers always shown").
|
||||
|
||||
## Threat Surface Scan
|
||||
|
||||
No new network endpoints introduced. Client-side changes only.
|
||||
|
||||
| Flag | File | Description |
|
||||
|------|------|-------------|
|
||||
| T-05-07-02 mitigated | `SettingsView.vue` | `?cloud_error=` decoded via `decodeURIComponent` and displayed via `{{ oauthError }}` template binding — Vue auto-escaping prevents HTML injection |
|
||||
| T-05-07-03 accepted | `CloudCredentialModal.vue` | Password lives in `ref('')` only during modal interaction; `close()` is called on `@connected` which unmounts the form; `watch(props.show)` resets all refs to empty on reopen |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- All frontend cloud storage management UI is complete and building.
|
||||
- 61 Vitest tests pass (4 new store tests + 2 new component tests + 55 pre-existing).
|
||||
- Plan 05-08 can proceed: AppSidebar cloud tree nodes (`CloudProviderTreeItem`, `CloudFolderTreeItem`) depend on `useCloudConnectionsStore` (now available).
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
Files verified present:
|
||||
- `frontend/src/stores/cloudConnections.js`: FOUND (1045 chars)
|
||||
- `frontend/src/stores/__tests__/cloudConnections.test.js`: FOUND (2129 chars)
|
||||
- `frontend/src/api/client.js`: FOUND (with listCloudConnections, disconnectCloud, connectWebDav, updateDefaultStorage)
|
||||
- `frontend/src/views/SettingsView.vue`: FOUND (with activeTab, oauthSuccessProvider, oauthError, SettingsPreferencesTab, SettingsCloudTab)
|
||||
- `frontend/src/components/settings/SettingsPreferencesTab.vue`: FOUND
|
||||
- `frontend/src/components/settings/SettingsAiTab.vue`: FOUND
|
||||
- `frontend/src/components/settings/SettingsCloudTab.vue`: FOUND (with google_drive, onedrive, nextcloud, webdav, CloudCredentialModal, useCloudConnectionsStore)
|
||||
- `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js`: FOUND
|
||||
- `frontend/src/components/cloud/CloudCredentialModal.vue`: FOUND (with authMethod)
|
||||
|
||||
Commits verified:
|
||||
- `612d542`: feat(05-07): cloud connections Pinia store + API client functions — FOUND
|
||||
- `63a6829`: feat(05-07): 3-tab SettingsView, SettingsCloudTab, CloudCredentialModal — FOUND
|
||||
|
||||
Test verification: `npm run test` → 61 passed, 0 failed
|
||||
Build verification: `npm run build` → exit 0, 185 kB bundle
|
||||
|
||||
---
|
||||
*Phase: 05-cloud-storage-backends*
|
||||
*Completed: 2026-05-29*
|
||||
Reference in New Issue
Block a user