76 lines
2.9 KiB
Markdown
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.
|