a8dfbd5dc6
Delete the old top-level page files whose content was migrated into service-page tabs in slices 5-9: - pages/Media.tsx, Applications.tsx (-> MediaTab) - pages/FileBrowser.tsx, FileBrowser.impl.tsx (-> FilesTab) - pages/Actions.tsx (-> ActionsTab) - pages/Users.tsx, UsersPage.impl.tsx (replaced by Authentik tabs) - components/BackupsPage.tsx (-> JobsTab) - components/ObservabilityPage.tsx (split into Alerts/Links/Metrics tabs) - hooks/useUsers.ts (orphaned after Users page deletion) - the corresponding page test files (Media, FileBrowser, Applications, Actions, UsersPage) that tested the deleted pages directly. The service-tab components are the live implementations; ServicePage renders them. No live code references the deleted files. Docs: append an Information Architecture section to REQUIREMENTS.md documenting the services-as-hub model (nav shape, service-page tabs, service type registry, Users->Authentik, Observability split, legacy route 404s, empty state). Add a CHANGELOG entry under [Unreleased]. 92 frontend tests pass (was 112; -20 deleted page tests); 271 backend tests pass; lint/build green. Refs openspec/changes/services-as-hub-ia/ (tasks slice 11).
99 lines
4.7 KiB
Markdown
99 lines
4.7 KiB
Markdown
# Slice 8 — Authentik Users + Messaging tabs (worker output)
|
|
|
|
## Files changed
|
|
|
|
| File | Status | Lines |
|
|
|------|--------|-------|
|
|
| `backend/src/media_library_viewer_api/routers/authentik_users.py` | modified | +66/-8 (added MessageRequest model + status + message endpoints) |
|
|
| `frontend/src/api/authentik.ts` | new | 65 |
|
|
| `frontend/src/hooks/useAuthentik.ts` | new | 43 |
|
|
| `frontend/src/pages/service-tabs/UsersTab.tsx` | new | 136 |
|
|
| `frontend/src/pages/service-tabs/MessagingTab.tsx` | new | 131 |
|
|
| `frontend/src/pages/service-tabs/__tests__/UsersTab.test.tsx` | new | 49 |
|
|
| `frontend/src/pages/service-tabs/__tests__/MessagingTab.test.tsx` | new | 47 |
|
|
| `frontend/src/pages/service-tabs/index.ts` | modified | +4/-4 |
|
|
| `frontend/src/pages/service-tabs/stubs.tsx` | modified | -8 (removed UsersTab/MessagingTab stubs) |
|
|
|
|
**Total: ~539 lines** (471 new files + 68 modified diff). Over the 400-line budget; dominated by the new-build UsersTab + MessagingTab (no existing UI to lift — built from scratch against the Authentik endpoint).
|
|
|
|
## Backend message endpoint (Option A — implemented)
|
|
|
|
Added to `routers/authentik_users.py`:
|
|
|
|
```
|
|
GET /api/services/authentik/{service_id}/message/status
|
|
POST /api/services/authentik/{service_id}/message
|
|
```
|
|
|
|
**POST body** (`MessageRequest`):
|
|
|
|
```json
|
|
{ "recipient_emails": ["alice@example.com"], "subject": "...", "html_body": "..." }
|
|
```
|
|
|
|
**Response** (success):
|
|
|
|
```json
|
|
{ "status": "queued", "request_id": "abc123", "recipient_count": 1 }
|
|
```
|
|
|
|
**Response** (error — service not configured / no recipients / SMTP invalid):
|
|
|
|
```json
|
|
{ "status": "error", "error": "description" }
|
|
```
|
|
|
|
The endpoint resolves the Authentik service record, validates SMTP settings, then enqueues via the existing `mail_queue.enqueue()`. The GET status endpoint proxies `mail_queue.status()`. Both are service-id scoped and return graceful errors matching the directory endpoint's pattern.
|
|
|
|
## UsersTab columns
|
|
|
|
| Column | Source field | Notes |
|
|
|--------|-------------|-------|
|
|
| Name | `user.name` | Falls back to "—" |
|
|
| Username | `user.username` | |
|
|
| Email | `user.email` | Falls back to "—" |
|
|
| Status | `user.is_active` | Badge: "Active" (default) / "Inactive" (secondary) |
|
|
|
|
Features: search input (committed on Enter/click), pagination (25 per page), error-Alert when endpoint returns an error field.
|
|
|
|
## MessagingTab
|
|
|
|
Compose form with:
|
|
|
|
- Recipient search + toggle buttons (from Authentik users with emails)
|
|
- Subject input
|
|
- HTML body textarea (default template)
|
|
- Send button wired to POST `/api/services/authentik/{id}/message`
|
|
- Success/error Alert on mutation result
|
|
- Recipient count display
|
|
|
|
## Validation
|
|
|
|
```
|
|
cd backend && .venv/bin/ruff check src/ tests/ → All checks passed!
|
|
cd backend && .venv/bin/python -m pytest tests/ → 271 passed, 2 warnings
|
|
cd frontend && npm run lint → 0 errors, 2 pre-existing warnings
|
|
cd frontend && npm run build → ✓ built (tsc -b + vite)
|
|
cd frontend && npm run test → 32 files / 100 tests passed (was 96; +4 new)
|
|
```
|
|
|
|
## Deviations from design
|
|
|
|
1. **Over 400-line budget.** The UsersTab and MessagingTab are built from scratch (no existing Users UI to lift — the old page was Jellyfin-backed and deleted). Could not shrink without dropping functionality.
|
|
|
|
2. **MessagingTab is simplified vs. the old compose UI.** The old UsersPage had rich-text formatting toolbar (bold/italic/link/bullet), attachment upload, email preview iframe, and detailed queue-status banners. This slice implements a minimal but functional compose (recipient selection + subject + HTML body + send + result alert). Rich-text toolbar + attachments are follow-ups. The backend endpoint accepts the core fields (recipient_emails, subject, html_body) but not attachments yet.
|
|
|
|
3. **No attachment upload.** The mail_queue.enqueue() accepts attachments, but the POST endpoint does not accept multipart yet. Attachments are a follow-up (requires multipart handling on the endpoint + attachment UI).
|
|
|
|
4. **Queue status polled via a dedicated hook.** `useAuthentikMessageStatus(serviceId)` polls `/api/services/authentik/{id}/message/status` every 5s. The MessagingTab does not yet display the queue status banner (minimal UI); the hook + endpoint exist for the follow-up that adds the queue indicator.
|
|
|
|
## skill_resolution
|
|
|
|
`none` — no project/user SKILL.md paths were injected, and no `.atl/skill-registry.md` was found.
|
|
|
|
## Residual risks
|
|
|
|
- **MessagingTab lacks rich-text toolbar + attachment upload + queue-status banner.** These are follow-ups; the core send flow works.
|
|
- **Old UsersPage.impl.tsx + its test file still pass** (rendered directly, not via routing). Deleted in Slice 11 cleanup.
|
|
- **Backend message endpoint returns 200 on error** (not 4xx/5xx), matching the directory endpoint's pattern. The frontend checks the `status`/`error` field.
|