Files
upl/static/index.html
T
ddidderr 1923ff2a6f feat: support parallel multi-file uploads
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
2026-05-30 18:32:29 +02:00

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>