You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b66257c
Browse filesBrowse the repository at this point in the historyBrowse files
feat(webui): the title bar says which checkout you are looking at (#130)
Branch, short sha, and when it landed — a left pair with the title:
the title answers "what am I reading", this answers "which build".
headSha uses git's own abbreviation rather than a fixed seven, so a
large repository lengthens it instead of truncating away the digits
you would paste into git show. headCommittedAt is the committer time,
not the author time: rebase, amend and cherry-pick push the committer
time to now while the author time stays at the first write, so an
author timestamp would show a just-rebased branch as months old.
No polling. One call is one real index refresh, and a checkout's
identity changes on commit or branch switch rather than on a timer;
the relative-time half rides the ticker the title bar already had.
Nothing renders for a non-git directory, an unborn HEAD, or a failed
request — an empty pill is a control that looks useful and says
nothing.
Co-authored-by: s39-dev <s39-dev@local>
Copy file name to clipboardExpand all lines: docs/webui.md
+47Lines changed: 47 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -438,6 +438,52 @@ batch. The Agent Team badge, the `workspaceDir` secondary line and the
438
438
reference's own shell, so they are not implemented here either. A later
439
439
agent must not mistake any of these for "implemented but broken".
440
440
441
+
## Conversation toolbar: the version badge (webui-parity 89)
442
+
443
+
The conversation toolbar's right end of the title row carries a version badge:
444
+
the branch name, the abbreviated commit id, and how long ago that commit
445
+
landed. It answers "which checkout am I looking at" without opening a terminal,
446
+
which is the question a user has when a build behaves unexpectedly and there
447
+
is more than one checkout in play.
448
+
449
+
| State | What renders |
450
+
| --- | --- |
451
+
| Repository with at least one commit |`branch` + `headSha` + relative commit time |
452
+
| Directory that is not a repository | nothing — the whole element is absent from the DOM |
453
+
| Repository with an unborn HEAD (`git init`, nothing committed) | nothing; there is no commit to name |
454
+
| Detached HEAD | the sha alone, with no placeholder word standing in for a branch |
455
+
| Request failed or has not answered yet | nothing |
456
+
457
+
The absent cases are the contract, not an afterthought: an empty pill would be
458
+
a control that looks live and carries no information, so
459
+
`resolveVersionBadge` returns `null` and the component renders an empty
460
+
string. `webapp/test/toolbar-version-badge.test.ts` pins the rendered output
461
+
in both directions.
462
+
463
+
**Placement.** The badge sits at the far end of the title row (`ml-auto`),
464
+
opposite the session title it qualifies, and before that row's `pr-20` reserve
465
+
— so the `fixed right-4` launcher cluster can never overlap it. It follows
466
+
the running-turn indicator when one is showing. The relative time is the only
467
+
part with a narrow-width rule (`hidden lg:inline`): the branch name and the
468
+
sha are what identify a build, so they stay and the time gives way. Long
469
+
branch names truncate rather than pushing the bar wider.
470
+
471
+
**The click copies the short sha.** It is a real `<button>` with an
472
+
`aria-label` and a transient 「已复制」 confirmation, not decorative text. A
473
+
denied clipboard shows no confirmation rather than a confirmation the user
474
+
acts on.
475
+
476
+
**Data and cost.** One `GET /api/git/status` on workspace change — the same
477
+
endpoint the right-panel Git panel reads, not a second source of truth. It
478
+
does not poll: a `git status` on a large tree is a real index refresh, a
479
+
version identity changes when the user commits or checks out a branch rather
480
+
than on a schedule, and the Git panel already sets the precedent of fetching
481
+
on workspace change plus an explicit Refresh. The relative-time half needs no
482
+
refetch at all — it ticks off the toolbar's existing 1s ticker, which the
483
+
elapsed-timer already pays for. While the Git panel is open, two requests for
484
+
the endpoint are in flight; that is accepted rather than hoisting panel state
485
+
into a provider above the shell for a panel the badge does not render.
486
+
441
487
## Context window (what the picker shows, and what a pick does today)
442
488
443
489
The model picker's settings detail renders at **two levels** (ticket 49 batch 2). The panel-bottom area always describes the ACTIVE model; when a provider cascade is open, the fly-out renders as the reference picker's two-column popover — the provider's model rows on the left, a **follow-focus settings column** on the right. Hovering or keyboard-focusing a model row switches that column to the model without picking it; a cascade that just opened (nothing focused yet) falls back to the active model, mirroring the reference. Both areas read the same draft mirror (below), so a window pick made in either place highlights in both.
@@ -475,6 +521,7 @@ below cites the component file and one `data-testid` per surface.
475
521
| Home quick-capability capsules (ticket 55c) |`components/chat.tsx#HomeState`|`home-quick-capabilities`|
| Toolbar (top bar with model selector) |`components/toolbar.tsx`|`toolbar-session-status`|
524
+
| Toolbar version badge (branch + short sha + commit time, webui-parity 89) |`components/version-badge.tsx`|`toolbar-version-badge`|
478
525
| Composer + drop overlay |`components/composer.tsx`|`composer-drop-overlay`, `composer-send-button`|
479
526
| Chat (virtual list ≥ 200 messages) |`components/chat.tsx` + `chat-virtual-list.tsx`|`chat-virtual-top-spacer`|
480
527
| Turn process bar (composite summary + output rate since ticket 46 PR3) |`components/activity-group.tsx#TurnProcessDisclosure`|`turn-process-disclosure`|
@@ -1098,6 +1104,22 @@ zero ahead/behind without an error.
1098
1104
carry `origPath` (the pre-rename path) alongside `path` (the new
1099
1105
path). `isRepo:false` answers a non-git directory without an error.
1100
1106
1107
+
| Field | Meaning |
1108
+
| --- | --- |
1109
+
|`headSha`|`git log -1 --format=%h` — the abbreviated commit id at **git's own** abbreviation length (7 by default, longer where 7 would be ambiguous). Consumers must not hard-code 7. |
1110
+
|`headCommittedAt`|`git log -1 --format=%cI` — HEAD's **committer** time, strict ISO 8601. Committer, not author: a rebase, amend or cherry-pick moves the committer time forward while the author time stays at the original write, so the author time would report a freshly rebased branch as months old. |
1111
+
1112
+
A repository with an unborn HEAD (`git init`, nothing committed yet)
1113
+
answers `ok:true, isRepo:true` with `headSha: null` and
1114
+
`headCommittedAt: null` — the workspace is a healthy repository, it
1115
+
simply has no commit to name. A directory that is not a repository at
1116
+
all omits both fields entirely, and so does a `dir` the containment
1117
+
gate refuses, which lets the toolbar's version badge treat "absent or
1118
+
null" as a single "render nothing" case.
1119
+
1120
+
A detached HEAD still reports `headSha`; `branch` is `null` and the
1121
+
badge shows the sha alone.
1122
+
1101
1123
**Errors** — 400 missing `dir`; the body is `{ok:false, error}` and
1102
1124
the status stays `200` (the panel reads `ok` rather than the HTTP
|`headCommittedAt`|`git log -1 --format=%cI` —— HEAD 的**提交者**时间,严格 ISO 8601。取提交者时间而非作者时间:rebase、amend、cherry-pick 都会把提交者时间推后而作者时间停在最初那次写入,用作者时间会把刚 rebase 过的分支显示成几个月前。 |
0 commit comments