2.9 KiB
2.9 KiB
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-filesvia 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-drivesWebSocket 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-fileswith the selected{driveName}when the view mounts or drive changes. - Render a simple table displaying
filenameandsizefor each row. - Provide a "Download" button/link per row that navigates to
/files/{id}.
<!-- 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
dropevents on supported file types. - On drop, initiate the WebSocket upload sequence:
// 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
fileIdreceipt 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, andfiles: []. - Handle incoming
file-uploadedmessages from WebSocket by inserting new records into the active drive's file array.