Skip to content

Commit fd37f9c

Browse files
authored
Polish session log view (#7131)
- Disable scrolling of unexpanded content - Fixing path display - Improve display of bash commands
1 parent ea74fdd commit fd37f9c

5 files changed

Lines changed: 50 additions & 24 deletions

File tree

src/github/pullRequestOverview.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,9 @@ export class PullRequestOverviewPanel extends IssueOverviewPanel<PullRequestMode
481481
}
482482
}
483483

484-
private async openSessionLog(_message: IRequestMessage<{ link: SessionLinkInfo }>): Promise<void> {
484+
private async openSessionLog(message: IRequestMessage<{ link: SessionLinkInfo }>): Promise<void> {
485485
try {
486-
await SessionLogViewManager.instance?.openForPull(this._item, _message.args.link);
486+
await SessionLogViewManager.instance?.openForPull(this._item, message.args.link);
487487
} catch (e) {
488488
Logger.error(`Open session log view failed: ${formatError(e)}`, PullRequestOverviewPanel.ID);
489489
}

src/view/sessionLogView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ class SessionLogView extends Disposable {
271271
<meta charset="UTF-8">
272272
<meta name="viewport" content="width=device-width, initial-scale=1.0">
273273
<title>${vscode.l10n.t('Session Log')}</title>
274-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline' ${this.webviewPanel.webview.cspSource}; script-src ${this.webviewPanel.webview.cspSource} 'unsafe-eval'; font-src ${this.webviewPanel.webview.cspSource};">
274+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline' ${this.webviewPanel.webview.cspSource}; script-src ${this.webviewPanel.webview.cspSource} 'unsafe-eval' blob:; font-src ${this.webviewPanel.webview.cspSource};">
275275
</head>
276276
<body>
277277
<div id="app"></div>

webviews/sessionLogView/codeView.tsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface CodeViewProps {
1919

2020
export const CodeView: React.FC<CodeViewProps> = ({ label, description, content }) => {
2121
const [open, setOpen] = React.useState<boolean>(true);
22+
const [hasExpandableContent, setHasExpandableContent] = React.useState<boolean>(false);
2223
const [expanded, setExpanded] = React.useState<boolean>(false);
2324
const [editor, setEditor] = React.useState<monaco.editor.IStandaloneCodeEditor | undefined>(undefined);
2425

@@ -47,7 +48,6 @@ export const CodeView: React.FC<CodeViewProps> = ({ label, description, content
4748
scrollBeyondLastLine: false,
4849
lineNumbers: 'off',
4950
renderLineHighlight: 'none',
50-
automaticLayout: true,
5151
fontSize: 12,
5252
wordWrap: 'on',
5353
rulers: [],
@@ -57,43 +57,59 @@ export const CodeView: React.FC<CodeViewProps> = ({ label, description, content
5757
});
5858

5959
setEditor(editor);
60-
updateEditorHeight(editor);
60+
updateEditorDimensions(editor);
61+
62+
// Check if content exceeds collapsed height and should show expand button
63+
setHasExpandableContent(editor.getContentHeight() > collapsedHeight);
64+
65+
// Listen for width changes and relayout editor
66+
let lastObservedWidth = editorContainerRef.current.clientWidth;
67+
const resizeObserver = new ResizeObserver(entries => {
68+
const newWidth = entries.at(0)?.contentRect.width;
69+
if (newWidth && newWidth !== lastObservedWidth) {
70+
lastObservedWidth = newWidth;
71+
updateEditorDimensions(editor, lastObservedWidth);
72+
}
73+
});
74+
resizeObserver.observe(editorContainerRef.current);
6175

62-
// Cleanup
6376
return () => {
77+
resizeObserver.disconnect();
6478
if (editor) {
6579
editor.dispose();
6680
setEditor(undefined);
6781
}
6882
};
83+
6984
}, [editorContainerRef]);
7085

7186
// Update editor height when expanded state changes
7287
React.useEffect(() => {
7388
if (editor) {
74-
updateEditorHeight(editor);
89+
updateEditorDimensions(editor);
7590
}
7691
}, [expanded]);
7792

78-
const updateEditorHeight = (editorInstance: monaco.editor.IStandaloneCodeEditor) => {
79-
if (!editorContainerRef.current) return;
93+
const updateEditorDimensions = (editorInstance: monaco.editor.IStandaloneCodeEditor, containerWidthHint?: number) => {
94+
if (!editorContainerRef.current) {
95+
return;
96+
}
8097

8198
const contentHeight = editorInstance.getContentHeight();
82-
const width = editorContainerRef.current.clientWidth || 300;
99+
const width = containerWidthHint ?? (editorContainerRef.current.clientWidth || 300);
83100

84101
if (expanded) {
85102
if (editorContainerRef.current) {
86103
editorContainerRef.current.style.height = `${contentHeight}px`;
87104
}
88-
editorInstance.layout({ width, height: contentHeight });
89105
} else {
90106
const newContentHeight = Math.min(contentHeight, collapsedHeight);
91107
if (editorContainerRef.current) {
92108
editorContainerRef.current.style.height = `${newContentHeight}px`;
93109
}
94-
// Always lay the editor out for the full height
95-
editorInstance.layout({ width, height: contentHeight });
96110
}
111+
112+
editorInstance.layout({ width, height: contentHeight });
97113
};
98114

99115
const toggleExpanded = () => {
@@ -104,9 +120,6 @@ export const CodeView: React.FC<CodeViewProps> = ({ label, description, content
104120
setOpen(!open);
105121
};
106122

107-
// Check if content exceeds collapsed height and should show expand button
108-
const hasExpandableContent = editor ? editor.getContentHeight() > collapsedHeight : false;
109-
110123
return (
111124
<div className={`codeview-wrapper ${!expanded && hasExpandableContent ? 'collapsed' : ''}`}>
112125
<details className="codeview-details" open={open}>

webviews/sessionLogView/sessionView.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,13 @@ const SessionLog: React.FC<SessionLogProps> = ({ logs }) => {
130130
if (content) {
131131
const file = content.fileA ?? content.fileB;
132132
const lang = (file && getLanguageForResource(file)) ?? 'plaintext';
133+
const fileLabel = file && toFileLabel(file);
133134

134135
return (
135136
<CodeView
136137
key={`view-${index}`}
137-
label="View"
138-
description={file && toFileLabel(file)}
138+
label={fileLabel === '' ? 'View repository' : 'View'}
139+
description={fileLabel}
139140
content={{ value: content.content, lang }}
140141
/>
141142
);
@@ -145,7 +146,7 @@ const SessionLog: React.FC<SessionLogProps> = ({ logs }) => {
145146
<CodeView
146147
key={`edit-${index}`}
147148
label="Edit"
148-
description={args.path}
149+
description={args.path && toFileLabel(args.path)}
149150
content={{ value: choice.delta.content, lang: 'diff' }}
150151
/>
151152
);
@@ -168,11 +169,22 @@ const SessionLog: React.FC<SessionLogProps> = ({ logs }) => {
168169
/>
169170
);
170171
} else if (name === 'bash') {
172+
let command: string | undefined;
173+
try {
174+
const args = choice.delta.tool_calls.at(0)?.function.arguments;
175+
command = args && JSON.parse(args).command;
176+
if (command) {
177+
command = '$ ' + command;
178+
}
179+
} catch (error) {
180+
console.warn(`Failed to parse bash command arguments: ${error}`);
181+
}
182+
171183
return (
172184
<CodeView
173185
key={`bash-${index}`}
174186
label="Run Bash command"
175-
content={{ value: choice.delta.content, lang: 'markdown' }}
187+
content={{ value: [command, choice.delta.content].filter(Boolean).join('\n'), lang: 'bash' }}
176188
/>
177189
);
178190
}
@@ -252,6 +264,7 @@ function getLanguageForResource(filePath: string): string | undefined {
252264

253265

254266
function toFileLabel(file: string): string {
267+
// File paths are absolute and look like: `/home/runner/work/repo/repo/<path>`
255268
const parts = file.split('/');
256-
return parts.slice(5).join('/');
269+
return parts.slice(6).join('/');
257270
}

webviews/sessionLogView/sessionsApi.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export function parseSessionLogs(rawText: string): SessionResponseLogChunk[] {
6464

6565
return parts as SessionResponseLogChunk[];
6666
}
67-
// Utility functions
67+
6868
export function parseDiff(content: string): { content: string; fileA: string | undefined; fileB: string | undefined; } | undefined {
6969
const lines = content.split(/\r?\n/g);
7070
let fileA: string | undefined;
@@ -90,8 +90,8 @@ export function parseDiff(content: string): { content: string; fileA: string | u
9090

9191
return {
9292
content: lines.slice(startDiffLineIndex).join('\n'),
93-
fileA,
94-
fileB
93+
fileA: typeof fileA === 'string' ? '/' + fileA : undefined,
94+
fileB: typeof fileB === 'string' ? '/' + fileB : undefined
9595
};
9696
}
9797

0 commit comments

Comments
 (0)