Files
hub/docs/drives-phase-4.md
T
2026-09-21 16:18:42 -05:00

76 lines
2.9 KiB
Markdown

# Phase 4: Frontend Integration
## Objective
Build the Vue3 components that consume the drive API for listing, uploading, and downloading files. Integration is minimal and relies on established Vue3 patterns.
## Concepts
### Minimal Frontend Design
- **Drives View**: Fetches drives on mount. Clicking a drive triggers `list-files` via WebSocket.
- **Upload Handling**: Standard drag-and-drop zone. On drop, initiates WS upload sequence. Updates local store immediately upon receiving `fileId`.
- **Downloads**: Uses dedicated REST endpoint `/files/<id>` secured by QuartAuth bearer token. Constructs `<a href="/files/{id}" download>Download</a>` rather than streaming binary over WebSocket.
### Download Strategy
Files require server-side resolution (ownership verification + path generation). Therefore:
- The frontend never requests raw file bytes over WebSocket.
- Instead, a direct anchor link to the secured REST endpoint handles downloads.
- This avoids memory bloat on both client and server sides.
## Tasks
### 4.1 Drives View Component
Create a component (`src/views/DrivesView.vue`) that:
- Fetches available drives on mount using the `list-drives` WebSocket action.
- Renders a list/table of drives with clickable names/IDs.
- On click, stores selected drive name and emits an event to show the files list.
### 4.2 Files List View
Create or update the files view component to:
- Call `list-files` with the selected `{driveName}` when the view mounts or drive changes.
- Render a simple table displaying `filename` and `size` for each row.
- Provide a "Download" button/link per row that navigates to `/files/{id}`.
```vue
<!-- Example file list item -->
<a :href="`/files/${file.id}`" :download="file.name">
{{ file.name }} ({{ file.size }})
</a>
```
### 4.3 Upload Zone
Implement a drag-and-drop zone (`components/FileUploadZone.vue`):
- Listen for `drop` events on supported file types.
- On drop, initiate the WebSocket upload sequence:
```javascript
// 1. Send metadata header
ws.send(JSON.stringify({
action: "upload-file",
nonce: crypto.randomUUID(),
body: {
driveName: currentDrive.value,
fileName: droppedFile.name,
mime: droppedFile.type
}
}));
// 2. Immediately follow with binary payload
ws.send(droppedFile); // File object sent directly as binary
// 3. Wait for server response
// On receiving {action: "file-updated", fileId: ..., nonce: ...}:
// - Update local store to add the new file record
// - Optionally show a success toast
```
- Store uploaded files in local Vuex/Pinia store immediately after `fileId` receipt to reflect progress/success instantly without waiting for another poll cycle.
### 4.4 Store Updates
Extend your application store (Pinia/Vuex) to:
- Hold state for `drives: []`, `currentDrive`, and `files: []`.
- Handle incoming `file-uploaded` messages from WebSocket by inserting new records into the active drive's file array.