Conversation
…ssions\n\nchore(release): v2.10.0
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a tiled view feature (v2.10.0) that allows users to view two sessions side-by-side, each with independent terminals and sockets.
- Adds a new tiled interface with draggable splitter and persistent position
- Implements per-pane session management with dropdowns and close actions
- Extends font size settings to apply across all panes
Reviewed Changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/public/style.css | Adds CSS for tile layout, pane styling, resizer, and tile controls |
| src/public/session-manager.js | Adds hooks to refresh pane session selectors when sessions are loaded/updated |
| src/public/panes.js | New file implementing ClaudePane and PaneManager classes for tiled view functionality |
| src/public/index.html | Adds tiled view HTML structure, tile toggle button, and theme selection script |
| src/public/app.js | Integrates PaneManager, adds tile view toggle handler, and extends settings for multi-pane support |
| package.json | Updates version from 2.8.0 to 2.10.0 |
| CHANGELOG.md | Documents v2.9.0 theme changes and v2.10.0 tiled view features |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| width: 28px; height: 28px; display:flex; align-items:center; justify-content:center; | ||
| background: transparent; border: 1px solid var(--border); border-radius: 4px; | ||
| color: var(--text-secondary); cursor: pointer; transition: all .2s; flex-shrink: 0; margin-left: 4px; |
There was a problem hiding this comment.
[nitpick] The .tab-tile styles are duplicated from .tab-new. Consider creating a shared base class to reduce code duplication and improve maintainability.
| .tiles-container { flex: 1; display: flex; min-height: 0; } | ||
| .tile-grid { | ||
| display: grid; grid-template-columns: 1fr 6px 1fr; grid-template-rows: 100%; width: 100%; | ||
| } | ||
| .tile-pane { display:flex; flex-direction: column; min-width: 0; border-left: 1px solid var(--border); } | ||
| .tile-pane:first-child { border-left: none; } | ||
| .tile-toolbar { display:flex; align-items:center; gap: 8px; padding: 6px 8px; background: var(--bg-secondary); border-bottom:1px solid var(--border); } | ||
| .tile-toolbar .spacer { flex:1; } | ||
| .tile-session-select { background: var(--bg-tertiary); color: var(--text-primary); border:1px solid var(--border); border-radius:6px; padding:6px 8px; font-family: var(--font-mono); font-size:12px; } | ||
| .tile-close { background: transparent; border:1px solid var(--border); border-radius:4px; color: var(--text-secondary); width:26px; height:26px; display:flex; align-items:center; justify-content:center; cursor:pointer; } | ||
| .tile-close:hover { background: var(--bg-tertiary); color: var(--text-primary); } | ||
| .tile-terminal { flex:1; min-height:0; position: relative; } | ||
| .tile-terminal .xterm { height: 100%; } | ||
|
|
||
| .resizer { | ||
| background: var(--border); cursor: col-resize; width: 6px; height: 100%; |
There was a problem hiding this comment.
[nitpick] Multiple CSS rules are written on single lines making them difficult to read and maintain. Consider formatting these rules with proper line breaks and indentation for better readability.
| .tiles-container { flex: 1; display: flex; min-height: 0; } | |
| .tile-grid { | |
| display: grid; grid-template-columns: 1fr 6px 1fr; grid-template-rows: 100%; width: 100%; | |
| } | |
| .tile-pane { display:flex; flex-direction: column; min-width: 0; border-left: 1px solid var(--border); } | |
| .tile-pane:first-child { border-left: none; } | |
| .tile-toolbar { display:flex; align-items:center; gap: 8px; padding: 6px 8px; background: var(--bg-secondary); border-bottom:1px solid var(--border); } | |
| .tile-toolbar .spacer { flex:1; } | |
| .tile-session-select { background: var(--bg-tertiary); color: var(--text-primary); border:1px solid var(--border); border-radius:6px; padding:6px 8px; font-family: var(--font-mono); font-size:12px; } | |
| .tile-close { background: transparent; border:1px solid var(--border); border-radius:4px; color: var(--text-secondary); width:26px; height:26px; display:flex; align-items:center; justify-content:center; cursor:pointer; } | |
| .tile-close:hover { background: var(--bg-tertiary); color: var(--text-primary); } | |
| .tile-terminal { flex:1; min-height:0; position: relative; } | |
| .tile-terminal .xterm { height: 100%; } | |
| .resizer { | |
| background: var(--border); cursor: col-resize; width: 6px; height: 100%; | |
| .tiles-container { | |
| flex: 1; | |
| display: flex; | |
| min-height: 0; | |
| } | |
| .tile-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 6px 1fr; | |
| grid-template-rows: 100%; | |
| width: 100%; | |
| } | |
| .tile-pane { | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 0; | |
| border-left: 1px solid var(--border); | |
| } | |
| .tile-pane:first-child { | |
| border-left: none; | |
| } | |
| .tile-toolbar { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| padding: 6px 8px; | |
| background: var(--bg-secondary); | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .tile-toolbar .spacer { | |
| flex: 1; | |
| } | |
| .tile-session-select { | |
| background: var(--bg-tertiary); | |
| color: var(--text-primary); | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| padding: 6px 8px; | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| } | |
| .tile-close { | |
| background: transparent; | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| color: var(--text-secondary); | |
| width: 26px; | |
| height: 26px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| } | |
| .tile-close:hover { | |
| background: var(--bg-tertiary); | |
| color: var(--text-primary); | |
| } | |
| .tile-terminal { | |
| flex: 1; | |
| min-height: 0; | |
| position: relative; | |
| } | |
| .tile-terminal .xterm { | |
| height: 100%; | |
| } | |
| .resizer { | |
| background: var(--border); | |
| cursor: col-resize; | |
| width: 6px; | |
| height: 100%; |
| fit() { | ||
| try { this.fitAddon?.fit(); } catch (_) {} | ||
| } |
There was a problem hiding this comment.
The empty catch block with underscore parameter suppresses all errors, which could hide important issues. Consider logging the error or handling specific expected exceptions.
| disconnect() { | ||
| try { this.socket?.close(); } catch (_) {} | ||
| this.socket = null; | ||
| try { this.terminal?.clear(); } catch (_) {} | ||
| } |
There was a problem hiding this comment.
Empty catch blocks suppress all errors without logging. Consider logging errors or handling specific expected exceptions to aid debugging.
| sessions: this.panes.map(p => p.sessionId) | ||
| }; | ||
| localStorage.setItem('cc-web-tiles', JSON.stringify(state)); | ||
| } catch (_) {} |
There was a problem hiding this comment.
The empty catch block silently ignores localStorage errors. Consider logging the error as localStorage failures could indicate storage quota issues or privacy mode restrictions.
| } catch (_) {} | |
| } catch (err) { | |
| console.error("Failed to persist pane state to localStorage:", err); | |
| } |
| (st.sessions || []).forEach((id, i) => id && this.assignSession(i, id)); | ||
| }, 500); | ||
| } | ||
| } catch (_) {} |
There was a problem hiding this comment.
Empty catch block in restoreFromStorage() silently ignores parsing errors. Consider logging errors to help debug configuration restoration issues.
| } catch (_) {} | |
| } catch (err) { | |
| console.error("Failed to restore pane configuration from storage:", err); | |
| } |
This PR releases v2.10.0.
Highlights:
No API/CLI changes.