mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
- Hide the new btn-session-manager header button on phones: add it to the @media (max-width: 430px) display:none block in mobile.css (next to .btn-away-digest) and to KNOWN_PHONE_HIDDEN in the mobile-header policy test, closing the recurring phone-header-leak regression that was PR #153's red CI job. - Put the session-manager header button on its own line in index.html (was crammed onto the away-digest line). - app.js: drop session:updated from the unified-list SSE refresh trigger — it is batch-broadcast ~every 500ms per active session and would turn an open modal / visible welcome list into a sustained ~1 Hz full projects rescan loop; created/deleted (structural changes) are sufficient. - terminal-ui.js _fetchUnifiedSessions: check the ApiResponse envelope and throw on failure so a 5xx surfaces via the caller's catch instead of rendering an empty history. - terminal-ui.js _openSessionRowMenu: on re-entry, invoke the previous menu's close fn (stored as _openRowMenuClose) so its document/window listeners are detached rather than leaked; use claudeSessionId || sessionId in the 'Resume session' menu item to match the main-row and Session Manager resume routing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1426,8 +1426,11 @@ class CodemanApp {
|
||||
// visible welcome list) on session structural changes. Extra listeners on the
|
||||
// same EventSource — EventSource supports multiple listeners per event — so the
|
||||
// existing handlers above are untouched. Registered through addListener so they
|
||||
// are torn down with the rest on reconnect.
|
||||
for (const event of [SSE_EVENTS.SESSION_CREATED, SSE_EVENTS.SESSION_UPDATED, SSE_EVENTS.SESSION_DELETED]) {
|
||||
// are torn down with the rest on reconnect. Only structural events (created /
|
||||
// deleted) trigger a refetch: session:updated is batch-broadcast every ~500ms
|
||||
// per active session, which would otherwise turn an open modal / visible welcome
|
||||
// list into a sustained ~1 Hz full ~/.claude/projects rescan loop.
|
||||
for (const event of [SSE_EVENTS.SESSION_CREATED, SSE_EVENTS.SESSION_DELETED]) {
|
||||
addListener(event, () => this._onSessionListMaybeChanged());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,8 @@
|
||||
</div>
|
||||
<button class="btn-icon-header btn-redraw-terminal btn-redraw-terminal--hidden" onclick="app.restoreTerminalSize()" title="Redraw terminal to fit current screen (Ctrl+Shift+R)" aria-label="Redraw terminal"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="1 4 1 10 7 10"/><polyline points="23 20 23 14 17 14"/><path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/></svg></button>
|
||||
<button class="btn-icon-header btn-response-viewer-header btn-response-viewer-header--hidden" onclick="app.toggleResponseViewer()" title="View last response" aria-label="View last response"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>
|
||||
<button class="btn-icon-header btn-away-digest" onclick="app.openAwayDigest()" title="Away Digest" aria-label="Open away digest"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M3 6h.01"/><path d="M3 12h.01"/><path d="M3 18h.01"/></svg></button> <button class="btn-icon-header btn-session-manager" onclick="app.openSessionManager()" title="Session Manager" aria-label="Open session manager"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg></button>
|
||||
<button class="btn-icon-header btn-away-digest" onclick="app.openAwayDigest()" title="Away Digest" aria-label="Open away digest"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13"/><path d="M8 12h13"/><path d="M8 18h13"/><path d="M3 6h.01"/><path d="M3 12h.01"/><path d="M3 18h.01"/></svg></button>
|
||||
<button class="btn-icon-header btn-session-manager" onclick="app.openSessionManager()" title="Session Manager" aria-label="Open session manager"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg></button>
|
||||
<button class="btn-icon-header btn-attachments-history btn-attachments-history--hidden" id="attachmentsHistoryBtn" onclick="app.toggleAttachmentHistory()" title="Attachments" aria-label="Open attachment history" aria-expanded="false">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
|
||||
<span class="attachment-history-badge" id="attachmentHistoryBadge" style="display:none;">0</span>
|
||||
|
||||
@@ -459,14 +459,16 @@ html.mobile-init .file-browser-panel {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
/* Hide header settings gear, lifecycle log, and away digest on mobile - settings
|
||||
moved to toolbar; away digest is a secondary informational control that doesn't
|
||||
belong on the cramped phone header.
|
||||
/* Hide header settings gear, lifecycle log, away digest, and session manager on
|
||||
mobile - settings moved to toolbar; away digest and the session manager are
|
||||
secondary controls that don't belong on the cramped phone header (the session
|
||||
manager stays reachable via the Ctrl+K palette's "Browse all sessions" item).
|
||||
(The attachments button is opt-in / default-hidden everywhere via its own
|
||||
--hidden marker, so it needs no mobile-specific rule here.) */
|
||||
.btn-icon-header.btn-settings,
|
||||
.btn-icon-header.btn-lifecycle-log,
|
||||
.btn-icon-header.btn-away-digest {
|
||||
.btn-icon-header.btn-away-digest,
|
||||
.btn-icon-header.btn-session-manager {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -1152,8 +1152,14 @@ Object.assign(CodemanApp.prototype, {
|
||||
*/
|
||||
async _fetchUnifiedSessions(limit = 60) {
|
||||
const res = await fetch('/api/sessions/unified?limit=' + limit);
|
||||
const data = await res.json();
|
||||
return data.data?.sessions || [];
|
||||
// ApiResponse envelope: { success, data: { sessions } }. Throw on failure so
|
||||
// callers (loadHistorySessions) hit their catch instead of rendering a 5xx as
|
||||
// an empty history.
|
||||
const data = await res.json().catch(() => null);
|
||||
if (!res.ok || !data || data.success === false || !data.data) {
|
||||
throw new Error(data?.error || `unified sessions request failed (HTTP ${res.status})`);
|
||||
}
|
||||
return data.data.sessions || [];
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1385,14 +1391,15 @@ Object.assign(CodemanApp.prototype, {
|
||||
* @param {HTMLElement} detail the inline detail panel element
|
||||
*/
|
||||
_openSessionRowMenu(anchorEl, s, cases, item, detail) {
|
||||
// Close any already-open row menu first.
|
||||
if (this._openRowMenuEl) {
|
||||
// Close any already-open row menu first — call its own close fn so the
|
||||
// previous menu's document/window listeners are detached (a raw .remove()
|
||||
// would leave them dangling until the next event self-cleans).
|
||||
if (this._openRowMenuClose) {
|
||||
try {
|
||||
this._openRowMenuEl.remove();
|
||||
this._openRowMenuClose();
|
||||
} catch {
|
||||
/* noop */
|
||||
}
|
||||
this._openRowMenuEl = null;
|
||||
}
|
||||
|
||||
const isLiveOpen =
|
||||
@@ -1416,7 +1423,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
} catch {
|
||||
/* noop */
|
||||
}
|
||||
if (this._openRowMenuEl === menu) this._openRowMenuEl = null;
|
||||
if (this._openRowMenuEl === menu) {
|
||||
this._openRowMenuEl = null;
|
||||
this._openRowMenuClose = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper: build one menu item button.
|
||||
@@ -1451,7 +1461,9 @@ Object.assign(CodemanApp.prototype, {
|
||||
if (isLiveOpen) {
|
||||
this.selectSession(s.sessionId);
|
||||
} else {
|
||||
this.resumeHistorySession(s.sessionId, s.workingDir || '');
|
||||
// Resume by the Claude conversation UUID when present (resumed sessions
|
||||
// carry theirs separately from their Codeman id).
|
||||
this.resumeHistorySession(s.claudeSessionId || s.sessionId, s.workingDir || '');
|
||||
}
|
||||
this.closeSessionManager?.();
|
||||
closeMenu();
|
||||
@@ -1521,6 +1533,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
window.addEventListener('resize', onScrollResize, true);
|
||||
|
||||
this._openRowMenuEl = menu;
|
||||
this._openRowMenuClose = closeMenu;
|
||||
},
|
||||
|
||||
/** Number of history items shown before "Show More" */
|
||||
|
||||
Reference in New Issue
Block a user