479108779f
All API calls now go through a thin request() wrapper around native fetch. Removes the axios dependency entirely. The wrapper injects the JWT on every request and — the key fix — clears localStorage and redirects to /login on any 401 response, so expired sessions no longer leave users on broken pages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
211 lines
9.2 KiB
Markdown
211 lines
9.2 KiB
Markdown
# Frontend — Status
|
||
|
||
## What it is
|
||
|
||
React 18 + TypeScript + Vite SPA styled with **shadcn/ui** (Radix primitives) and **Tailwind CSS v3**. Design tokens are CSS custom properties supporting light/dark themes. In dev it runs on port `5173` and proxies `/api/*` to `backend:8000`. In prod it is served by nginx on port `80`.
|
||
|
||
All API calls go through `src/api/client.ts` (single Axios instance, JWT injected via request interceptor from `localStorage`).
|
||
|
||
---
|
||
|
||
## Routes
|
||
|
||
| Path | Component | Auth |
|
||
|------|-----------|------|
|
||
| `/login` | `LoginPage` | Public |
|
||
| `/` | `DashboardPage` | Required |
|
||
| `/apps` | `AppsPage` | Required |
|
||
| `/apps/documents` | `DocumentsPage` | Required |
|
||
| `/apps/documents/settings` | `DocServiceSettingsPage` | ServiceAdminRoute (is_admin OR doc-service-admin) |
|
||
| `/apps/ai/settings` | `AIAdminSettingsPage` | ServiceAdminRoute (is_admin OR ai-service-admin) |
|
||
| `/admin` | `AdminPage` (redirects to `/admin/users`) | Admin only |
|
||
| `/admin/users` | `AdminUsersPage` | Admin only |
|
||
| `/admin/groups` | `AdminGroupsPage` | Admin only |
|
||
| `/profile` | `ProfilePage` | Required |
|
||
| `/settings` | `SettingsPage` (placeholder) | Required |
|
||
| `/settings/plugins/:id` | `PluginSettingsPage` | Required (per-plugin access control) |
|
||
|
||
`PrivateRoute` redirects to `/login` when no token. `AdminRoute` redirects to `/` when not admin.
|
||
|
||
---
|
||
|
||
## Current functionality
|
||
|
||
### Auth
|
||
|
||
- Login form (`POST /api/auth/login`) stores JWT in `localStorage`
|
||
- Logout clears token and redirects to `/login`
|
||
- `GET /api/users/me` verifies token on protected routes
|
||
|
||
### Home dashboard (`/`)
|
||
|
||
Personalised landing page per user:
|
||
- Time-aware greeting with the user's display name
|
||
- Grid of **pinned app cards** from `GET /api/services`, filtered to user's saved list
|
||
- **Customize mode** (pencil button): shows all services; `+` / `−` toggle; commits via `PATCH /api/users/me/preferences`
|
||
|
||
### Apps page (`/apps`)
|
||
|
||
Cards from `GET /api/services` (polled every 30 s):
|
||
- healthy + app_path → clickable card with "Available" badge
|
||
- healthy + no app_path → non-clickable card
|
||
- unhealthy → dimmed, non-clickable, "Unavailable"
|
||
- Settings button visible to admins and service-admin group members
|
||
|
||
### Sidebar navigation
|
||
|
||
`Apps` expandable accordion: **Documents** single NavLink to `/apps/documents`. Category navigation moved to SourcePanel (only visible on `/apps/documents` route). Admin section (Users, Groups, Appearance) for admins. Collapsible to icon-only mode.
|
||
|
||
### Documents page (`/apps/documents`) — three-column layout
|
||
|
||
**SourcePanel** (240px, left): Appears only on `/apps/documents`.
|
||
- Views: All Documents / Mine / Shared with me (URL param `?view=`)
|
||
- Category tree with client-side search (searchable when > 4 categories)
|
||
- Inline new category form
|
||
- "Manage categories" button opens `ManageCategoriesDialog`
|
||
|
||
**Toolbar:** Debounced search input (400ms) + filter chips system.
|
||
- Filter chips: Status, Document type, Category (each adds a removable chip)
|
||
- "Add filter" button opens a two-step picker (dimension → value)
|
||
- Sort via clickable column headers (↑/↓ chevron)
|
||
|
||
**Compact table rows:**
|
||
- Columns: checkbox | title/filename | type | status dot | categories (2 + overflow) | sharing icon | date | size | 3-dot actions
|
||
- Row click opens `DocumentSlideOver`
|
||
- Shared-with-me rows show a primary border accent
|
||
|
||
**DocumentSlideOver** (480px, right slide-over):
|
||
- Metadata (status dot, size, dates, source)
|
||
- Inline title edit (pencil icon)
|
||
- Type picker (chips for each doc type)
|
||
- **AI Suggestions** — folder and filename confirm/reject buttons (was missing before, now implemented)
|
||
- Extracted data key-value table
|
||
- Categories multi-select combobox (search-to-filter)
|
||
- AI-suggested categories with Assign / Create & Assign actions
|
||
- Tags chip editor (add/remove inline)
|
||
- **Sharing section** (owner only): lists groups the doc is shared with; group picker combobox (filtered to user's own groups); remove share button
|
||
- Raw text section (collapsed by default)
|
||
- Re-analyse / Delete actions (owner only)
|
||
|
||
**Bulk actions bar** (floating, bottom center, owner view only):
|
||
- Appears when any rows are checked
|
||
- Share with group (opens group picker → shares all selected)
|
||
- Delete (confirm dialog)
|
||
- Clear selection
|
||
|
||
**Upload experience:**
|
||
- Full-page drag-and-drop overlay (activates on `dragenter`)
|
||
- Multi-file upload (iterates all selected/dropped files)
|
||
- Bottom-right upload queue panel (collapsible toast) with per-file status + "Review →" link after upload
|
||
|
||
**Document sharing:**
|
||
- Owner shares doc with any of their own groups from the slide-over
|
||
- Recipient sees shared docs in "Shared with me" view
|
||
- Recipient can View + Download only (no edit/delete/share)
|
||
- `share_count` indicator (Users icon) in table rows
|
||
|
||
**Polling:** List query refetches every 3s automatically when any visible doc is pending/processing (single query, not per-document). Uses TanStack Query `refetchInterval` function.
|
||
|
||
### AI Service Settings (`/apps/ai/settings`)
|
||
|
||
Provider selector, per-provider fields, Test Connection, Save.
|
||
|
||
### Document Service Settings (`/apps/documents/settings`)
|
||
|
||
Upload limits + watch directory config.
|
||
|
||
### Admin — Users page (`/admin/users`)
|
||
|
||
User list, toggle active, create user, delete user.
|
||
|
||
### Admin — Groups page (`/admin/groups`)
|
||
|
||
Group list, create, edit name/description, delete, add/remove members.
|
||
|
||
### Profile page (`/profile`)
|
||
|
||
Display and edit personal information.
|
||
|
||
---
|
||
|
||
## API client (`src/api/client.ts`)
|
||
|
||
**No Axios** — replaced with a native `fetch` wrapper (`request()`). Global 401 handler clears the token and redirects to `/login`, fixing the expired-session blank-page bug. All exported function signatures are unchanged.
|
||
|
||
Key document-related functions:
|
||
|
||
| Function | Description |
|
||
|----------|-------------|
|
||
| `listDocuments(params)` | `GET /documents` — paginated with filters |
|
||
| `listSharedWithMe(params)` | `GET /documents/shared-with-me` |
|
||
| `uploadDocument(file)` | `POST /documents/upload` |
|
||
| `deleteDocument(id)` | `DELETE /documents/{id}` |
|
||
| `downloadDocument(id, filename)` | Blob URL download |
|
||
| `viewDocument(id)` | Blob URL → new tab, 60s revoke |
|
||
| `getDocumentShares(docId)` | `GET /documents/{id}/shares` |
|
||
| `addDocumentShare(docId, groupId)` | `POST /documents/{id}/shares` |
|
||
| `removeDocumentShare(docId, groupId)` | `DELETE /documents/{id}/shares/{group_id}` |
|
||
| `getMyGroups()` | `GET /users/me/groups` (for share picker) |
|
||
| `confirmFolderSuggestion(docId)` | Apply AI folder suggestion |
|
||
| `rejectFolderSuggestion(docId)` | Dismiss AI folder suggestion |
|
||
| `confirmFilenameSuggestion(docId)` | Apply AI filename suggestion |
|
||
| `rejectFilenameSuggestion(docId)` | Dismiss AI filename suggestion |
|
||
|
||
---
|
||
|
||
## State management
|
||
|
||
- **TanStack Query** — all server state
|
||
- `["documents", params]` — owned doc list (refetchInterval when pending/processing)
|
||
- `["documents-shared", params]` — shared-with-me list
|
||
- `["categories"]` — all user categories (shared across SourcePanel + DocumentSlideOver)
|
||
- `["document-shares", docId]` — shares for a specific document
|
||
- `["my-groups"]` — current user's group memberships
|
||
- **URL search params** — `view`, `page`, `sort`, `order`, `search`, `status`, `document_type`, `category_id`
|
||
- **Local `useState`** — UI-only state (drag, upload queue, active doc ID, selected IDs, slide-over open)
|
||
|
||
---
|
||
|
||
## Component inventory
|
||
|
||
| Component | Path | Description |
|
||
|-----------|------|-------------|
|
||
| `AppShell` | `src/components/AppShell.tsx` | Layout: Sidebar + SourcePanel (on /apps/documents) + main |
|
||
| `Sidebar` | `src/components/Sidebar.tsx` | Collapsible left nav (categories removed, replaced by SourcePanel) |
|
||
| `SourcePanel` | `src/components/SourcePanel.tsx` | Views + searchable category tree (docs route only) |
|
||
| `ManageCategoriesDialog` | `src/components/ManageCategoriesDialog.tsx` | Category CRUD modal |
|
||
| `DocumentSlideOver` | `src/components/DocumentSlideOver.tsx` | Right slide-over: detail, edit, share, AI suggestions |
|
||
| `ThemeToggle` | `src/components/ThemeToggle.tsx` | Sun/moon toggle |
|
||
| `PluginSchemaForm` | `src/components/PluginSchemaForm.tsx` | JSON Schema → React form |
|
||
| `Button` | `src/components/ui/button.tsx` | shadcn/ui Button |
|
||
| `Input` | `src/components/ui/input.tsx` | shadcn/ui Input |
|
||
|
||
---
|
||
|
||
## Known limitations / not implemented
|
||
|
||
- **JWT in `localStorage`** — XSS risk; migrate to `httpOnly` cookie when backend supports it
|
||
- **No toast / notification system** — errors shown inline; success is silent
|
||
- **No loading skeletons** — spinner only
|
||
- **Raw text not in DocumentOut** — slide-over shows a placeholder; full text requires direct backend API call
|
||
|
||
---
|
||
|
||
## Future work
|
||
|
||
- [x] SourcePanel with views + searchable category navigation
|
||
- [x] DocumentSlideOver replacing expand-in-row
|
||
- [x] Filter chip system
|
||
- [x] Multi-file upload with queue panel + drag-and-drop
|
||
- [x] Bulk actions bar (share, delete)
|
||
- [x] Document sharing UI (Sharing section + Shared with me view)
|
||
- [x] AI suggestion confirm/reject UI (folder + filename)
|
||
- [x] Groups admin UI
|
||
- [x] Replace Axios with native fetch; add global 401 → `/login` redirect for expired sessions
|
||
- [ ] Toast notification system
|
||
- [ ] Loading skeletons
|
||
- [ ] Cmd+K global search (`CommandDialog`)
|
||
- [ ] Advanced filter: extracted data fields (needs backend support)
|
||
- [ ] `httpOnly` cookie auth (requires backend change)
|
||
- [ ] TanStack Virtual for category list > 200 items
|