Skip to content

feat(web): a Done section that keeps the last 7 days - #65

Merged
ANT1OFF merged 1 commit into
mainfrom
feat/done-section
Nov 2, 2026
Merged

ANT1OFF merged 1 commit into
mainfrom
feat/done-section

Conversation

@ANT1OFF

@ANT1OFF ANT1OFF commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

The overview's Done today only showed what finished since local midnight, so finished work vanished overnight. It is now Done, and keeps the last 7 days.

Overview → Done

  • Renamed from "Done today". It stays last in the column, starts folded, and its rows open the thread as before.
  • Lists finished work from the last 7 days (today plus the six days before, cut at local midnight), latest first, under day headings: "Today", "Yesterday", then the weekday and date in the app's existing style (dayLabel, as Outputs uses: "Fri 30 Oct"). Row times are 24-hour.
  • Shows the first 10 rows. When there are more, a quiet "Show all in Workers (⌘J)" link opens ⌘J scrolled to its Done list, with the first row selected. The key in the label follows the user's binding.
  • The count is everything in the 7-day window, not just the 10 rows shown.

⌘J Workers

  • "Done today" and "Earlier" are now one Done section, with the same day headings and then features within each day. It keeps all the history Earlier had, older than 7 days included. "Now" is unchanged.
  • Finished work with no time on record goes last, under "Earlier", so it doesn't show up as 1 Jan 1970.

Archived and merged workers

  • Archiving (archive_thread parks the thread) never removed a worker from the done lists. The ledger the web reads keeps parked workers as state archived, and the model already counted them as done. Workers closed with their worktree come from orchestrator.finishedWorkers and show as before. Both are in Done for their 7 days, and the tests now cover it.
  • New: a worker archived after its PR merged now shows merged (glyph and merged api#412) instead of a bare "archived", using the ledger's stateBase.

Not included

  • Solo threads. Finished solo threads already have a place: the folded "Done" line under Solo threads. Adding them here would list them twice, so Done stays workers-only.
  • Persisted section id. The id stays doneToday. It is stored in the layout store and synced as Settings.layout.overviewSections.doneToday in the contracts schema, and renaming it would reset users' fold and hide choices. Only the label, component and model names changed (OverviewDone, doneRows, DoneRow, WorkersTab "done").
  • One workspace in ⌘J. The overview's Done covers every workspace, but ⌘J lists the workspace in front of you, so "Show all" opens that workspace's Done (as ⌘J always has).
  • Day headings in ⌘J. The now line stays as it was (merged 12 Oct before today) because the worker header and the finished-worker view show it outside any day heading. Under ⌘J's day headings the date repeats the heading.
  • No server change. The web already had every timestamp it needed.

Checks run (all synthetic, against the mock API; no live provider):

  • bun run typecheck: pass
  • bunx vitest run src/orchestration src/stores/side-panels.test.ts src/views src/settings src/settings-sync: 85 files, 765 tests, pass. New model tests cover the midnight boundary, Yesterday, the 7-day cutoff (in and out by one minute), DST-safe daysBefore, an archived-after-merge worker still in Done and reading merged, closed workers on their days, and undated rows last.
  • bunx playwright test e2e/orchestration.spec.ts e2e/overview-sidebar.spec.ts e2e/overview-extras.spec.ts e2e/workers-list.spec.ts: 73 pass, including a new "Done shows its first ten rows, and Show all opens ⌘J on its Done".
  • bun run lint, bun run fmt:check, bun run check:scaffold: pass
  • I did not run the full bun run check; the merge gate runs it.

Known limits and anything left untested: no live-provider run. perf-views.spec.ts only had its profiler name renamed (OverviewDone) and was not run, since it needs GRAM_PERF_VIEWS=1.

Screenshots

The overview at 1440 px with Pull requests and Done opened (dark)

Before After
overview-sidebar-extras-dark before overview-sidebar-extras-dark after

The overview at 1440 px with Pull requests and Done opened (light)

Before After
overview-sidebar-extras-light before overview-sidebar-extras-light after

The overview's Done opened on a busy week: its days, ten rows and Show all (dark)

Before After
overview-done-week-dark before overview-done-week-dark after

The overview's Done opened on a busy week: its days, ten rows and Show all (light)

Before After
overview-done-week-light before overview-done-week-light after

⌘J scrolled to its earlier days (Earlier before Done took it in), with its search (dark)

Before After
workers-list-earlier-dark before workers-list-earlier-dark after

⌘J's Done (Done today before), with a worker whose worktree was cleaned up (dark)

Before After
workers-list-done-today-dark before workers-list-done-today-dark after

The overview's Done today becomes Done: the last seven days of finished work,
latest first under Today, Yesterday and dated day headings, ten rows and then
Show all in Workers, which opens ⌘J on its Done. ⌘J merges Done today and
Earlier into one Done section with the same day headings and all the history
Earlier had. Workers archived after their PR merged stay in Done and read
merged.
@ANT1OFF
ANT1OFF merged commit 8c7bd49 into main Nov 2, 2026
22 checks passed
@ANT1OFF
ANT1OFF deleted the feat/done-section branch November 2, 2026 00:03
ANT1OFF added a commit that referenced this pull request Nov 2, 2026
The user asked for Done to show every past chat, not the last 7 days.
Done now lists **every finished chat**: workers and the solo threads
marked done, all the way back. It also gets a **group-by choice in its
header: Date (the default) or Orchestrator**. The choice is remembered,
and ⌘J's Done has the same choice.

**What Done holds**
- Every finished worker in every workspace, as ⌘J lists them: merged,
delivered, done, archived, and closed with their worktree (from the
reopen list, then the transcript archive, back to the oldest transcript
the archive keeps, up to 500 per workspace).
- Solo threads marked done, mixed in with the workers by when they
finished. "Finished" means what the old Solo threads → Done line used
(`doneSoloThreads`: `completedAt` set, settled, not parked). That line
is gone, so finished chats are in one place. A solo row keeps its
right-click menu (Reopen etc.) and can still be dragged into a pane.
- Times: workers use the same time ⌘J already used (thread
`completedAt`, else last report, else last activity; closed workers use
`closedAt`). Solo threads use `completedAt`, which `doneSoloThreads`
guarantees. The code falls back to `lastActivityAt` only in case it's
ever missing.

**Grouping** (one icon in the Done header. Its hover says "Group by
date" or "Group by orchestrator", and a click opens a menu with both)
- **Date** (default): Today, Yesterday, then weekday and date ("Fri 30
Oct") for the last 7 days, then by month ("October 2026"). Rows show
24-hour times within the week and the date ("6 Oct", or "31 Dec 2025" in
another year) under month headings.
- **Orchestrator**: one group per workspace, named as the overview names
it, plus **Solo threads**. The group with the latest finished item comes
first, and rows are latest first within each group. Each row shows its
time today, else its date.
- The choice is saved in the layout store (`doneGrouping`, persisted
with the window's layout like `reviewRequestsGrouped`). The overview and
⌘J share it.

**Paging: paginated, not virtualized**
- Done still starts folded. Opened, it shows 30 rows. A quiet **Show
more** adds 30 more each time.
- Paging runs **across the whole list**, not per group (the simpler
option): the page cuts wherever row 30 falls, even inside a group.
- The data: the web already gets every live thread in the snapshot, with
no time cut, so ledger workers and solo threads were all there. But
`orchestrator.finishedWorkers` only returned the reopen list plus the
newest **50** archive-only workers per workspace, while the archive
keeps up to 500. New additive RPC: **`orchestrator.finishedWorkersPage {
workspaceId, after? } → { workers, next? }`**. Its first page is exactly
what `finishedWorkers` returns. Later pages are the next 50 archive
transcripts past an exact `(archivedAt, threadId)` cursor, so nothing
repeats or gets skipped, even when timestamps tie. The old RPC is
unchanged.
- The web reads only a workspace's first page up front. It asks for the
next page only when "Show more" reaches rows a later page could come
before (`doneWindow`). Until that page arrives, those rows are held
back, so loading never puts a row above ones already shown.
- **"Show all in Workers (⌘J)" is removed.** Done now has everything,
across all workspaces, while ⌘J shows only one workspace, so the link no
longer added anything.
- The count in the header is everything loaded so far. When older
archive pages haven't been read yet, it grows as you page.

**⌘J**
- Done has the same grouping control and groups as the overview, solo
threads included (shown as a "Solo threads" feature by date, or their
own group by orchestrator). Workers stay sub-grouped by feature inside
each group. Same 30-row pages with Show more. Search filters all loaded
rows. An archived worker's line now carries its date ("archived 3 Oct").

**Not included / known limits**
- When Done is turned off in Settings → General, solo threads marked
done aren't listed anywhere in the overview, because the separate solo
Done line is gone. They can still be found through search and ⌘K.
- The persisted section id stays `doneToday`, as in #65, so users keep
their fold and hide settings.
- The cursor struct is written inline in the RPC payload. Using the
named `FinishedWorkersCursor` schema there made every RPC client type
collapse (TS2722 across the web). The response type uses the named
schema. There's a comment at the spot.

### Checks (all synthetic, against the mock API; no live provider)
- `bun run typecheck`: pass
- `bun run lint`, `bun run fmt:check`, `bun run check:scaffold`: pass
- vitest, web `src/orchestration src/views src/stores src/settings
src/settings-sync src/api`: 118 files, 1030 tests, pass. New
`done-model.test.ts` covers date grouping (days, months, other years,
undated last), orchestrator grouping and its ordering, solo and worker
interleaving, paging across the list, holding rows back for an unread
page in both groupings, choosing which workspace to load, and a
workspace with nothing loaded yet. `overview-extras-model.test.ts` and
`workers-model.test.ts` were updated (no time window, solo rows, month
headings, `soloWorkerRow`, `doneFeatures`, `searchRows`).
- vitest, server `finished-workers.test.ts` (new test: 120 transcripts
with non-worker ones and same-millisecond ties, paged in 3 pages, no
repeats or skips, with live and reopen-list workers excluded) plus
`service-wakes.test.ts`: pass. Contracts: 48 files, 551 tests, pass.
- Playwright `orchestration, overview-sidebar, sidebar-virtual, grid,
grid-ergonomics, drag-to-workspace, thread-actions, overview-extras,
workers-list, reaching-workers`: all pass. New cases: Show more paging
through 120 archived workers from a new mock scenario
(`simulateLongHistory`), Orchestrator grouping in the overview and in
⌘J, and the choice persisting.
- `smoke.spec.ts` "streams a scripted thread…" **fails, and fails the
same way on main (8c7bd49)** in a separate checkout. That's unrelated to
this change. Its other test passes.
- I didn't run the full `bun run check`; the merge gate runs it.
`perf-views.spec.ts` was not run (it needs `GRAM_PERF_VIEWS=1`).

### Screenshots

The pr-shots clock is fixed to mid-June, so the headings read June
dates.

**The overview at 1440 px with Pull requests and Done opened** (dark)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/c385bc20-d7b2-4184-8555-1d82050f9ed7)
|
![after](https://github.com/user-attachments/assets/59dc94b0-ef12-4a4c-ba25-deb85bec8754)
|

**The overview at 1440 px with Pull requests and Done opened** (light)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/2f073da0-db38-473b-aaf2-b7d229a5a3a5)
|
![after](https://github.com/user-attachments/assets/bdc0fa55-cda5-45b0-887c-2dc934fc47f8)
|

**Done opened on a busy week: 10 rows and Show all before; days, a page
of 30 and Show more after** (dark)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/d1c14096-c1b6-490e-a99c-f0588af3bfd4)
|
![after](https://github.com/user-attachments/assets/5bba4fbb-03e9-4c00-a6c7-6979aa6a1eff)
|

**The same** (light)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/56148111-e76e-4c6d-b222-dd976523c20d)
|
![after](https://github.com/user-attachments/assets/140b9f92-2772-43c0-8ca4-547ef49bbfb9)
|

**Solo threads: a Done line under it before; only Parked after (the done
ones are in Done)** (dark)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/70619b97-2387-4a37-8f98-f9912c37d795)
|
![after](https://github.com/user-attachments/assets/0c2c1895-e45d-498c-aac5-37921a721481)
|

**The same** (light)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/ce4ef9e7-a721-4f85-bc17-0f953cf765f3)
|
![after](https://github.com/user-attachments/assets/9f9fdf22-767e-49be-b36c-d74281e8ac9f)
|

**Done on a long history (120 archived workers), Show more pressed
twice: month groups** (after only)

| Dark | Light |
| --- | --- |
|
![dark](https://github.com/user-attachments/assets/bbd0c1af-4a2b-4ce2-ad71-0f6e2168344c)
|
![light](https://github.com/user-attachments/assets/9fb8b2fa-1628-47cc-8275-55ece4d9f48a)
|

**Done grouped by orchestrator, with the group-by menu open** (after
only)

| Dark | Light |
| --- | --- |
|
![dark](https://github.com/user-attachments/assets/1f1d49a7-0e82-4b47-9ad6-c98fcc614f53)
|
![light](https://github.com/user-attachments/assets/18b301d9-694d-4e50-aa52-752555a2ad07)
|

**⌘J scrolled to Done's oldest group, with its search** (dark)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/89c4eec0-e1c4-4c2b-88c1-9802792129bc)
|
![after](https://github.com/user-attachments/assets/e9822f4d-3c86-48a2-914d-0010ff762970)
|

**⌘J's Done, with a worker whose worktree was cleaned up** (dark)

| Before | After |
| --- | --- |
|
![before](https://github.com/user-attachments/assets/3b4d896d-4ce8-4dcc-9d88-5e68ac568ff3)
|
![after](https://github.com/user-attachments/assets/03167519-da0f-4f0a-a354-8ffaf42f3f1e)
|

**⌘J's Done grouped by orchestrator: the workspace, then the solo
threads** (dark, after only)


![after](https://github.com/user-attachments/assets/dce67f1b-0ad5-4dd4-b21a-7acc805d4108)
ANT1OFF added a commit that referenced this pull request Nov 2, 2026
Desktop release metadata proposal only. Merging this PR does not publish
or tag Gram; follow docs/RELEASING.md to release.
---


## [1.4.0](v1.3.1...v1.4.0)
(2026-11-02)


### Features

* **agents:** identify Gram's Claude processes as the gram entrypoint
([#91](#91))
([f7dd703](f7dd703))
* **desktop:** run on Linux
([#82](#82))
([1d37deb](1d37deb))
* **desktop:** turn voice input off on Linux with one check
([#79](#79))
([470ff8b](470ff8b))
* **orchestration:** a person's PR comment wakes the worker that owns it
([#86](#86))
([19bdc1c](19bdc1c))
* **orchestration:** a wrap-up turn when a worker stops without
reporting ([#88](#88))
([36a07fb](36a07fb))
* **orchestration:** workers say what they ruled out and check before
repeating ([#90](#90))
([8bdce01](8bdce01))
* **release:** publish and update Linux AppImage and .deb
([#95](#95))
([c33c464](c33c464))
* **voice:** an accurate mode with a Parakeet pass on each pause
([#83](#83))
([2b04a52](2b04a52))
* **voice:** hold one key to talk, with a tone at each end
([#87](#87))
([1a9b3ef](1a9b3ef))
* **voice:** start capture at the press, and an opt-in ready microphone
([#81](#81))
([505d240](505d240))
* **web:** a Done section that keeps the last 7 days
([#65](#65))
([8c7bd49](8c7bd49))
* **web:** Done lists every finished chat
([#67](#67))
([c91d9ac](c91d9ac))
* **web:** one attention count, quieter rows, a sidebar and board that
agree ([#92](#92))
([f193da4](f193da4))
* **web:** orchestrator → workers in the sidebar, a board that matches
([#80](#80))
([686e737](686e737))


### Bug Fixes

* **desktop:** harden the Linux key vault and autostart entry
([#85](#85))
([4b35eac](4b35eac))
* **e2e:** hold the t-flaky turn while the smoke test reads its opening
line ([#93](#93))
([2edc4ac](2edc4ac))
* **e2e:** release the dictation tap as soon as a word is heard
([#94](#94))
([7781194](7781194))
* prepare only approved local-check sources
([#32](#32))
([af3fab7](af3fab7))
* repair main after [#32](#32)
([#68](#68))
([ce352e6](ce352e6))
* **voice:** keep the last word after release
([#78](#78))
([cc40a47](cc40a47))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: gram-release-please[bot] <351321620+gram-release-please[bot]@users.noreply.github.com>
Co-authored-by: Johan <32440065+ANT1OFF@users.noreply.github.com>
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