Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
84185e1
feat: retry failed downloads with backoff, then remove them
khaosdoctor Nov 8, 2026
cba691e
fix(ui): wrap long file names in the downloads table
khaosdoctor Nov 8, 2026
69b5e36
feat(ui): add bulk retry, cancel and delete to the downloads table
khaosdoctor Nov 8, 2026
e48df7b
feat(ui): show the version in the sidebar and link the repository in …
khaosdoctor Nov 8, 2026
0039385
fix(ui): show the release version instead of the package.json one
khaosdoctor Nov 8, 2026
033e03c
feat: stream live download progress, speed and ETA
khaosdoctor Nov 8, 2026
bf652ca
feat: track uploads to peers and show them in the UI
khaosdoctor Nov 8, 2026
1bb8b73
perf: serve uploads zero-copy and take bytes and duration from a peer…
khaosdoctor Nov 8, 2026
d0f2b89
fix: address review feedback on failed-download cleanup and upload tr…
khaosdoctor Nov 8, 2026
b81d506
fix: stop the reaper when switched off mid-pass, contain upload track…
khaosdoctor Nov 8, 2026
75ef320
fix: coalesce every change source into one snapshot per second per st…
khaosdoctor Nov 8, 2026
0f0f954
fix: subscribe the overview stream to connectors through their object
khaosdoctor Nov 8, 2026
68d3a07
feat: record catalog size and import time history and serve dashboard…
khaosdoctor Nov 8, 2026
0478b6e
feat(ui): redesign the dashboard with collapsible sections and histor…
khaosdoctor Nov 8, 2026
9322e70
fix: base dashboard upload speed on peer receipts and regenerate the …
khaosdoctor Nov 8, 2026
3fefc90
fix: regenerate the dashboard history migration on top of the uploads…
khaosdoctor Nov 9, 2026
1f98365
fix: build the overview from SQL totals and cap receipts at the reque…
khaosdoctor Nov 9, 2026
8f6bbe5
Merge branch 'feat/downloads-uploads' into feat/dashboard
khaosdoctor Nov 9, 2026
3d5f676
fix: accept an upload receipt only for exactly the requested bytes
khaosdoctor Nov 9, 2026
7dd5282
Merge branch 'feat/downloads-uploads' into feat/dashboard
khaosdoctor Nov 9, 2026
f4a30c0
fix: aggregate dashboard stats in SQL by stable peer ids, show chart …
khaosdoctor Nov 9, 2026
4cf346f
fix(ui): type the line chart's key lookup explicitly
khaosdoctor Nov 9, 2026
366c06f
feat(stats): serve dashboard history for a selectable range
khaosdoctor Nov 9, 2026
be5b88a
feat(ui): add a history range picker and mirrored activity charts to …
khaosdoctor Nov 9, 2026
785a9ff
refactor: track uploads as idempotent peer transfers and derive downl…
khaosdoctor Nov 9, 2026
3a44b6c
fix(stats): carry the previous day's catalog reading into short ranges
khaosdoctor Nov 9, 2026
45ef03f
Merge branch 'feat/downloads-uploads' into feat/dashboard
khaosdoctor Nov 9, 2026
ffca03e
fix: build the transfer URL locally, clear stale download speeds, rec…
khaosdoctor Nov 10, 2026
2b7f5fa
Merge branch 'feat/downloads-uploads' into feat/dashboard
khaosdoctor Nov 10, 2026
55f3b03
fix: keep the original uploads migration and convert the table in a n…
khaosdoctor Nov 10, 2026
c6b9590
Merge branch 'feat/downloads-uploads' into feat/dashboard
khaosdoctor Nov 10, 2026
1f1a758
fix: date the dashboard history migration after the upload transfers one
khaosdoctor Nov 10, 2026
4a65459
fix(db): wait on a busy SQLite lock instead of failing
khaosdoctor Nov 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ jobs:
push: true
tags: ${{ steps.meta-ui.outputs.tags }}
labels: ${{ steps.meta-ui.outputs.labels }}
# Shown in the UI. Same value as the image's org.opencontainers.image.version
# label: `1.2.3` on a v* tag, `main` or `pr-<n>` otherwise.
build-args: |
APP_VERSION=${{ steps.meta-ui.outputs.version }}
cache-from: type=gha,scope=ui
cache-to: type=gha,mode=max,scope=ui

Expand Down
21 changes: 21 additions & 0 deletions apps/backend/drizzle/0014_uploads.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
CREATE TABLE `uploads` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`peer_name` text NOT NULL,
`peer_key_id` integer,
`item_id` text NOT NULL,
`filename` text NOT NULL,
`total_bytes` integer NOT NULL,
`range_start` integer DEFAULT 0 NOT NULL,
`requested_bytes` integer NOT NULL,
`sent_bytes` integer DEFAULT 0 NOT NULL,
`duration_ms` integer,
`status` text NOT NULL,
`error` text,
`started_at` text NOT NULL,
`updated_at` text NOT NULL,
`finished_at` text,
CONSTRAINT "uploads_status_check" CHECK("uploads"."status" in ('uploading', 'completed', 'aborted', 'unconfirmed'))
);
--> statement-breakpoint
CREATE INDEX `uploads_status_idx` ON `uploads` (`status`);--> statement-breakpoint
CREATE INDEX `uploads_started_at_idx` ON `uploads` (`started_at`);
29 changes: 29 additions & 0 deletions apps/backend/drizzle/0015_upload_transfers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_uploads` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`transfer_id` text NOT NULL,
`idempotency_key` text NOT NULL,
`peer_name` text NOT NULL,
`peer_key_id` integer,
`item_id` text NOT NULL,
`filename` text NOT NULL,
`total_bytes` integer NOT NULL,
`range_start` integer,
`sent_bytes` integer DEFAULT 0 NOT NULL,
`duration_ms` integer,
`status` text NOT NULL,
`started_at` text NOT NULL,
`updated_at` text NOT NULL,
`finished_at` text,
CONSTRAINT "uploads_status_check" CHECK("__new_uploads"."status" in ('uploading', 'completed', 'unconfirmed'))
);
--> statement-breakpoint
INSERT INTO `__new_uploads`("id", "transfer_id", "idempotency_key", "peer_name", "peer_key_id", "item_id", "filename", "total_bytes", "range_start", "sent_bytes", "duration_ms", "status", "started_at", "updated_at", "finished_at") SELECT "id", lower(hex(randomblob(16))), 'legacy:' || "id", "peer_name", "peer_key_id", "item_id", "filename", "total_bytes", "range_start", "sent_bytes", "duration_ms", CASE WHEN "status" = 'aborted' THEN 'unconfirmed' ELSE "status" END, "started_at", "updated_at", "finished_at" FROM `uploads`;--> statement-breakpoint
DROP TABLE `uploads`;--> statement-breakpoint
ALTER TABLE `__new_uploads` RENAME TO `uploads`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `uploads_transfer_id_unique` ON `uploads` (`transfer_id`);--> statement-breakpoint
CREATE UNIQUE INDEX `uploads_idempotency_key_unique` ON `uploads` (`idempotency_key`);--> statement-breakpoint
CREATE INDEX `uploads_status_idx` ON `uploads` (`status`);--> statement-breakpoint
CREATE INDEX `uploads_started_at_idx` ON `uploads` (`started_at`);--> statement-breakpoint
ALTER TABLE `downloads` ADD `speed_bps` integer;
10 changes: 10 additions & 0 deletions apps/backend/drizzle/0016_dashboard_history.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE `catalog_size_history` (
`day` text NOT NULL,
`source_id` text NOT NULL,
`source_name` text NOT NULL,
`titles` integer NOT NULL,
`bytes` integer NOT NULL,
PRIMARY KEY(`day`, `source_id`)
);
--> statement-breakpoint
ALTER TABLE `downloads` ADD `imported_at` text;
Loading