Files
curo1305 ec0c69fb4e 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
2026-05-29 08:18:48 +02:00

11 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
05-cloud-storage-backends 07 ui
cloud-storage
vue3
pinia
vitest
settings
webdav
oauth
tailwind
phase plan provides
05-cloud-storage-backends 06 backend/api/cloud.py with all 7 endpoints (list, disconnect, OAuth initiate/callback, WebDAV connect, status update) — consumed by frontend API client
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
05-08
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
created modified
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
frontend/src/api/client.js
frontend/src/views/SettingsView.vue
frontend/package.json
frontend/vite.config.js
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
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)
CLOUD-01
CLOUD-03
CLOUD-04
CLOUD-05
CLOUD-06
14min 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 useCloudConnectionsStorefetchConnections() 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