feat(upload): add resumable chunk configuration and file validation
Some checks failed
Build and Publish Docker Image / deploy (push) Failing after 56s
Some checks failed
Build and Publish Docker Image / deploy (push) Failing after 56s
- Add `WARPBOX_RESUMABLE_CHUNK_MODE` and `WARPBOX_RESUMABLE_CHUNK_PATH` environment variables to configure temporary chunk storage. - Implement strict file validation for resuming uploads to ensure selected files match the pending session's metadata. - Add `PLANS.md` to document development stages, roadmap, and API specifications (including batching and resumable flows).
This commit is contained in:
@@ -126,6 +126,33 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h3 class="settings-section-title">Resumable uploads</h3>
|
||||
<label class="checkbox-field">
|
||||
<input type="checkbox" name="resumable_uploads_enabled" {{if .Data.Settings.ResumableUploadsEnabled}}checked{{end}}>
|
||||
<span>Enable browser/API resumable uploads</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Chunk size (MB)</span>
|
||||
<input name="resumable_chunk_size_mb" value="{{.Data.Settings.ResumableChunkSizeMB}}" required>
|
||||
</label>
|
||||
<label>
|
||||
<span>Draft retention (hours)</span>
|
||||
<input type="number" name="resumable_retention_hours" min="1" value="{{.Data.Settings.ResumableRetentionHours}}" required>
|
||||
</label>
|
||||
<label>
|
||||
<span>Chunk storage</span>
|
||||
<select name="resumable_chunk_mode" required>
|
||||
<option value="same" {{if eq .Data.Settings.ResumableChunkMode "same"}}selected{{end}}>Default local data path</option>
|
||||
<option value="custom" {{if eq .Data.Settings.ResumableChunkMode "custom"}}selected{{end}}>Custom local path, e.g. fast SSD</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Custom chunk path</span>
|
||||
<input name="resumable_chunk_path" value="{{.Data.Settings.ResumableChunkPath}}" placeholder="/mnt/fast-ssd/warpbox-chunks">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button class="button button-primary" type="submit">Save settings</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
{{end}}
|
||||
|
||||
{{if .Data.Files}}
|
||||
{{$processing := false}}{{range .Data.Files}}{{if .Processing}}{{$processing = true}}{{end}}{{end}}
|
||||
{{if $processing}}
|
||||
<div class="upload-processing-alert" role="status">
|
||||
Some files are still processing. You can share this link now, but processing files will become available shortly.
|
||||
</div>
|
||||
{{end}}
|
||||
{{$single := eq (len .Data.Files) 1}}
|
||||
<div class="badge-row">
|
||||
<span class="badge badge-expiry">Expires {{.Data.ExpiresLabel}}</span>
|
||||
@@ -74,8 +80,8 @@
|
||||
</div>
|
||||
<div class="download-list file-browser is-thumbs" data-file-browser>
|
||||
{{range .Data.Files}}
|
||||
<article class="download-item file-card" data-kind="{{.PreviewKind}}" data-file-context data-preview-url="{{.URL}}" data-view-url="{{.DownloadURL}}?inline=1" data-download-url="{{.DownloadURL}}" data-file-name="{{.Name}}" data-reaction-card data-react-url="{{.ReactURL}}" data-reacted="{{if .Reacted}}true{{else}}false{{end}}">
|
||||
<a class="file-open" href="{{.DownloadURL}}?inline=1"{{if not $single}} target="_blank" rel="noopener noreferrer"{{end}} aria-label="Open {{.Name}}">
|
||||
<article class="download-item file-card {{if .Processing}}is-processing{{end}}" data-kind="{{.PreviewKind}}" {{if not .Processing}}data-file-context data-preview-url="{{.URL}}" data-view-url="{{.DownloadURL}}?inline=1" data-download-url="{{.DownloadURL}}"{{end}} data-file-name="{{.Name}}" data-reaction-card data-react-url="{{.ReactURL}}" data-reacted="{{if .Reacted}}true{{else}}false{{end}}">
|
||||
{{if .Processing}}<div class="file-open" aria-label="{{.Name}} is processing">{{else}}<a class="file-open" href="{{.DownloadURL}}?inline=1"{{if not $single}} target="_blank" rel="noopener noreferrer"{{end}} aria-label="Open {{.Name}}">{{end}}
|
||||
<span class="file-media">
|
||||
{{if .HasThumbnail}}
|
||||
<img class="file-thumb" src="{{.ThumbnailURL}}" alt="" loading="lazy">
|
||||
@@ -86,11 +92,11 @@
|
||||
</span>
|
||||
<span class="file-main">
|
||||
<strong class="file-name" title="{{.Name}}">{{.Name}}</strong>
|
||||
<small>{{.Size}} · {{.ContentType}}</small>
|
||||
<small>{{.Size}} · {{if .Processing}}Processing{{else}}{{.ContentType}}{{end}}</small>
|
||||
</span>
|
||||
<span class="file-type">{{.ContentType}}</span>
|
||||
<span class="file-type">{{if .Processing}}Processing{{else}}{{.ContentType}}{{end}}</span>
|
||||
<span class="file-size">{{.Size}}</span>
|
||||
</a>
|
||||
{{if .Processing}}</div>{{else}}</a>{{end}}
|
||||
{{if not $.Data.Locked}}
|
||||
<div class="file-reaction-dock" data-reaction-dock>
|
||||
<div class="file-reactions" data-reaction-list>
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<div class="form-footer">
|
||||
<p id="file-summary">Choose one or more files to begin.</p>
|
||||
<button class="button button-primary" type="submit">Upload files</button>
|
||||
<button class="button button-danger upload-new-button" type="button" id="new-upload" hidden>New upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user