Skip to content

feat: transcription history dashboard (list, filter, sort, download, delete) - #45

Merged
lkmeta merged 8 commits into
mainfrom
feat/history-page
Aug 15, 2026
Merged

lkmeta merged 8 commits into
mainfrom
feat/history-page

Conversation

@lkmeta

@lkmeta lkmeta commented Aug 5, 2026 •

Copy link
Copy Markdown
Owner

Problem

Every transcription is stored in SQLite (status, timestamps, model, language, source) but there was no way to see or manage past jobs — you had to keep the tab open or remember a numeric job id.

Change

A read-only /history dashboard (linked in the nav on every page) that lists past jobs and lets you manage them:

  • Columns: id, when (UTC), source (uploaded filename or a "YouTube" link, full value on hover), duration, model, language (with → target when translated), status, actions.
  • Status filter + stats: a strip of counts (All / Completed / Failed / Canceled) that doubles as a one-click filter.
  • Sort: click any column header (numeric on id/date/duration, text elsewhere).
  • Pagination: 10 per page with Prev/Next, so hundreds of jobs stay readable.
  • Download / Delete: clear labeled row actions — Download the .zip, or Delete the job's files + DB row (POST /history/delete, refuses a still-running job). Clear all (POST /history/clear) removes every finished job and keeps running ones.
  • Colored status badges; long Error: … messages truncate with the full text on hover.
  • Retention notice: shows the actual RETENTION_DAYS window.
  • Stable, themed layout: fixed table layout + constant row-slots so filtering/paging changes only the content, never the table's size or shape; the page sits on the app's standard panel color and reads correctly in both light and dark themes.

db.list_jobs() returns recent rows (capped). ENABLE_HISTORY (default True) hides the page + endpoints on a shared deployment, since it lists all jobs by id and the app has no auth.

Evidence

  • pytest — 68 passed: list_jobs order/cap; /history lists a completed job with its download link and model label; delete removes row+files and refuses a running job; clear removes finished jobs but keeps running ones; every history endpoint 404s when ENABLE_HISTORY=False.
  • Rendered against the running container (Playwright): filter/sort/paginate/delete all work; table width and height stay constant across filters and pages; columns evenly proportioned; both light and dark themes readable; 0 JS errors.

lkmeta added 8 commits August 5, 2026 18:06
Add a read-only /history page (linked in the nav) that lists every past job
newest-first from the DB — id, time, duration, model, language, translation,
status, and a .zip download for finished jobs. The data already existed; this
just surfaces it, and retention keeps it bounded.

db.list_jobs() returns recent rows capped at 200. ENABLE_HISTORY (default True)
hides the page on shared deployments, since it lists all jobs by id and the app
has no auth.

Verified: pytest 65 (list_jobs order/cap, /history lists a completed job with
its download link, ENABLE_HISTORY=False -> 404); rendered against the container
(25 rows, download links, theme works, 0 JS errors).
Improve the /history table's usability:
- click any column header to sort (id/date/duration numeric, rest text);
  sorts on raw values (epoch, seconds), not the displayed strings.
- colored status badges (success/error/canceled/in-progress), readable in
  both themes; long "Error: ..." messages truncate with an ellipsis and keep
  the full text in a hover tooltip so they never overflow the table.
- solid panel background, zebra striping, hover, sticky header, one-line dates.

Verified: pytest; rendered in the container — sort by duration/id works, 25
badges render, no badge overflows the table, 0 JS errors, both themes readable.
Make the history table genuinely useful for managing past jobs:
- Source column: show what was transcribed (YouTube URL or uploaded filename),
  truncated with a hover tooltip.
- Delete: a trash button per row (POST /history/delete) removes the job's files
  and DB row; refuses a still-running job (cancel it first). A "Clear all"
  button (POST /history/clear) removes every finished job, keeping running ones.
- Pagination: 10 rows/page with Prev/Next, so hundreds of jobs stay readable;
  works together with column sorting.
- Fix: the header was hidden under the fixed navbar (missing top margin).
- Full status/error text stays available on hover (title tooltip).

Verified: pytest 68 (delete removes row+files, refuses running, clear keeps
running, endpoints 404 when ENABLE_HISTORY=False); rendered in the container —
subtitle clears the navbar, 10/page, source shown, sort works, delete drops a
row (25→24), both themes readable.
Address UX feedback on the history table:
- Actions fit without horizontal scroll: merged Language+Translation into one
  column, compact "YouTube" source link (full URL on hover) + shorter date.
- Clear, labeled row actions: green "Download" and red "Delete" buttons.
- Stat strip that doubles as status filters — click All / Completed / Failed /
  Canceled to filter the table; counts always reflect the full set.
- Moved "Clear all" to the footer next to pagination (out of the way).
- Show the actual retention window (RETENTION_DAYS) in the subtitle.

Verified: pytest; rendered in the container at 1280px — no horizontal scroll,
filter/sort/paginate/delete all work, 0 JS errors, both themes.
Filtering changed the visible rows, so the auto table layout recomputed column
widths and the table visibly "jumped". Use table-layout: fixed with an explicit
colgroup so column widths (and the table shape) stay constant — only the rows
change when you switch stat filters. Model cell truncates with ellipsis.

Verified: table width (1178px) and every column width are byte-identical across
All / Failed / Canceled filters.
A short filter result or last page made the table shorter (the Y axis jumped).
Always render exactly 10 row-slots — pad short pages with empty filler rows —
and pin a uniform row height, so the table keeps the same size and shape and
only its content changes.

Verified: table height (503px) and width (1178px) identical across the All /
Canceled filters and the last (partial) page; always 10 row-slots.
- Light theme was broken: the page background is always the dark hero image
  and only text colors flip, so the subtitle, stat cards and pager (which sat
  directly on the background) turned dark-on-dark. Put the whole history
  content on a theme-flipping panel (dark in dark theme, light in light theme)
  so everything stays readable, and make the stat-number colors theme-aware.
- Balance the columns: give every column a proportional width (Status no longer
  hogs the leftover space), so there are no odd wide/narrow gaps.

Verified: rendered in the container — both themes readable (subtitle, stat
cards, pager, table, badges), columns evenly proportioned.
Match .container/.container_faq by backing the history panel with
var(--background-color-dark) instead of a custom grey, so it's the same
window color as the rest of the app in both themes.
@lkmeta lkmeta changed the title feat: history page listing past transcriptions feat: transcription history dashboard (list, filter, sort, download, delete) Aug 5, 2026
@lkmeta
lkmeta merged commit 5d621eb into main Aug 15, 2026
4 checks passed
@lkmeta
lkmeta deleted the feat/history-page branch August 15, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant