From ec0c69fb4ef4b3d2127518ed16d0945a319e8172 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Fri, 29 May 2026 08:18:48 +0200 Subject: [PATCH] =?UTF-8?q?docs(05-07):=20complete=20cloud=20storage=20fro?= =?UTF-8?q?ntend=20UI=20plan=20=E2=80=94=20SUMMARY=20and=20STATE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .planning/STATE.md | 15 +- .../05-07-SUMMARY.md | 177 ++++++++++++++++++ 2 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 .planning/phases/05-cloud-storage-backends/05-07-SUMMARY.md diff --git a/.planning/STATE.md b/.planning/STATE.md index e8c5876..d7035ca 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -9,8 +9,8 @@ progress: total_phases: 5 completed_phases: 4 total_plans: 32 - completed_plans: 31 - percent: 90 + completed_plans: 32 + percent: 94 --- # Project State @@ -28,13 +28,13 @@ progress: | 2 | Users & Authentication | ✓ Complete (5/5 plans) | | 3 | Document Migration & Multi-User Isolation | ✓ Complete (5/5 plans, UAT passed, security gate passed) | | 4 | Folders, Sharing, Quotas & Document UX | ✓ Complete (9/9 plans, UAT 14/15 passed, 1 bug fixed) | -| 5 | Cloud Storage Backends | In Progress (6/8 plans complete) | +| 5 | Cloud Storage Backends | In Progress (7/8 plans complete) | ## Current Position **Phase:** 05-cloud-storage-backends — In Progress -**Plan:** 6/8 -**Progress:** [█████████░] 90% +**Plan:** 7/8 +**Progress:** [█████████░] 94% ## Performance Metrics @@ -183,6 +183,7 @@ _Updated at each phase transition._ | Last session | 2026-05-28 — Plan 05-04 executed: WebDAVBackend + NextcloudBackend (SSRF double-guard, asyncio.to_thread, list_folder); 262 passed / 43 xfailed / 1 pre-existing failure | | Last session | 2026-05-29 — Plan 05-05 executed: cloud.py (7 endpoints), main.py (routers registered), admin.py (SEC-09 cloud cleanup); 262 passed / 43 xfailed / 1 pre-existing failure | | Last session | 2026-05-29 — Plan 05-06 executed: documents.py cloud upload+content-proxy extension; all 15 xfail stubs promoted to 20 passing tests (CLOUD-03, CLOUD-05, CLOUD-07); 282 passed / 24 xfailed / 1 pre-existing failure | -| Next action | Execute Plan 05-07: Cloud Frontend Integration | +| Last session | 2026-05-29 — Plan 05-07 executed: useCloudConnectionsStore, 3-tab SettingsView, SettingsCloudTab (4 providers, status badges, OAuth callback), CloudCredentialModal; 61 tests passing, build exits 0 | +| Next action | Execute Plan 05-08: AppSidebar cloud tree nodes | | Pending decisions | None | -| Resume file | `.planning/phases/05-cloud-storage-backends/05-07-PLAN.md` | +| Resume file | `.planning/phases/05-cloud-storage-backends/05-08-PLAN.md` | diff --git a/.planning/phases/05-cloud-storage-backends/05-07-SUMMARY.md b/.planning/phases/05-cloud-storage-backends/05-07-SUMMARY.md new file mode 100644 index 0000000..c9e6b74 --- /dev/null +++ b/.planning/phases/05-cloud-storage-backends/05-07-SUMMARY.md @@ -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*