Commit Graph
58 Commits
Author SHA1 Message Date
curo1305 04e6ea2ba2 feat(14-07): extend StorageBrowser and CloudFolderView with analysis UX (Task 2)
StorageBrowser:
- Add analyze-file button per cloud file row (D-01); placed inside name cell
  to avoid interfering with capability-gated file-row-actions (Rule 1 compliance)
- Add file-select checkboxes for multi-select analysis (cloud mode only)
- Add analyze-selection toolbar button (D-01, ANALYZE-02)
- Add analyze-folder toolbar button when breadcrumb is non-empty (D-01)
- Add analyze-connection toolbar button when connectionRoot is set (D-01, ANALYZE-03)
- Add analysisEstimate prop + analysis-estimate-modal (D-03) with estimate-start button
- Add analysisQueue prop + analysis-aggregate-progress with simplified/detailed labels (D-05/D-06)
- Add expandable per-item list via analysis-queue-expand toggle (D-05)
- Add per-item cancel/retry/skip controls in expanded list (D-09, ANALYZE-05)
- Add Cancel all batch button (D-09, ANALYZE-05)
- Emit: analyze-file, analyze-selection, analyze-folder, analyze-connection,
  analysis-confirmed, analysis-cancelled, analysis-item-cancel/retry/skip, analysis-cancel-all

CloudFolderView:
- Pass analysis props to StorageBrowser from cloudStore
- Add analysis estimate, pending request state
- Handle all analysis emits: onAnalyzeFile, onAnalyzeSelection, onAnalyzeFolder,
  onAnalyzeConnection, onAnalysisConfirmed, onAnalysisItemCancel/Retry/Skip, onAnalysisCancelAll
- Routes all API calls through cloudStore (requestEstimate, enqueueAnalysis, etc.)
2026-06-23 19:42:53 +02:00
curo1305 b84b912acf test(14-06): add cache transparency assertion to frontend open/preview tests
- Add cache_backed_response_has_no_object_key describe block to CloudFolderOpenPreview.test.js
- Verifies openCloudFile response processed by CloudFolderView never exposes object_key, MinIO paths, or credentials_enc in rendered HTML or API call arguments (T-14-02)
- All 9 tests pass (8 pre-existing + 1 new)
2026-06-23 16:29:11 +02:00
curo1305 a7e55d1bb0 feat(13-10): reactive mock store in rendered-flow test surfaces health banner and no-probe assertions
- CloudFolderRenderedFlow.test.js: mock store uses Vue refs so folderFreshness propagates
  reactively to StorageBrowser via CloudFolderView's template binding (D-12 GREEN)
- setBrowseState in mock now updates _mockFolderFreshness so cloud-health-banner appears
  when API returns warning freshness (T-13-30 mitigated)
- Added testCloudConnection to API mock so D-13 no-probe assertion can verify it was not called
- beforeEach resets reactive refs for test isolation
- 11 rendered-flow tests pass; 70 total across health/store/view/rendered-flow suites
2026-06-22 23:56:13 +02:00
curo1305 60afb028bf feat(13-10): store-backed health mapping, reconnect UX, no-probe-on-navigation, and Google Drive consent copy
- D-12: connectionHealth ref as single source for browser compact status and Settings diagnostics
- D-13: handleHealthFailure schedules pendingHealthRetest; navigation never triggers probe
- D-13: testConnection method in store (explicit action only, not navigation side-effect)
- D-14: markReconnecting preserves cached browseItems as stale; markReconnectRefreshPending flag
- D-15: degraded vs requires_reauth health states distinguished in store vocabulary
- D-17: Google Drive scope notice in SettingsCloudTab for all connect/reconnect paths
- StorageBrowser: cloud-health-banner (warning/stale) and requires-reauth prompt with reconnect action
- 59 tests passing: store, Settings, and CloudFolderView health/reconnect suites
2026-06-22 23:55:58 +02:00
curo1305 3351e63458 feat(13-07): wire binary-only preview and authorized download through shared actions
- CloudFolderView: onFileOpen calls openCloudFile(connectionId, provider_item_id, file) — never window.open()
- CloudFolderView: D-18 fallback calls downloadCloudFile for unsupported formats
- api/cloud.js: add openCloudFile optional fileContext param (third argument) for test matching
- api/cloud.js: add downloadCloudFile authorized download endpoint helper
- CloudFolderOpenPreview.test.js: fix makeBrowserStub missing name (findComponent by name)
- All 8 preview suite tests pass — binary-only preview + authorized fallback download
2026-06-22 19:42:48 +02:00
curo1305 e7e62bbab8 feat(13-07): implement sequential cloud upload queue with typed pause/resume
- StorageBrowser: add conflict dialog (D-03) and error dialog (D-04) for paused queue states
- StorageBrowser: add upload-queue-resolve emit for Keep both / Replace / Skip / Retry / Cancel all actions
- StorageBrowser: add upload-queue-list with upload-queue-item rows for remaining queued items
- StorageBrowser: suppress UploadProgress in cloud mode (replaced by queue dialogs)
- CloudFolderView: replace placeholder onFilesSelected with sequential queue runner
- CloudFolderView: handle upload-queue-resolve events for all conflict/error resolution actions
- api/cloud.js: add conflictAction param to uploadCloudFile for keep_both/replace paths
- api/cloud.js: add downloadCloudFile authorized fallback helper
- CloudFolderView.test.js: fix CapturingStub missing name, add uploadCloudFile mock
- All 34 queue and thin-view tests pass (StorageBrowser.cloud-queue + CloudFolderView)
2026-06-22 19:42:29 +02:00
curo1305 8923ed5b3c test(13-02): add red store, health-flow, reconnect, and no-probe tests
- SettingsCloudTab.health.test.js: Test/Reconnect/Disconnect per-connection actions,
  explicit confirmation before credential removal, Google Drive broader scope consent
  copy (D-12/D-13/D-15/D-16/D-17/T-13-09)
- cloudConnections.test.js: connectionHealth state map, setConnectionHealth translation,
  degraded vs requires_reauth distinction, pendingHealthRetest after failure, reconnect
  preserves cached items, auto-test after connect, no-probe-on-navigation (D-12..D-15)
- CloudFolderRenderedFlow.test.js: warning+reconnect banner alongside cached items,
  requires_reauth renders actionable prompt, folder-navigate never triggers health probe
  (D-12/D-13/D-14/CONN-02/T-13-06)
2026-06-22 18:13:39 +02:00
curo1305 514925bd4c test(13-02): add red shared-browser queue/preview and thin-view tests
- StorageBrowser.cloud-queue.test.js: sequential upload queue, paused_conflict
  dialog (Keep both/Replace/Skip/Cancel all), paused_error dialog (Retry/Skip/
  Cancel all), backend-typed conflict/error bodies, no window.open() (D-01/D-03/D-04)
- CloudFolderOpenPreview.test.js: authorized file-open via API, no raw provider
  URLs, Office/Workspace authorized download fallback, no anchor-click download
  hack, no re-emitted file-open to router (D-02/D-18/T-13-07)
- CloudFolderView.test.js: extends thin-view invariants for Phase 13 queue prop
  forwarding and upload-event queue semantics (D-01/D-04)
2026-06-22 18:10:16 +02:00
curo1305 64ddb50cd6 fix(cloud): show provider root items in browser 2026-06-22 13:55:07 +02:00
curo1305 6d294ea7e6 test(12.1): add rendered-flow integration tests and security gate evidence
- Add CloudFolderRenderedFlow.test.js: 7 tests mounting real CloudFolderView
  with real StorageBrowser/BreadcrumbBar (only API and router stubbed)
  — mixed root render, opaque-ref folder navigation, breadcrumb lineage,
    warning freshness cached rows, fresh freshness, XSS text escaping
- Update 12.1-VALIDATION.md with Task 3 security gate results:
  bandit 0 HIGH, npm audit 0 critical, no Phase-12.1 gitleaks findings,
  595 backend / 376 frontend tests pass, build clean
2026-06-22 09:41:36 +02:00
curo1305 dc3e1725da feat(12.1-03): align cloud browser contract — kind, provider_item_id, server freshness
- CloudFolderView: folders/files classified by kind=folder/file (remove is_dir)
- CloudFolderView: navigateTo uses item.provider_item_id for route param (not item.id)
- CloudFolderView: handleBreadcrumbNavigate uses named route; opaque refs intact
- CloudFolderView: setBrowseState maps server freshness.refresh_state verbatim
- CloudFolderView: refreshedAt = server last_refreshed_at (not new Date())
- CloudFolderView: breadcrumb lineage built explicitly from visited nodes
- CloudProviderTreeItem: loadChildren filters by kind=folder (not is_dir)
- CloudFolderTreeItem: expandable = kind===folder; icon = kind===folder
- CloudFolderTreeItem: navigate() uses provider_item_id (not folder.id)
- CloudFolderTreeItem: loadChildren uses provider_item_id as parent_ref
- CloudFolderTreeItem: isActive checks provider_item_id first
All 82 focused tests pass; full suite: 369/369
2026-06-22 08:49:19 +02:00
curo1305 9974fca2cb test(12.1-03): add RED tests for server freshness mapping
- cloudConnections: setBrowseState warning/refreshing/fresh states
- cloudConnections: cached items remain during warning
- cloudConnections: selectConnection clears browse state
- cloudConnections: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: maps_server_warning_and_last_success
- CloudFolderView: http_200_does_not_imply_fresh
- CloudFolderView: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: cached_items_remain_visible_during_warning
3 new failures against unconditional fresh/new Date() behavior
2026-06-22 08:45:50 +02:00
curo1305 ba7f652cde test(12.1-03): add RED tests for kind/provider_item_id/freshness regressions
- CloudFolderView: renders_kind_folder_and_file_in_shared_browser (is_dir → kind)
- CloudFolderView: folder_click_uses_provider_item_id_not_id
- CloudFolderView: stable_docuvault_id_remains_row_key
- CloudFolderView: opaque_reference_round_trip (reserved chars)
- CloudFolderTreeItem: nested_tree_uses_provider_item_id (navigation + loadChildren)
- CloudFolderTreeItem: expandable based on kind=folder, not is_dir
- CloudFolderTreeItem: opaque OneDrive ref used intact
- CloudProviderTreeItem: tree_expansion_filters_kind_folder
- StorageBrowser: cloud folder/file rendering with normalized items
- CloudBreadcrumbNavigation: explicit lineage tests (pass against current code)
9 tests fail against is_dir/item.id behavior as expected
2026-06-22 08:44:27 +02:00
curo1305 bf9af11274 feat(12-03): connection-ID routing, rename, session folder memory, thin views
- Route /cloud/:connectionId/:folderId replaces /cloud/:provider/:folderId
- api/cloud.js: getCloudFoldersByConnectionId + renameCloudConnection
- cloudConnections store: rename, selectConnection, setBrowseState, defaultDisplayName, session storage helpers
- CloudStorageView: thin — passes connectionRoots to StorageBrowser
- CloudFolderView: thin — uses connectionId param, never provider slug
- SettingsCloudTab: inline rename input for each active connection
- 27 tests pass: store, view, settings
2026-06-18 23:25:29 +02:00
curo1305 a8e0a199f2 chore(11-06): delete orphaned AccountView.vue
- AccountView.vue had no active route component reference
- /account path uses redirect: '/settings' with no component import
- No imports found across the entire codebase
- Satisfies CODE-07: no unreferenced route views remain
2026-06-17 00:39:05 +02:00
curo1305 2af5b7c313 feat(11-05): visual consistency pass — typography, focus-visible, hover/active states, skeleton cleanup
- Normalize page titles to text-2xl font-semibold (was font-bold in TopicsView, DocumentView, SharedView)
- Normalize section titles to text-lg font-semibold (was text-xl in SettingsPreferencesTab, SettingsAiTab, SettingsCloudTab, BackupCodesDisplay, CloudCredentialModal)
- Normalize panel headings to text-sm font-semibold (SettingsAccountTab, DocumentView)
- Normalize AdminOverviewView page title from text-xl to text-2xl font-semibold
- Replace decorative sidebar skeleton inline styles with static Tailwind width classes (w-12/w-16/w-20)
- Add focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-1 to all interactive buttons across the app
- Add active:bg-* states to primary and secondary buttons for coherent press feedback
- Update nav-link scoped CSS in AppSidebar and AdminSidebar to include active:bg-gray-200 and focus-visible ring
- Add 7 new tests: VISUAL-01 skeleton class invariant, VISUAL-04 focus-visible invariant, VISUAL-03 typography invariant (36 test files, 270 tests pass)
2026-06-16 21:48:56 +02:00
curo1305 df53cef3b7 feat(11-04): mobile-safe modals and form baseline verification
- Add max-h-[90vh] overflow-y-auto to ShareModal, CloudCredentialModal,
  FolderDeleteModal, and DocumentView cloud-delete modal panels
- Add responsive px-4 sm:px-6 to DocumentPreviewModal header for narrow viewports
- Add data-test attributes to all modal panels for testability
- Confirm @tailwindcss/forms active in tailwind.config.js (no drift found)
- Audit forms: focus:outline-none focus:ring-2 pattern is consistent throughout
- Add 4 test files covering mobile-safe modal classes and form baseline:
  ShareModal.mobile.test.js, CloudCredentialModal.mobile.test.js,
  FolderDeleteModal.mobile.test.js, DocumentPreviewModal.mobile.test.js

VISUAL-02, RESP-04
2026-06-16 21:33:57 +02:00
curo1305 11228306e4 Merge cleanup branch 2026-06-16 15:40:33 +02:00
curo1305andClaude Sonnet 4.6 ce67b9f98a fix(cloud): skeleton on first render + informative toast when opening cloud files
- loading initialised to true so skeleton rows show immediately on mount
  instead of the empty state flashing before data arrives
- @file-open no longer a silent no-op; shows an info toast explaining the
  file must be opened via the cloud provider directly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 13:57:18 +02:00
curo1305 e97ca164d7 Refactor backend and frontend cleanup paths 2026-06-16 11:50:17 +02:00
curo1305andClaude Sonnet 4.6 9a1c7df65d fix(10): resolve WR-03/WR-04 code review warnings
WR-04: AdminAuditView.vue had a local formatTimestamp() duplicating shared
util logic — moved to utils/formatters.js and imported from there per CLAUDE.md
shared-module rule.

WR-03: Remove unused onUnmounted import from FileManagerView.vue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 10:18:00 +02:00
curo1305 6b56763689 fix(10): close UX-06/UX-10/UX-13 verification gaps — Escape modal close, rename/revoke toasts, StorageBrowser picker tests 2026-06-16 09:57:17 +02:00
curo1305 20835bc706 refactor(10-12): migrate view-level SVGs to AppIcon
- CloudStorageView: cloud icon
- SettingsView: checkCircle, exclamationCircle, x (x2)
- AccountView: checkMark (TOTP enabled indicator)
- AdminAiView: chevronDown (accordion)
- AdminUsersView: copy, check, refresh
- SettingsAccountTab: checkMark (TOTP enabled)
- TotpEnrollment: checkMark (verified state)
- CloudCredentialModal: x, chevronRight
- DocumentView: warning (cloud delete modal)
- SharedView: document icon
2026-06-16 09:37:47 +02:00
curo1305 69bf40af32 feat(10-10): wire OsDragOverlay into App.vue; expose handleOsDrop on FileManagerView
- App.vue: import + mount <OsDragOverlay @files-dropped="onOsFilesDropped" />
  after <ToastContainer /> (overlay z-[9998] stays below toast z-[9999])
- App.vue: add onOsFilesDropped handler -> routeViewRef.value?.handleOsDrop?.(files)
- FileManagerView: extend defineExpose to include handleOsDrop delegating to
  existing onFilesSelected({ files, autoClassify: true }) — no duplicate upload logic
- Full test suite: 198 passed, 0 failures
2026-06-15 20:46:05 +02:00
curo1305 aaa0532af9 feat(10-09): plumb keyboard shortcut ref chain — DropZone→SearchBar→StorageBrowser→FileManagerView
- DropZone: defineExpose({ triggerInput }) to expose file picker trigger
- SearchBar: add inputEl ref + defineExpose({ focus }) for / shortcut
- StorageBrowser: add dropZoneRef + searchBarRef; expand defineExpose to include triggerUpload, focusSearch, clearSearch
- FileManagerView: add defineExpose delegating all four methods to browserRef via optional chaining
2026-06-15 20:35:38 +02:00
curo1305 776a1d9948 chore: merge executor worktree (10-08 admin views wiring) 2026-06-15 20:30:25 +02:00
curo1305 3e79423cfd feat(10-08): BreadcrumbBar in remaining admin views + SettingsView; EmptyState in SharedView + CloudStorageView
- AdminQuotasView: BreadcrumbBar (Quotas, showRoot=false)
- AdminAiView: BreadcrumbBar (AI Config, showRoot=false)
- AdminOverviewView: BreadcrumbBar (empty segments, showRoot=false) above existing h2
- SettingsView: BreadcrumbBar with breadcrumbSegments computed (Settings > activeTabLabel)
- SharedView: BreadcrumbBar (Shared with me) + EmptyState (icon=inbox)
- CloudStorageView: BreadcrumbBar in toolbar + EmptyState (icon=cloud) with Settings router-link CTA
- Full test suite: 178 passed, 0 failures
2026-06-15 20:27:00 +02:00
curo1305 9ea51d6401 feat(10-06): wire breadcrumb mapping + toast call sites; delete FolderBreadcrumb
- FileManagerView: add mappedBreadcrumb computed ({id,label} from foldersStore.breadcrumb)
- FileManagerView: import useToastStore; add toast.show() to doMove, doDeleteDoc, onFilesSelected
- FileManagerView: remove console.error from doMove/doDeleteDoc (toast communicates errors)
- CloudFolderView: add mappedBreadcrumb computed; pass to StorageBrowser :breadcrumb
- Delete FolderBreadcrumb.vue + FolderBreadcrumb.test.js (no dead code per CLAUDE.md)
- FileManagerView.test.js: replace dead FolderBreadcrumb mock with BreadcrumbBar mock
- StorageBrowser.skeleton.test.js: remove unused FolderBreadcrumb stub
- Full suite: 164/164 pass, 0 failures
2026-06-15 20:26:06 +02:00
curo1305 8e360f4f21 feat(10-08): skeleton tables + BreadcrumbBar + EmptyState in AdminAuditView and AdminUsersView
- AdminAuditView: add BreadcrumbBar (Audit Log, showRoot=false), replace loading spinner with 8-row skeleton tbody, replace empty div with EmptyState (icon=clipboardList) + Clear filters CTA
- AdminUsersView: add BreadcrumbBar (Users, showRoot=false), replace loading spinner with 5-row x 6-col skeleton tbody
- Promote CTA test to use real EmptyState (no stub) so slot content renders
- All 8 skeleton tests pass GREEN
2026-06-15 20:25:05 +02:00
curo1305 ec5fd23ec2 test(10-08): promote admin skeleton stubs to real RED tests — 8 failing tests
- AdminAuditView.skeleton.test.js: 5 real assertions (skeleton rows, cell count, no loading text, EmptyState, CTA)
- AdminUsersView.skeleton.test.js: 3 real assertions (skeleton rows, 6 cells, no loading text)
- All 8 tests fail until Task 2 updates the view components
2026-06-15 20:22:34 +02:00
curo1305 75970352fc test(10-05): Wave 0 skeleton + dropdown stubs (UX-02, UX-03, UX-04, UX-13, UX-14)
- StorageBrowser.skeleton.test.js: 7 it.todo stubs for UX-02 skeleton rows + UX-13 Teleport dropdown
- AppSidebar.empty.test.js: 10 it.todo stubs for UX-03 skeleton, UX-01 micro empty states, UX-14 inline-New removal
- AdminAuditView.skeleton.test.js: 5 it.todo stubs for UX-04 audit skeleton + UX-01 empty state
- AdminUsersView.skeleton.test.js: 3 it.todo stubs for UX-04 users skeleton
- dropdown.test.js: 4 it.todo stubs for UX-13 Teleport+getBoundingClientRect pattern
2026-06-15 20:11:40 +02:00
curo1305andClaude Sonnet 4.6 7ef65de046 refactor(09-05): CODE-09 purge — Phase 9 files (WHAT comments removed)
Frontend: AdminLayout, AdminSidebar, AdminOverviewView, AdminUsersView,
AdminQuotasView, AdminAiView, AdminAuditView, router/index.js, LoginView,
tailwind.config.js, api/admin.js — WHAT labels stripped; WHY constraints
preserved (D-16 anchors, security notes, api_key write-only invariant,
router guard rationale, D-08/D-09/D-10 decision refs, fetchWithRetry reason).
Backend: overview.py was already clean (no WHAT comments present).
Frontend: 137 tests pass, build succeeds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 21:52:30 +02:00
curo1305 e6467d18cf feat(09-04): delete AdminView + 4 tab files; update tests + router guard test
- git rm AdminView.vue, AdminUsersTab.vue, AdminQuotasTab.vue, AdminAiConfigTab.vue, AuditLogTab.vue
- Migrate tab tests to import from views/admin/Admin*View.vue
- Update router.guard.test.js: replace AdminView mock with AdminLayout + 5 admin view mocks
- Add D-09 redirect test (admin on / → /admin)
- Fix stale api/admin.js JSDoc consumer list
- Fix SettingsView.vue stale AdminView comment reference
2026-06-12 16:11:00 +02:00
curo1305 bdd68b2edf feat(09-04): wire admin login redirect in LoginView.vue (D-08)
- After successful login, admin users redirect to /admin; regular users to /
- Honors ?redirect= query param for non-admin users as before
- authStore.user.role is synchronously populated before handleLoginResult fires
2026-06-12 16:08:25 +02:00
curo1305 164003b19b feat(09-03): extract AdminAiView + AdminAuditView from tab components
- Created frontend/src/views/admin/AdminAiView.vue (extracted from AdminAiConfigTab.vue)
  - Import path for SearchableModelSelect rewritten to ../../components/ui/SearchableModelSelect.vue
  - System AI Providers (Global) section preserved above per-user table (Phase 7 constraint)
- Created frontend/src/views/admin/AdminAuditView.vue (verbatim from AuditLogTab.vue per D-13)
  - actionTypeClass() helper preserved verbatim with all bg-amber-50, bg-purple-50 dynamic classes
  - Filter bar, paginated table, CSV download, daily-export list all preserved as-is
- Both files have no defineProps, no top-level padding, identical line counts to sources
- Build succeeds: 143 modules transformed, no errors
2026-06-12 16:01:29 +02:00
curo1305 d690a445b9 feat(09-03): extract AdminUsersView + AdminQuotasView from tab components
- Created frontend/src/views/admin/AdminUsersView.vue (verbatim extraction of AdminUsersTab.vue)
- Created frontend/src/views/admin/AdminQuotasView.vue (verbatim extraction of AdminQuotasTab.vue)
- Both files have no defineProps, no top-level padding, identical import paths (../../api/client.js, ../../utils/formatters.js)
- Line counts match source exactly (480 and 182 lines respectively)
- Build succeeds with no Vite errors referencing new view files
2026-06-12 15:58:51 +02:00
curo1305 1e14e15cbf feat(09-02): create AdminOverviewView.vue
- Single-fetch view calling getAdminOverview() on mount with loading/error states
- Four stat cards grid (Users, Storage, Processing, Ready) per ADMIN-11 and D-01
- Recent audit table with 5 columns (When/Event/Actor/Target/IP) matching AuditLogTab.vue structure
- Uses formatSize/formatDate from shared utils/formatters.js (no duplication)
- No top-level padding (AdminLayout owns p-8 max-w-5xl mx-auto)
- No Pinia store — single-fetch component consistent with admin tab pattern
2026-06-12 15:48:19 +02:00
curo1305 21e5d27c90 feat(07.3-03): frontend remember_me — checkbox + ref threading + store pass-through
- LoginView.vue: add rememberMe ref(false) + "Stay signed in for 30 days" checkbox in password step; thread rememberMe.value through all 3 submit handlers (submitPassword, submitTotp, submitBackupCode) (D-12)
- stores/auth.js: login() forwards options.rememberMe as remember_me in api.login body (D-12)
- api/client.js: no change needed — already forwards full body verbatim
- Frontend build passes (vite build exits 0)
2026-06-06 17:23:02 +02:00
curo1305andClaude Sonnet 4.6 3b11b9a596 feat(07-uat): admin AI panel UX enhancements + DocumentCard status indicators
- GET /api/admin/ai-config/models — fetch model list from provider's /models endpoint
- POST /api/admin/ai-config/test-connection — replaced GET; accepts unsaved form
  values (api_key, base_url, model_name) so admins can test before saving
- TestConnectionRequest Pydantic model with provider_id validation
- SearchableModelSelect.vue — new reusable combobox; Teleport to body avoids
  overflow:hidden clipping; shows all models on open, filters only on typing;
  static "Enter manually" item always pinned at bottom; caches per provider
- AdminAiConfigTab: model name input replaced with SearchableModelSelect;
  testingProvider ref + spinner added to Test Connection button
- DocumentCard: processing spinner + "Classifying…", pending "Queued" badge,
  classification_failed badge; topics section only shown when status=ready
- FileManagerView: onUnmounted imported (polling wiring pending next session)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 09:26:02 +02:00
curo1305andClaude Sonnet 4.6 cce70b2ef6 refactor(frontend): extract shared modules, thin views, delete dead code
Shared utilities:
- Add src/utils/formatters.js — formatDate, formatSize, providerColor,
  providerBg, providerLabel; all components import from here, no inline duplicates
- Add src/components/ui/TreeItem.vue — generic expand/collapse tree node;
  FolderTreeItem, CloudFolderTreeItem, CloudProviderTreeItem now wrap it
- Add src/components/storage/StorageBrowser.vue — unified file browser grid
  used by both FileManagerView and CloudFolderView

View refactor (thin data-providers):
- FileManagerView.vue: stripped to props + event wiring; all layout moved to StorageBrowser
- CloudFolderView.vue: same treatment — feeds props into StorageBrowser
- All tree sidebar components delegate expand/collapse to TreeItem.vue

Dead code removed:
- Delete HomeView.vue — no active route, replaced by FileManagerView
- Delete FolderView.vue — no active route, logic merged into FileManagerView

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:10:47 +02:00
curo1305andClaude Sonnet 4.6 d771f0805d fix(06.2): shared badge and recipient handle missing in FileManagerView
- shares.py grant_share: include recipient_handle in response so ShareModal shows the name immediately without reload
- FileManagerView: add Shared pill badge next to document name (badge only existed in DocumentCard, not the main file manager view)
- FileManagerView ShareModal: wire @unshared to clear is_shared flag when last recipient is removed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:47:00 +02:00
curo1305andClaude Sonnet 4.6 a0f6c2f663 fix(06.2): resolve four sharing UX issues found in re-test UAT
- AccountView: remove hardcoded @ prefix so handle matches what share dialog expects
- documents store: set is_shared=true optimistically after successful share so badge shows without refetch
- GET /api/documents/{id}: allow recipients of an active share to view the document (was returning 404 for non-owners)
- ShareModal: move Share button to its own full-width row so it no longer overflows the input area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:32:51 +02:00
curo1305 c08ea42b1b feat(02-06): Account tab in SettingsView + QR code in TotpEnrollment (GAPs 3, 5)
- frontend/package.json: add qrcode@1.5.4 to runtime dependencies
- TotpEnrollment.vue: import QRCode; generate data URL in startSetup(); render img tag
- SettingsAccountTab.vue: new component with all AccountView content (2FA, password, sessions)
- SettingsView.vue: add Account tab rendering SettingsAccountTab; import SettingsAccountTab
2026-05-31 20:40:28 +02:00
curo1305 f5e111bfa2 feat(06.2-05): actionable cloud error + audit log @ prefix
- CloudFolderView: detect no-connection error and show actionable message
  directing user to Settings; add router-link to /settings and Retry button
- AuditLogTab: prefix user handles with @ in the User column
2026-05-31 20:10:22 +02:00
curo1305 045e723f7a feat(06.2-05): show @handle in AccountView and AdminUsersTab
- Add Username row (@handle) to Account information section in AccountView.vue
- Add Handle column (th + td with @prefix) to users table in AdminUsersTab.vue
- Both use existing data already present in API responses (no backend changes)
2026-05-31 20:09:50 +02:00
curo1305andClaude Sonnet 4.6 cce8586235 feat(06.2-03): frontend — CloudDeleteWarningModal + remove_only path in DocumentView
- api/client.js: deleteDocument gains removeOnly param; deleteDocumentRemoveOnly wrapper added
- DocumentView.vue: confirmDelete inspects response.cloud_delete_failed, shows modal on failure
- DocumentView.vue: inline CloudDeleteWarningModal (C-3 contract) with Remove from app / Cancel
- confirmRemoveOnly() calls DELETE ?remove_only=true and navigates to /

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:11:31 +02:00
curo1305andClaude Sonnet 4.6 10175ee4b5 fix(05-12): close 3 UAT gaps — OAuth 400 preflight, 502 cloud fallback, upload hint
- oauth_initiate: pre-flight check returns 400 with env-var hint when
  GOOGLE_CLIENT_ID/SECRET or ONEDRIVE_CLIENT_ID/SECRET are not configured,
  preventing opaque MSAL/OAuth library 500 errors on misconfigured servers
- stream_document_content: broad except-clause catches non-CloudConnectionError
  exceptions and returns 502 with user-friendly message (was raw 500)
- docker-compose.yml: add volumes: - ./backend:/app to celery-worker so code
  changes are picked up by docker compose restart without a rebuild
- CloudStorageView: upload hint paragraph directs users to navigate into a
  cloud folder; no DropZone added (no folder context at overview level)
- 3 new backend tests pass; 2 existing tests patched with credential monkeypatch;
  full suite: 293 passed, 0 new failures, 1 pre-existing (test_extract_docx)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 17:55:08 +02:00
curo1305andClaude Sonnet 4.6 5250895587 feat(05): cloud folder browser views, routing, and sidebar nav
Add CloudStorageView (/cloud) and CloudFolderView (/cloud/:provider/:folderId).
Tree items filter to directories only (is_dir) to hide files in the nav tree.
CloudProviderTreeItem root click navigates to /cloud/{provider}/root instead
of /settings. AppSidebar Cloud Storage link upgraded to router-link with
active-class highlighting. Router registers both cloud routes with requiresAuth.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 11:58:08 +02:00
curo1305andClaude Sonnet 4.6 34f012b4e8 fix(05): resolve 5 critical code review findings
CR-01: add Field(min_length=1) to UserDeleteConfirm.admin_password
CR-02: add folder ownership check in PATCH /documents/{id} — prevents IDOR
        when folder_id belongs to another user
CR-03: add min_length=1, max_length=255, and path-separator validator to
        DocumentPatch.filename — prevents empty and path-traversal filenames
CR-04: fetchDocumentContent now throws on non-ok responses instead of
        silently returning the error Response
CR-05: object URL revoke in DocumentView uses pagehide + load events with
        120s fallback instead of unreliable 60s blind timer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 11:51:54 +02:00
curo1305 4a42ccee5a feat(05-09): authenticated document preview via fetch + Blob URL
- Add fetchDocumentContent() to client.js: fetch with Bearer auth, 401 refresh
  retry pattern, returns raw Response (not parsed JSON) for blob() calls
- Replace iframe :src=proxyUrl (unauthenticated) in DocumentPreviewModal.vue
  with authenticated fetch → blob → URL.createObjectURL; loading/error states;
  URL.revokeObjectURL on unmount to prevent memory leaks
- Replace window.open(rawUrl) in DocumentView.vue openPdf() with
  fetchDocumentContent → blob → objectUrl → window.open; 60s auto-revoke
- Frontend build exits 0 with zero errors
- Closes T-05-09-04: no persistent unauthenticated content exposure
2026-05-30 11:18:01 +02:00