mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-09 00:49:41 +02:00
fix(ui): a described session tab shows just the description (#232)
Reported by @mtiller. A session named `w2-foo-bar: some description` rendered both halves on the tab, so the generated id ate the width that the part the user actually chose needed. The tab now shows the description alone and the `w<n>-<case>` id moves to the tooltip, where it stays available without being read every time. It is still shown in the session settings modal. Undescribed tabs are unchanged. `aria-label` deliberately keeps the FULL name, so screen readers still get the id. Also fixes a re-render loop this exposed: the incremental update compared `nameEl.textContent` against the full name, which for a described tab never matched, so those tabs re-rendered on every pass. The compare now targets the display label. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+22
-8
@@ -3438,14 +3438,19 @@ class CodemanApp {
|
|||||||
statusEl.className = `tab-status ${status}`;
|
statusEl.className = `tab-status ${status}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update name if changed
|
// Update name if changed. #232: a description (the `: suffix` part of the
|
||||||
|
// name) is the whole tab label; the generated id lives in the tooltip. The
|
||||||
|
// compare targets the DISPLAY text, or a described tab would re-render on
|
||||||
|
// every pass (textContent never equals the full name there).
|
||||||
const nameEl = tab.querySelector('.tab-name');
|
const nameEl = tab.querySelector('.tab-name');
|
||||||
if (nameEl && nameEl.textContent !== name) {
|
if (nameEl) {
|
||||||
const _p = parseSessionPrefix(name);
|
const _p = parseSessionPrefix(name);
|
||||||
if (_p && _p.suffix) {
|
const _label = _p && _p.suffix ? _p.suffix : name;
|
||||||
nameEl.innerHTML = '<span class="tab-prefix">' + escapeHtml(_p.prefix) + '</span><span class="tab-suffix">: ' + escapeHtml(_p.suffix) + '</span>';
|
if (nameEl.textContent !== _label) {
|
||||||
} else {
|
nameEl.textContent = _label;
|
||||||
nameEl.textContent = name;
|
tab.title = _p && _p.suffix
|
||||||
|
? (session.workingDir ? `${_p.prefix} (${session.workingDir})` : _p.prefix)
|
||||||
|
: (session.workingDir || '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3617,14 +3622,23 @@ class CodemanApp {
|
|||||||
const tallTabsEnabled = this._tallTabsEnabled ?? false;
|
const tallTabsEnabled = this._tallTabsEnabled ?? false;
|
||||||
const showFolder = tallTabsEnabled && session.name && folderName && folderName !== name;
|
const showFolder = tallTabsEnabled && session.name && folderName && folderName !== name;
|
||||||
|
|
||||||
parts.push(`<div class="session-tab ${isActive ? 'active' : ''}${alertClass}${loadState ? ' tab-loading' : ''}" data-id="${id}" data-color="${color}" ${loadState ? `data-load-phase="${escapeHtml(loadState.phase)}"` : ''} onclick="app.handleSessionTabClick(event, ${escapeHtml(JSON.stringify(id))})" oncontextmenu="event.preventDefault(); app.startInlineRename(${escapeHtml(JSON.stringify(id))})" tabindex="0" role="tab" aria-selected="${isActive ? 'true' : 'false'}" aria-busy="${loadState ? 'true' : 'false'}" aria-label="${escapeHtml(name)} session" ${session.workingDir ? `title="${escapeHtml(session.workingDir)}"` : ''}>
|
// #232: a session with a description (the `: suffix` part of its name) shows
|
||||||
|
// JUST the description on the tab; the generated w<n>-<case> id moves to the
|
||||||
|
// tooltip and stays visible in the session settings modal.
|
||||||
|
const parsedName = parseSessionPrefix(name);
|
||||||
|
const tabLabel = parsedName && parsedName.suffix ? parsedName.suffix : name;
|
||||||
|
const tabTooltip = parsedName && parsedName.suffix
|
||||||
|
? (session.workingDir ? `${parsedName.prefix} (${session.workingDir})` : parsedName.prefix)
|
||||||
|
: (session.workingDir || '');
|
||||||
|
|
||||||
|
parts.push(`<div class="session-tab ${isActive ? 'active' : ''}${alertClass}${loadState ? ' tab-loading' : ''}" data-id="${id}" data-color="${color}" ${loadState ? `data-load-phase="${escapeHtml(loadState.phase)}"` : ''} onclick="app.handleSessionTabClick(event, ${escapeHtml(JSON.stringify(id))})" oncontextmenu="event.preventDefault(); app.startInlineRename(${escapeHtml(JSON.stringify(id))})" tabindex="0" role="tab" aria-selected="${isActive ? 'true' : 'false'}" aria-busy="${loadState ? 'true' : 'false'}" aria-label="${escapeHtml(name)} session" ${tabTooltip ? `title="${escapeHtml(tabTooltip)}"` : ''}>
|
||||||
${_tabIdx < 9 ? '<span class="tab-number">' + (_tabIdx + 1) + '</span>' : ''}
|
${_tabIdx < 9 ? '<span class="tab-number">' + (_tabIdx + 1) + '</span>' : ''}
|
||||||
${loadState ? '<span class="tab-load-spinner" aria-hidden="true"></span>' : ''}
|
${loadState ? '<span class="tab-load-spinner" aria-hidden="true"></span>' : ''}
|
||||||
<span class="tab-status ${status}" aria-hidden="true"></span>
|
<span class="tab-status ${status}" aria-hidden="true"></span>
|
||||||
<span class="tab-info">
|
<span class="tab-info">
|
||||||
<span class="tab-name-row">
|
<span class="tab-name-row">
|
||||||
${mode === 'shell' ? '<span class="tab-mode shell" aria-hidden="true">sh</span>' : mode === 'opencode' ? '<span class="tab-mode opencode" aria-hidden="true">oc</span>' : mode === 'codex' ? '<span class="tab-mode codex" aria-hidden="true">cx</span>' : mode === 'gemini' ? '<span class="tab-mode gemini" aria-hidden="true">gm</span>' : mode === 'antigravity' ? '<span class="tab-mode antigravity" aria-hidden="true">ag</span>' : ''}
|
${mode === 'shell' ? '<span class="tab-mode shell" aria-hidden="true">sh</span>' : mode === 'opencode' ? '<span class="tab-mode opencode" aria-hidden="true">oc</span>' : mode === 'codex' ? '<span class="tab-mode codex" aria-hidden="true">cx</span>' : mode === 'gemini' ? '<span class="tab-mode gemini" aria-hidden="true">gm</span>' : mode === 'antigravity' ? '<span class="tab-mode antigravity" aria-hidden="true">ag</span>' : ''}
|
||||||
<span class="tab-name" data-session-id="${id}">${(() => { const p = parseSessionPrefix(name); return p && p.suffix ? '<span class="tab-prefix">' + escapeHtml(p.prefix) + '</span><span class="tab-suffix">: ' + escapeHtml(p.suffix) + '</span>' : escapeHtml(name); })()}</span>
|
<span class="tab-name" data-session-id="${id}">${escapeHtml(tabLabel)}</span>
|
||||||
<span class="tab-detached-badge" aria-hidden="true">detached</span>
|
<span class="tab-detached-badge" aria-hidden="true">detached</span>
|
||||||
</span>
|
</span>
|
||||||
${showFolder ? `<span class="tab-folder">\u{1F4C1} ${escapeHtml(folderName)}</span>` : ''}
|
${showFolder ? `<span class="tab-folder">\u{1F4C1} ${escapeHtml(folderName)}</span>` : ''}
|
||||||
|
|||||||
@@ -1383,15 +1383,6 @@ html[data-line-anim="packet"] .connection-line.line-enter {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.session-tab .tab-prefix {
|
|
||||||
color: var(--text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.session-tab .tab-suffix {
|
|
||||||
color: var(--text);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tab folder path — hidden by default, shown via .tabs-show-folder on container */
|
/* Tab folder path — hidden by default, shown via .tabs-show-folder on container */
|
||||||
.session-tab .tab-folder {
|
.session-tab .tab-folder {
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user