Export improvements (#22867)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions

* backend

* frontend + i18n

* tests + api spec

* tweak backend to use Job infrastructure for exports

* frontend tweaks and Job infrastructure

* tests

* tweaks

- add ability to remove from case
- change location of counts in case card

* add stale export reaper on startup

* fix toaster close button color

* improve add dialog

* formatting

* hide max_concurrent from camera config export settings

* remove border

* refactor batch endpoint for multiple review items

* frontend

* tests and fastapi spec

* fix deletion of in-progress exports in a case

* tweaks

- hide cases when filtering cameras that have no exports from those cameras
- remove description from case card
- use textarea instead of input for case description in add new case dialog

* add auth exceptions for exports

* add e2e test for deleting cases with exports

* refactor delete and case endpoints

allow bulk deleting and reassigning

* frontend

- bulk selection like Review
- gate admin-only actions
- consolidate dialogs
- spacing/padding tweaks

* i18n and tests

* update openapi spec

* tweaks

- add None to case selection list
- allow new case creation from single cam export dialog

* fix codeql

* fix i18n

* remove unused

* fix frontend tests
This commit is contained in:
Josh Hawkins
2026-04-14 08:19:50 -06:00
committed by GitHub
parent 18c068a3f9
commit e7e6f87682
31 changed files with 6789 additions and 733 deletions
+20 -8
View File
@@ -82,14 +82,26 @@ export class ApiMocker {
route.fulfill({ json: stats }),
);
// Reviews
await this.page.route("**/api/reviews**", (route) => {
const url = route.request().url();
if (url.includes("summary")) {
return route.fulfill({ json: reviewSummary });
}
return route.fulfill({ json: reviews });
});
// Reviews. The real backend exposes /review (singular) for the main
// list and /review/summary for the summary — the previous plural glob
// (**/api/reviews**) never matched either endpoint, so review-dependent
// tests silently ran without data. The POST mutations at /reviews/viewed
// and /reviews/delete (plural) still fall through to the generic
// mutation catch-all further down the file.
await this.page.route(/\/api\/review\/summary/, (route) =>
route.fulfill({ json: reviewSummary }),
);
await this.page.route(/\/api\/review(\?|$)/, (route) =>
route.fulfill({ json: reviews }),
);
// Export jobs. The Exports page polls this every 2s while any export
// is in_progress; without a mock route it falls through to the preview
// server which returns 500 and makes the page flap between loading and
// rendered state, breaking tests that navigate to /export.
await this.page.route("**/api/jobs/export", (route) =>
route.fulfill({ json: [] }),
);
// Recordings summary
await this.page.route("**/api/recordings/summary**", (route) =>