# 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/` secured by QuartAuth bearer token. Constructs `Download` 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 {{ file.name }} ({{ file.size }}) ``` ### 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.