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

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-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}.
<!-- 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:
// 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.