@@ -70,22 +70,6 @@ export class SessionLogViewManager extends Disposable implements vscode.WebviewP
7070
7171 return this . open ( sessionLogs , undefined ) ;
7272 } ) ) ;
73-
74- this . _register ( vscode . commands . registerCommand ( 'sessionLog.openOnWeb' , async ( ) => {
75- if ( ! this . _activePanel ) {
76- return ;
77- }
78-
79- const pullInfo = this . _activePanel . pullInfo ;
80- if ( ! pullInfo ) {
81- vscode . window . showErrorMessage ( vscode . l10n . t ( 'No pull for this session.' ) ) ;
82- return ;
83- }
84-
85-
86- const sessionUrl = vscode . Uri . parse ( `https://${ pullInfo . host } /${ pullInfo . owner } /${ pullInfo . repo } /pull/${ pullInfo . pullId } /agent-sessions/${ this . _activePanel . sessionId } ` ) ;
87- return vscode . env . openExternal ( sessionUrl ) ;
88- } ) ) ;
8973 }
9074
9175 public override dispose ( ) {
@@ -100,12 +84,18 @@ export class SessionLogViewManager extends Disposable implements vscode.WebviewP
10084
10185 async openForPull ( pullRequest : PullRequestModel ) : Promise < void > {
10286 try {
103- const sessionLogs = await this . copilotAgentManager . getSessionLogsFromPullRequest ( pullRequest . id ) ;
87+ const sessionLogs = await this . copilotAgentManager . getMostRecentSessionLogsFromPullRequest ( pullRequest . id , false ) ;
10488 if ( ! sessionLogs ) {
10589 throw new Error ( 'No sessions found for this pull request.' ) ;
10690 }
10791
108- return this . open ( sessionLogs , pullRequest ) ;
92+ const existingPanel = this . getPanelForPullRequest ( pullRequest ) ;
93+ if ( existingPanel ) {
94+ existingPanel . revealAndRefresh ( sessionLogs ) ;
95+ return ;
96+ } else {
97+ return this . open ( sessionLogs , pullRequest ) ;
98+ }
10999 } catch ( error ) {
110100 Logger . error ( `Failed to retrieve session logs: ${ error } ` , 'SessionLogViewManager' ) ;
111101 const url = await this . copilotAgentManager . getSessionUrlFromPullRequest ( pullRequest . id ) ;
@@ -117,6 +107,10 @@ export class SessionLogViewManager extends Disposable implements vscode.WebviewP
117107 }
118108 }
119109
110+ private getPanelForPullRequest ( pullRequest : PullRequestModel ) : SessionLogView | undefined {
111+ return Array . from ( this . _panels ) . find ( panel => panel . view . isForPullRequest ( pullRequest ) ) ?. view ;
112+ }
113+
120114 async open ( logs : IAPISessionLogs , pullRequest : PullRequestModel | undefined ) : Promise < void > {
121115 const copilotApi = await getCopilotApi ( this . credentialStore ) ;
122116 if ( ! copilotApi ) {
@@ -133,14 +127,7 @@ export class SessionLogViewManager extends Disposable implements vscode.WebviewP
133127 }
134128 ) ;
135129
136- const pullInfo : SessionPullInfo & { title : string } | undefined = pullRequest ? {
137- host : pullRequest . githubRepository . remote . gitProtocol . host ,
138- owner : pullRequest . githubRepository . remote . owner ,
139- repo : pullRequest . githubRepository . remote . repositoryName ,
140- pullId : pullRequest . number ,
141- title : pullRequest . title ,
142- } : undefined ;
143-
130+ const pullInfo = pullRequest ? toPullInfo ( pullRequest ) : undefined ;
144131 return this . setupWebview ( webviewPanel , logs . sessionId , pullInfo , copilotApi ) ;
145132 }
146133
@@ -160,29 +147,6 @@ export class SessionLogViewManager extends Disposable implements vscode.WebviewP
160147 }
161148
162149 private async setupWebview ( webviewPanel : vscode . WebviewPanel , sessionId : string , pullInfo : SessionPullInfo & { title : string } | undefined , copilotApi : CopilotApi ) : Promise < void > {
163- const distDir = vscode . Uri . joinPath ( this . context . extensionUri , 'dist' ) ;
164-
165- webviewPanel . webview . options = {
166- enableScripts : true ,
167- localResourceRoots : [
168- distDir
169- ]
170- } ;
171- webviewPanel . webview . html = `<!DOCTYPE html>
172- <html lang="en">
173- <head>
174- <meta charset="UTF-8">
175- <meta name="viewport" content="width=device-width, initial-scale=1.0">
176- <title>${ vscode . l10n . t ( 'Session Log' ) } </title>
177- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline' ${ webviewPanel . webview . cspSource } ; script-src ${ webviewPanel . webview . cspSource } 'unsafe-eval'; font-src ${ webviewPanel . webview . cspSource } ;">
178- </head>
179- <body>
180- <div id="app"></div>
181-
182- <script type="module" src="${ webviewPanel . webview . asWebviewUri ( vscode . Uri . joinPath ( distDir , 'webview-session-log-view.js' ) ) } "></script>
183- </body>
184- </html>` ;
185-
186150 const logView = new SessionLogView ( sessionId , pullInfo , webviewPanel , copilotApi , this . context , this . reposManagers , this . telemetry ) ;
187151 const panelDisposables : vscode . Disposable [ ] = [ ] ;
188152 const panelEntry = { view : logView , disposables : panelDisposables } ;
@@ -213,7 +177,7 @@ class SessionLogView extends Disposable {
213177 public readonly pullInfo : SessionPullInfo & { title : string } | undefined ,
214178 private readonly webviewPanel : vscode . WebviewPanel ,
215179 private readonly copilotApi : CopilotApi ,
216- context : vscode . ExtensionContext ,
180+ private readonly context : vscode . ExtensionContext ,
217181 reposManagers : RepositoriesManager ,
218182 telemetry : ITelemetry ,
219183 ) {
@@ -235,7 +199,6 @@ class SessionLogView extends Disposable {
235199
236200 this . _register ( this . webviewPanel . webview . onDidReceiveMessage ( async ( message : any ) => {
237201 if ( message . type === 'openPullRequestView' ) {
238-
239202 let pullRequest : PullRequestModel | undefined ;
240203 if ( pullInfo ) {
241204 const folderManager = reposManagers . getManagerForRepository ( pullInfo . owner , pullInfo . repo ) ?? reposManagers . folderManagers . at ( 0 ) ;
@@ -249,6 +212,14 @@ class SessionLogView extends Disposable {
249212
250213 const folderManager = reposManagers . getManagerForIssueModel ( pullRequest ) ?? reposManagers . folderManagers [ 0 ] ;
251214 await PullRequestOverviewPanel . createOrShow ( telemetry , context . extensionUri , folderManager , pullRequest ) ;
215+ } else if ( message . type === 'openOnWeb' ) {
216+ if ( ! pullInfo ) {
217+ vscode . window . showErrorMessage ( vscode . l10n . t ( 'No pull request information available for this session.' ) ) ;
218+ return ;
219+ }
220+
221+ const sessionUrl = vscode . Uri . parse ( `https://${ pullInfo . host } /${ pullInfo . owner } /${ pullInfo . repo } /pull/${ pullInfo . pullId } /agent-sessions/${ this . sessionId } ` ) ;
222+ return vscode . env . openExternal ( sessionUrl ) ;
252223 }
253224 } ) ) ;
254225
@@ -265,7 +236,45 @@ class SessionLogView extends Disposable {
265236 super . dispose ( ) ;
266237 }
267238
239+ public isForPullRequest ( pullRequest : PullRequestModel ) : boolean {
240+ if ( ! this . pullInfo ) {
241+ return false ;
242+ }
243+ const inInfo = toPullInfo ( pullRequest ) ;
244+ return arePullInfosEqual ( this . pullInfo , inInfo ) ;
245+ }
246+
247+ public revealAndRefresh ( _sessionLogs : IAPISessionLogs ) {
248+ // TODO: handle opening different session from pull
249+ this . initialize ( ) ;
250+ this . webviewPanel . reveal ( ) ;
251+ }
252+
268253 private async initialize ( ) {
254+ const distDir = vscode . Uri . joinPath ( this . context . extensionUri , 'dist' ) ;
255+
256+ this . webviewPanel . webview . options = {
257+ enableScripts : true ,
258+ localResourceRoots : [
259+ distDir
260+ ]
261+ } ;
262+ this . webviewPanel . webview . html = `<!DOCTYPE html>
263+ <html lang="en">
264+ <head>
265+ <meta charset="UTF-8">
266+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
267+ <title>${ vscode . l10n . t ( 'Session Log' ) } </title>
268+ <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 } ;">
269+ </head>
270+ <body>
271+ <div id="app"></div>
272+
273+ <script type="module" src="${ this . webviewPanel . webview . asWebviewUri ( vscode . Uri . joinPath ( distDir , 'webview-session-log-view.js' ) ) } "></script>
274+ </body>
275+ </html>` ;
276+
277+
269278 let readyResolve : ( value : void | PromiseLike < void > ) => void ;
270279 const ready = new Promise < void > ( resolve => { readyResolve = resolve ; } ) ;
271280 this . _register ( this . webviewPanel . webview . onDidReceiveMessage ( ( message : any ) => {
@@ -289,7 +298,6 @@ class SessionLogView extends Disposable {
289298 return ;
290299 }
291300
292-
293301 this . webviewPanel . webview . postMessage ( {
294302 type : 'init' ,
295303 themeData,
@@ -333,6 +341,23 @@ class SessionLogView extends Disposable {
333341 }
334342}
335343
344+ function toPullInfo ( pullRequest : PullRequestModel ) : SessionPullInfo & { title : string ; } {
345+ return {
346+ host : pullRequest . githubRepository . remote . gitProtocol . host ,
347+ owner : pullRequest . githubRepository . remote . owner ,
348+ repo : pullRequest . githubRepository . remote . repositoryName ,
349+ pullId : pullRequest . number ,
350+ title : pullRequest . title ,
351+ } ;
352+ }
353+
354+ function arePullInfosEqual ( a : SessionPullInfo , b : SessionPullInfo ) : boolean {
355+ return a . host === b . host &&
356+ a . owner === b . owner &&
357+ a . repo === b . repo &&
358+ a . pullId === b . pullId ;
359+ }
360+
336361async function loadCurrentThemeData ( ) : Promise < any > {
337362 let themeData : any = null ;
338363 const currentThemeName = vscode . workspace . getConfiguration ( 'workbench' ) . get < string > ( 'colorTheme' ) ;
0 commit comments