mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 23:49:41 +02:00
COD-39 attachment history drawer
Stacks on COD-38: accumulates a per-session attachment history and exposes it through a slide-in drawer with an unread badge, so attachments stay reachable after their cards are dismissed. Backend: - session-attachment-history: history state — dedupe by source path / relative path, newest-first, 100-item cap, and externalPath sanitization (the absolute host path is server-private and never leaves toState()). - session.ts: _attachmentHistory + getter (sanitized) / upsert / restore / getAttachmentHistoryForPersist; restored from saved state in the constructor. - file-routes: GET /attachments (list — resolves each entry to live metadata + routes; external entries are re-registered) and GET /attachments/:id (metadata poll). The by-id route guards via the registry's TOCTOU-safe resolveServableAttachmentPath. - server.ts: detected/registered attachments upsert into history and persist; the private (externalPath-bearing) history rides on disk under __attachmentHistory, separate from the sanitized public copy, and is restored on mux-session recovery. - types/session.ts: SessionAttachmentHistoryItem + SessionState.attachmentHistory. Frontend: - panels-ui: the drawer (lazy-built), unread badge, list render with per-item preview/download/open/"Card" (reshow) actions, and live refresh of the open drawer on new detections. - app.js: history state + per-session badge/cleanup wiring. - index.html / styles.css / mobile.css: header button + badge and the drawer. Verified: tsc / eslint / prettier / frontend-syntax / public-assets clean; new history-module unit tests pass; full test:ci green (2866 passed); badge, drawer open/render/reshow/close verified in-browser.
This commit is contained in:
committed by
Claude (Codeman maintainer)
parent
5eacb1cf03
commit
577b6d7384
@@ -390,6 +390,9 @@ class CodemanApp {
|
||||
this.imagePopupZIndex = ZINDEX_IMAGE_POPUP_BASE;
|
||||
this.attachmentCards = new Map(); // Map<attachmentId, { element, sessionId, filePath }>
|
||||
this.attachmentCardStack = null;
|
||||
this.attachmentHistoryCounts = new Map(); // Map<sessionId, count>
|
||||
this.attachmentHistoryItems = [];
|
||||
this.attachmentHistoryDrawerOpen = false;
|
||||
|
||||
// File browser state (methods in panels-ui.js)
|
||||
this.fileBrowserData = null;
|
||||
@@ -2222,6 +2225,7 @@ class CodemanApp {
|
||||
KeyboardHandler.init();
|
||||
// Clear tab alerts
|
||||
this.tabAlerts.clear();
|
||||
this.attachmentHistoryCounts.clear();
|
||||
// Clear shown completions (used for duplicate notification prevention)
|
||||
if (this._shownCompletions) {
|
||||
this._shownCompletions.clear();
|
||||
@@ -3225,6 +3229,10 @@ class CodemanApp {
|
||||
// Instant active-class toggle (no 100ms debounce), then schedule full render for badges/status
|
||||
this._updateActiveTabImmediate(sessionId);
|
||||
this.renderSessionTabs();
|
||||
this.updateAttachmentHistoryBadge?.();
|
||||
if (this.attachmentHistoryDrawerOpen) {
|
||||
this.loadAttachmentHistory?.(sessionId);
|
||||
}
|
||||
this._updateLocalEchoState();
|
||||
|
||||
// Restore flushed offset AND text IMMEDIATELY so backspace/typing work during
|
||||
@@ -3595,6 +3603,10 @@ class CodemanApp {
|
||||
this.projectInsights.delete(sessionId);
|
||||
this.pendingHooks.delete(sessionId);
|
||||
this.tabAlerts.delete(sessionId);
|
||||
this.attachmentHistoryCounts.delete(sessionId);
|
||||
if (this.attachmentHistoryDrawerOpen && this.activeSessionId === sessionId) {
|
||||
this.closeAttachmentHistory?.();
|
||||
}
|
||||
this.terminalLoadStates.delete(sessionId);
|
||||
this.clearCountdownTimers(sessionId);
|
||||
this.closeSessionLogViewerWindows(sessionId);
|
||||
|
||||
Reference in New Issue
Block a user