1923ff2a6f
The browser upload flow was built around one selected file and one global upload state. That made the existing chunk pool useful for a single file, but users could not start several selected files at the same time. Refactor the browser state into per-file upload items. Each selected file now has its own upload record, completed-chunk set, abort controller, retry state, progress row, and saved IndexedDB resume record. The picker accepts multiple files, `Start all` and `Resume all` use a bounded file-level pool, and each file keeps the existing bounded chunk pool. This keeps parallel uploads useful without letting one large selection create unbounded request fan-out. Keep the server API unchanged. Each file still receives a separate server upload id, and server-side progress remains authoritative before any missing chunks are scheduled. Terminal conflicts still stop the affected file without overwriting completed data. Update the user-facing markup, styles, project docs, and test checklist for the multi-file scheduler. Add a server regression test that interleaves two uploads and verifies the completed files contain exactly their own bytes. Test Plan: - just check - git diff --check
48 lines
1.5 KiB
HTML
48 lines
1.5 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>upl</title>
|
|
<link rel="stylesheet" href="/styles.css">
|
|
<script src="/app.js" defer></script>
|
|
</head>
|
|
<body>
|
|
<main class="app-shell">
|
|
<section class="upload-panel" aria-labelledby="app-title">
|
|
<div class="panel-heading">
|
|
<div>
|
|
<h1 id="app-title">upl</h1>
|
|
<p class="subtle">Resumable uploads to this machine.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="file-picker">
|
|
<button id="pick-button" type="button">Choose files</button>
|
|
<input id="file-input" type="file" multiple>
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<button id="start-button" type="button" disabled>Start all</button>
|
|
<button id="pause-button" type="button" disabled>Pause all</button>
|
|
<button id="resume-button" type="button" disabled>Resume all</button>
|
|
</div>
|
|
|
|
<section class="upload-section" id="upload-section" hidden>
|
|
<h2>Selected uploads</h2>
|
|
<ul class="upload-list" id="upload-list"></ul>
|
|
</section>
|
|
|
|
<section class="pending-section" id="pending-section" hidden>
|
|
<h2>Saved upload progress</h2>
|
|
<ul class="pending-list" id="pending-list"></ul>
|
|
</section>
|
|
|
|
<ol class="event-log" id="event-log" aria-live="polite">
|
|
<li>Choose files to begin.</li>
|
|
</ol>
|
|
</section>
|
|
</main>
|
|
</body>
|
|
</html>
|