mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
master
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
14de2b7012 |
fix(tabs): keep the created stamp reachable on a tight rail, and do not skip the first render
Two review nits on the vertical rail's detailed rows. 1. The tab-rail-tight rule (below 288px) hides `.tab-meta-created`, and its comment claimed the value "survives in the row's title attribute either way". It did not: the only title carrying it lived ON that element, and a `display: none` element has no hover target, so the created stamp was not shrunk but gone with no way to ask for it. Rather than just correcting the comment, `_sidebarRichMetaHTML()` now puts BOTH absolute stamps on the `.tab-meta` line itself, so the pill and the gaps around the stamps remain as hover targets. An item's own title still wins where the item is visible. 2. applyTabOrientation() decided whether applyTabWrapSettings() had already re-rendered by comparing `_tallTabsEnabled` before and after. That reads an UNDEFINED previous value as "it rendered", but applyTabWrapSettings() deliberately renders nothing on its first call ever (it only establishes the baseline: `prevTallTabs !== undefined && prevTallTabs !== showFolder`). So on a first call that also flips the folder row, neither function rendered and the rows stayed stale. Reachable when the pre-paint script throws and leaves the layout attributes on their catch-branch fallbacks for applyTabOrientation() to correct. The guard now mirrors applyTabWrapSettings()'s own condition. Both new tests were run against the unfixed code first and fail there, which is the only thing that makes them regression tests. (The third, "does not render twice", passes either way by design: it pins that fix 2 did not introduce a double rebuild.) Verified in a real browser against a live server with two sessions, driving the narrowing through _setTabRailWidth() the way the resize drag does: at the 320 default the row reads "CREATED 2m ago · IDLE <1m" with the created element displayed; at 256 the tight class is on, the created element computes to display:none, the visible text drops to "IDLE <1m", and the meta line's title still reads "First created: ...". At 220 the compact threshold drops rich rows entirely. Screenshots confirm no truncation artifacts in either state. Full gate green (6104 passed), typecheck, lint, format, frontend-syntax and public-assets all clean. |
||
|
|
b330f1d9e8 |
feat(tabs): give the vertical rail the home screen's per-session detail
The vertical tab rail (tabOrientation 'vertical') listed names and nothing
else, while the rich sidebar and both home screens already answered the
question a docked column exists to answer: which of these sessions wants me
next, and how long has it been like that. The rail is a docked column too, so
it now draws the same row.
- New per-device setting tabRailDetail ('rich' | 'simple', default rich),
App Settings -> Appearance -> Tabs, in SettingsUpdateSchema + displayKeys and
stamped as data-tab-rail-detail by the pre-paint script, so a detailed rail
does not flash through simple rows on every load.
- ONE gate for both vertical surfaces: isRichTabRows() =
isSessionSidebarRich() || isTabRailRich(). The row model, the markup and the
20s in-place clock are the existing rich-sidebar ones, classified by
_mobileOverviewState/_mobileOverviewSince, so the rail, the sidebar, the
desktop home rail and the phone overview cannot disagree about what
"working" means or which stamp measures it.
- Detail rides on its OWN attribute, exactly as the sidebar's does, so every
existing [data-tab-orientation='vertical'] rule keeps matching both variants
untouched. A flip of detail ALONE still forces a full render (the stamps line
is emitted by the row template, not toggled by CSS) and re-runs
applyTabWrapSettings(), which owns the folder line and is now rail-aware.
- CSS: every rich paint rule gains a rail twin as a COMMA-GROUPED selector,
never :is() - an :is() list takes its most specific argument, which would
lift the sidebar arm from (0,3,1) to the rail's (0,5,1) and let these rules
outrank things they never used to.
- Width is why there are thresholds. At 256px the stamps line ellipsizes
mid-word, the same reason the rich sidebar is 300px, so a rail that has never
been sized defaults to 320 (RICH_DEFAULT_WIDTH, the existing Wide preset,
which also keeps the settings select on a named choice). A width the user has
chosen is never overridden: below 288px the created stamp is dropped rather
than truncated (tab-rail-tight, CSS only) and below 240px the rows go back to
simple (tab-rail-compact, which re-renders).
- The rich clock is armed and disarmed by applyTabOrientation() as well as
applySessionListLayout(); a leaked interval would rewrite stamps in a list
that no longer has any.
Also fixes a data-loss bug in the inline tab rename that predates the rail and
reproduces in every layout, header strip included: Escape set the input to ''
and blurred it, and the blur handler commits - so cancelling a rename PUT an
empty name, and the tab fell back to its folder label (measured against a live
server: ["rail-alpha","","rail-gamma"]). Escape now calls cancelRename(), which
invalidates the edit so the blur that follows the input's removal is a no-op.
Tests: rail-detail gate, the three ways it turns back off (simple, compact,
horizontal), sidebar-wins, render-on-detail-flip and the plumbing/CSS guards in
test/session-list-layout.test.ts; the rename cancel in test/inline-rename.test.ts
(browser suite), pinned by running it against the old code first. Verified live
against a real server on an isolated instance: detailed/simple/compact/header/
sidebar variants, click-select, the ... menu, inline rename, Alt+N, the in-place
stamp tick and a full settings-picker round-trip including reload.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
e3a2fb767f | feat(tabs): COD-358 add resizable vertical session rail | ||
|
|
98e37bf895 |
feat(sidebar): add a rich session sidebar that carries the home screen's row detail
Session List Layout gains a third option. The old "Left sidebar" becomes "Left sidebar simple" and is unchanged down to the byte; the new "Left sidebar" puts on each row what the desktop home rail and the phone overview already show: when the session was first created, how long it has been in the state it is in, and a status pill naming that state. A docked column is not a tab strip. It has width to spare and a row per session either way, and "name + folder" is the whole story a TAB can tell, not the whole story there is. This is the information that was missing, and it already existed one surface over. Both sidebar values are the same layout, and both set data-session-list="sidebar"; the row detail rides on a separate data-sidebar-detail attribute. That split is the load-bearing decision here: every one of the ~25 isSessionSidebarActive() call sites and every html[data-session-list="sidebar"] rule in styles.css and mobile.css keeps matching both variants without being touched. A third data-session-list value would have meant auditing and editing all of them. - Stored values: 'header', 'sidebar' (simple), 'sidebar-rich'. Anyone already on 'sidebar' keeps exactly the layout they picked — the rename is label-only. - State classification and the "how long has it been like this" anchor come from _mobileOverviewState() / _mobileOverviewSince(), not re-derived, so the three surfaces cannot disagree about what "working" means. A working pane repaints ~1/s, so its duration is measured from the turn's last Enter: a running turn reads "working 12m", not "0m". - Stamps refresh in place on a 20s clock rather than by re-rendering — a rebuild would restart every load spinner and alert animation in the list, twice a minute. The clock runs only while rich rows are on screen, and is stopped from both render paths and from applySessionListLayout(). - The incremental render path updates the pill, the accent class and the since anchor; a tick alone cannot see a state change, and a new turn re-stamps lastSubmitAt without changing state. - applySessionListLayout() now re-renders on a DETAIL change too. simple <-> rich leaves data-session-list on 'sidebar' both times, and the meta line is emitted by the row template rather than toggled by CSS, so the old layout-only test would have flipped the setting and repainted nothing. - Width: 300px for the extra line. The collapsed 44px rail and the handheld drawer are both explicitly held back from it — the desktop rule is (0,3,1) and would otherwise out-specify mobile.css's (0,2,1) drawer base and pin a 320px phone's drawer to 300px. - Missing/stale mobile-overview.js degrades to a row with no meta line rather than throwing and taking the whole tab strip down. 15 new tests cover the attribute split, the solo-window override, the detail-change re-render, the row model, both render paths, the clock lifecycle and the mobile width guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
24ed43935c |
fix: file-link and session-sidebar review follow-ups from 1.19.0
Five post-merge review items from PRs #306 (clickable file paths) and #307 (session sidebar): - constants.js FILE_PREVIEW_EXTENSIONS gains the media extensions it was missing vs the single-source sets in attachment-registry.ts (m4v ogv ogg oga m4a aac flac opus), so an in-workspace .m4a opens the preview player instead of the log viewer; new test/media-extension-parity.test.ts pins all three copies (constants.js, panels-ui.js, attachment-registry.ts) against each other. - FILE_PATH_LINK_PATTERN drops `etc` from its root alternation: /etc is unconditionally in DEFAULT_BLOCKED_TREES, so every /etc link 403'd. Negative cases added to the link-provider and response-viewer tests. - updateSidebarCount() counts the rows actually on the sidebar list (session rows + web-tab rows, minus filtered-out ones) instead of this.sessions.size, and applySidebarFilter() refreshes it so the count follows the filter box per keystroke. - The incremental-render connection-line gate now also fires in sidebar layout (this._lineageEdgeCount is permanently 0 there), matching the strip-scroll listener widened in #307, so a badge changing row heights redraws subagent/ultracode connectors. - isSensitivePath() blocks ~/.claude.json, ~/.claude/settings.json and ~/.claude/settings.local.json (credential-bearing by schema), anchored to homedir() read at check time so case-level .claude/settings*.json files stay servable in the File Viewer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c01edcbbb8 |
feat(web): optional collapsible left session sidebar
The header tab strip stops working past roughly a dozen sessions: it wraps into two or three rows, eats vertical space and still cannot be scanned. This adds a vertical session list in a left <aside> as an ALTERNATIVE layout — a filter box, a live count, and a 44px collapsed rail that keeps the ambient signal (status dot, task badge) visible. The strip is not removed. Settings -> Display -> Tab Bar -> Session List Layout switches between them and the default stays 'header', so existing users see no change until they opt in. Structure: one #sessionTabs element, two mount points. applySessionListLayout() re-parents the SAME node between #sessionTabsHost and #sessionSidebarList, which is why there is no second renderer and no duplicated wiring — app.$() caches getElementById results and never invalidates them, so a moved node keeps every existing consumer (settings-ui, webview-tabs, the generated gesture bundle, the mobile tests) working untouched. Notable integration points: - Below 1024px the sidebar is an off-canvas drawer overlaying the terminal; closed it gets inert + aria-hidden so it cannot be tabbed into, and touch swipes over it no longer switch sessions. - Subagent and ultracode windows anchor to the right edge of a sidebar row instead of its bottom, connector curves follow. - Alt+B toggles; the chord is gated out of the PTY so xterm cannot also write ESC b into a live session. - Collapse state lives in its own localStorage key (the settings blob is rebuilt from DOM controls on every save) and falls back to in-memory intent where storage throws. Verified: frontend syntax + public asset checks, tsc, eslint, 26 new jsdom tests, and a headless-Chromium harness (scripts/verify-session-sidebar.mts) that renders a synthetic 25-session fleet in both layouts at 1600/1000/393px and asserts mount point, widths, inert/aria state and row count. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |