mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 22:19:42 +02:00
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.
This commit is contained in:
@@ -711,6 +711,22 @@ describe('rich session sidebar', () => {
|
||||
expect(html).toContain('data-i18n-skip');
|
||||
});
|
||||
|
||||
it('carries both absolute stamps on the LINE, not only on the two items', () => {
|
||||
// Below 288px the rail hides `.tab-meta-created` (tab-rail-tight), and a
|
||||
// title on a `display: none` element has no hover target — so a tooltip
|
||||
// living only there means the created stamp is gone, not shrunk. The line
|
||||
// itself has to carry it for the CSS rule's "still reachable" to be true.
|
||||
const { app } = boot({ stored: { sessionListLayout: 'sidebar-rich' } });
|
||||
stubOverview(app);
|
||||
const html = app._sidebarRichMetaHTML(app._sidebarRichRow('s1', SESSION));
|
||||
|
||||
const line = html.slice(0, html.indexOf('>'));
|
||||
expect(line).toContain('class="tab-meta"');
|
||||
expect(line).toContain('title="');
|
||||
expect(line).toContain('First created');
|
||||
expect(line).toContain('working');
|
||||
});
|
||||
|
||||
it('drops the second stamp when the session has never been active', () => {
|
||||
const { app } = boot({ stored: { sessionListLayout: 'sidebar-rich' } });
|
||||
stubOverview(app);
|
||||
@@ -906,6 +922,45 @@ describe('detailed rows in the vertical tab rail', () => {
|
||||
expect(app._sidebarRichClock).toBeTruthy();
|
||||
});
|
||||
|
||||
it('still renders on the first call, when applyTabWrapSettings only sets its baseline', () => {
|
||||
// The pre-paint script stamps the layout attributes; if it THREW it leaves
|
||||
// them on the catch-branch fallbacks and applyTabOrientation() is the first
|
||||
// thing to correct them, with `_tallTabsEnabled` still undefined.
|
||||
// applyTabWrapSettings() renders only when it has a previous value to
|
||||
// compare, so reading "the value changed" as "it rendered" skipped BOTH
|
||||
// renders and left the rows stale.
|
||||
const { win, app } = boot({ stored: { sessionListLayout: 'header', tabOrientation: 'vertical' } });
|
||||
expect(app._tallTabsEnabled).toBeUndefined();
|
||||
expect(win.document.documentElement.getAttribute('data-tab-orientation')).toBeNull();
|
||||
|
||||
app.applyTabOrientation();
|
||||
|
||||
expect(win.document.documentElement.dataset.tabOrientation).toBe('vertical');
|
||||
// The folder row turned on in the same pass, so this is exactly the case
|
||||
// where the two guards could point at each other and neither fires.
|
||||
expect(app._tallTabsEnabled).toBe(true);
|
||||
expect(app._fullRenderSessionTabs).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not render twice when applyTabWrapSettings already did', () => {
|
||||
// The mirror case: a detail flip that turns the folder row off makes
|
||||
// applyTabWrapSettings() re-render, and applyTabOrientation() must not
|
||||
// stack a second full rebuild of the strip on top of it.
|
||||
const { win, app } = railBoot({ tabOrientation: 'vertical', tabRailDetail: 'rich' });
|
||||
expect(app._tallTabsEnabled).toBe(true);
|
||||
(app._fullRenderSessionTabs as unknown as { mockClear(): void }).mockClear();
|
||||
|
||||
win.localStorage.setItem(
|
||||
'codeman-app-settings',
|
||||
JSON.stringify({ sessionListLayout: 'header', tabOrientation: 'vertical', tabRailDetail: 'simple' })
|
||||
);
|
||||
delete (app as unknown as { _cachedAppSettings?: unknown })._cachedAppSettings;
|
||||
app.applyTabOrientation();
|
||||
|
||||
expect(app._tallTabsEnabled).toBe(false);
|
||||
expect(app._fullRenderSessionTabs).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('plumbs the rail detail through the settings UI, the schema and the pre-paint script', () => {
|
||||
expect(INDEX_HTML).toContain('id="appSettingsTabRailDetail"');
|
||||
expect(INDEX_HTML).toContain('<option value="rich">Detailed</option>');
|
||||
|
||||
Reference in New Issue
Block a user