Skip to content

Commit ded65b1

Browse files
authored
Merge pull request #929 from web3dev1337/fix/review-console-fit-and-scroll
fix: refit review console terminals after dock
2 parents 9db8495 + 0a984bd commit ded65b1

2 files changed

Lines changed: 130 additions & 33 deletions

File tree

client/app.js

Lines changed: 119 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11825,6 +11825,103 @@ class ClaudeOrchestrator {
1182511825
return uniqueSessionIds;
1182611826
}
1182711827

11828+
getReviewConsoleTerminalScrollContainer(containerEl) {
11829+
const container = containerEl || null;
11830+
if (!container) return null;
11831+
return container.closest?.('[data-rc-panel="terminals"]')
11832+
|| container.closest?.('.worktree-inspector-panel')
11833+
|| container;
11834+
}
11835+
11836+
scrollReviewConsoleTerminalIntoView(containerEl, sessionId, { block = 'center' } = {}) {
11837+
const container = this.getReviewConsoleTerminalScrollContainer(containerEl);
11838+
const sid = String(sessionId || '').trim();
11839+
if (!container || !sid) return;
11840+
11841+
const wrapper = document.getElementById(this.getSessionDomId('wrapper', sid));
11842+
if (!wrapper || !wrapper.isConnected) return;
11843+
11844+
const wrapperRect = wrapper.getBoundingClientRect();
11845+
const containerRect = container.getBoundingClientRect();
11846+
if (!wrapperRect.height || !containerRect.height) return;
11847+
11848+
const deltaTop = wrapperRect.top - containerRect.top;
11849+
const deltaBottom = wrapperRect.bottom - containerRect.bottom;
11850+
let nextScrollTop = container.scrollTop;
11851+
11852+
if (block === 'nearest') {
11853+
if (deltaTop < 0) nextScrollTop += deltaTop;
11854+
else if (deltaBottom > 0) nextScrollTop += deltaBottom;
11855+
} else {
11856+
nextScrollTop += deltaTop - Math.max(0, (containerRect.height - wrapperRect.height) / 2);
11857+
}
11858+
11859+
container.scrollTop = Math.max(0, nextScrollTop);
11860+
}
11861+
11862+
queueReviewConsoleTerminalLayout(containerEl, sessionIds, { preferredSessionId = '', scrollToBottom = false } = {}) {
11863+
const container = containerEl || null;
11864+
const uniqueSessionIds = Array.from(new Set(
11865+
(Array.isArray(sessionIds) ? sessionIds : [])
11866+
.map((sid) => String(sid || '').trim())
11867+
.filter(Boolean)
11868+
));
11869+
if (!container || uniqueSessionIds.length === 0) return;
11870+
11871+
const runLayoutPass = ({ anchor = false, pushBottom = false } = {}) => {
11872+
const visibleSessionIds = [];
11873+
uniqueSessionIds.forEach((sid) => {
11874+
const wrapper = document.getElementById(this.getSessionDomId('wrapper', sid));
11875+
if (!wrapper || !wrapper.isConnected || wrapper.style.display === 'none' || wrapper.classList.contains('hidden')) {
11876+
return;
11877+
}
11878+
11879+
visibleSessionIds.push(sid);
11880+
try {
11881+
this.terminalManager?.fitTerminal?.(sid);
11882+
} catch {
11883+
// ignore
11884+
}
11885+
11886+
const term = this.terminalManager?.terminals?.get?.(sid);
11887+
if (!term) return;
11888+
11889+
try {
11890+
term.refresh(0, Math.max(0, term.rows - 1));
11891+
} catch {
11892+
// ignore
11893+
}
11894+
11895+
if (!pushBottom) return;
11896+
11897+
try {
11898+
this.terminalManager?.userScrolling?.set?.(sid, false);
11899+
} catch {
11900+
// ignore
11901+
}
11902+
try {
11903+
term.scrollToBottom?.();
11904+
} catch {
11905+
// ignore
11906+
}
11907+
});
11908+
11909+
if (!anchor || visibleSessionIds.length === 0) return;
11910+
const preferred = String(preferredSessionId || visibleSessionIds[0] || '').trim();
11911+
if (preferred) {
11912+
this.scrollReviewConsoleTerminalIntoView(container, preferred, { block: 'center' });
11913+
}
11914+
};
11915+
11916+
requestAnimationFrame(() => {
11917+
requestAnimationFrame(() => {
11918+
runLayoutPass({ anchor: true, pushBottom: !!scrollToBottom });
11919+
setTimeout(() => runLayoutPass({ anchor: false, pushBottom: false }), 140);
11920+
setTimeout(() => runLayoutPass({ anchor: false, pushBottom: false }), 420);
11921+
});
11922+
});
11923+
}
11924+
1182811925
restoreReviewConsoleDockedTerminals() {
1182911926
try {
1183011927
if (!this.reviewConsoleDockedTerminals || this.reviewConsoleDockedTerminals.size === 0) {
@@ -11961,17 +12058,13 @@ class ClaudeOrchestrator {
1196112058
wrapper.style.display = '';
1196212059
wrapper.classList.add('review-console-terminal');
1196312060
container.appendChild(wrapper);
11964-
11965-
// Let layout settle, then fit.
11966-
setTimeout(() => {
11967-
try {
11968-
this.terminalManager?.fitTerminal?.(sid);
11969-
} catch {
11970-
// ignore
11971-
}
11972-
}, 60);
1197312061
}
1197412062

12063+
this.queueReviewConsoleTerminalLayout(container, sessionIds, {
12064+
preferredSessionId: sessionIdHint || sessionIds[0] || '',
12065+
scrollToBottom: true
12066+
});
12067+
1197512068
return sessionIds.length;
1197612069
}
1197712070

@@ -13472,14 +13565,6 @@ class ClaudeOrchestrator {
1347213565

1347313566
const label = inferredWorktreeId || String(t.id || '').trim() || worktreePath;
1347413567
await this.openWorktreeInspectorForPath(worktreePath, { label, task: t, reviewConsole: true, sessionIdHint: sessionId, prUrlHint });
13475-
13476-
if (rcShowTerminals) {
13477-
const preferredSessionId = sessionId || (inferredWorktreeId ? `${inferredWorktreeId}-claude` : '');
13478-
if (preferredSessionId) {
13479-
const wrapper = document.getElementById(this.getSessionDomId('wrapper', preferredSessionId));
13480-
wrapper?.scrollIntoView?.({ behavior: 'smooth', block: 'center' });
13481-
}
13482-
}
1348313568
}
1348413569

1348513570
async fetchPullRequestDetails(prUrl, { maxFiles = 300, maxCommits = 200, maxComments = 50, maxReviews = 50 } = {}) {
@@ -13814,6 +13899,14 @@ class ClaudeOrchestrator {
1381413899
return String(a).localeCompare(String(b));
1381513900
});
1381613901

13902+
const preferredMatchingSessionId = (() => {
13903+
const taskSessionId = String(t?.sessionId || '').trim();
13904+
if (taskSessionId && matchingSessionIds.includes(taskSessionId)) return taskSessionId;
13905+
const currentSessionId = this.getCurrentInteractionSessionId?.();
13906+
if (currentSessionId && matchingSessionIds.includes(currentSessionId)) return currentSessionId;
13907+
return matchingSessionIds.find((sid) => !isServer(sid)) || matchingSessionIds[0] || '';
13908+
})();
13909+
1381713910
this.setReviewConsoleVisibilityBypass(matchingSessionIds);
1381813911

1381913912
const statusLabel = (s) => {
@@ -14259,13 +14352,11 @@ class ClaudeOrchestrator {
1425914352
});
1426014353
terminalsContainer.classList.toggle('paired-layout', hasVisibleAgent && hasVisibleServer);
1426114354

14262-
if (visibleSessionIds.length) {
14263-
setTimeout(() => {
14264-
visibleSessionIds.forEach((sid) => {
14265-
try { this.terminalManager?.fitTerminal?.(sid); } catch {}
14266-
});
14267-
}, 60);
14268-
}
14355+
if (visibleSessionIds.length) {
14356+
this.queueReviewConsoleTerminalLayout(terminalsContainer, visibleSessionIds, {
14357+
preferredSessionId: preferredMatchingSessionId
14358+
});
14359+
}
1426914360
};
1427014361

1427114362
const updateGrid = () => {
@@ -14996,15 +15087,11 @@ class ClaudeOrchestrator {
1499615087
wrapper.style.display = '';
1499715088
wrapper.classList.add('review-console-terminal');
1499815089
terminalsContainer.appendChild(wrapper);
14999-
15000-
setTimeout(() => {
15001-
try {
15002-
this.terminalManager?.fitTerminal?.(sid);
15003-
} catch {
15004-
// ignore
15005-
}
15006-
}, 60);
1500715090
}
15091+
this.queueReviewConsoleTerminalLayout(terminalsContainer, matchingSessionIds, {
15092+
preferredSessionId: preferredMatchingSessionId,
15093+
scrollToBottom: true
15094+
});
1500815095
try { updateTerminalKindVisibility(); } catch {}
1500915096
}
1501015097

client/styles.css

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2847,6 +2847,7 @@ header {
28472847
display: flex;
28482848
flex-direction: column;
28492849
gap: 6px;
2850+
min-width: 0;
28502851
min-height: 0;
28512852
overflow: auto;
28522853
}
@@ -2872,6 +2873,7 @@ header {
28722873
padding: 6px;
28732874
display: flex;
28742875
flex-direction: column;
2876+
min-width: 0;
28752877
min-height: 0;
28762878
}
28772879

@@ -2963,7 +2965,9 @@ header {
29632965

29642966
.worktree-inspector-terminals.review-console-terminals-grid {
29652967
grid-template-columns: minmax(0, 1fr);
2966-
height: 100%;
2968+
flex: 1 1 auto;
2969+
height: auto;
2970+
min-width: 0;
29672971
min-height: 0;
29682972
align-content: stretch;
29692973
grid-auto-rows: minmax(160px, 1fr);
@@ -2976,9 +2980,15 @@ header {
29762980

29772981
.worktree-inspector-terminals .terminal-wrapper.review-console-terminal {
29782982
height: 100%;
2983+
min-width: 0;
29792984
min-height: 160px;
29802985
}
29812986

2987+
.review-console-grid .worktree-inspector-terminals-panel {
2988+
overflow-x: hidden;
2989+
overflow-y: auto;
2990+
}
2991+
29822992
.rc-panel-toggle-btn {
29832993
min-width: 58px;
29842994
height: 26px;

0 commit comments

Comments
 (0)