From 0162d3386b80c608d3f5b39535ca4cea9c7470c6 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 13 Mar 2023 11:01:23 -0700 Subject: [PATCH 1/5] Rerender request items once slash commands are loaded --- .../browser/interactiveSessionWidget.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts index 1b0d2eabc3b4..a94a44960582 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts @@ -112,7 +112,9 @@ export class InteractiveSessionWidget extends Disposable implements IInteractive this.slashCommandsPromise = undefined; this.lastSlashCommands = undefined; - this.getSlashCommands(); // start the refresh + this.getSlashCommands().then(() => { + this.onDidChangeItems(); + }); this._onDidChangeViewModel.fire(); } @@ -186,8 +188,8 @@ export class InteractiveSessionWidget extends Disposable implements IInteractive this.tree.setChildren(null, treeItems, { diffIdentityProvider: { - getId(element) { - return element.id; + getId: (element) => { + return element.id + `${isRequestVM(element) && !!this.lastSlashCommands ? '_scLoaded' : ''}`; }, } }); From d3d57e928ca550cf6083fc0e21f28f6ba3ada178 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 13 Mar 2023 11:23:01 -0700 Subject: [PATCH 2/5] Fix command button rendering --- .../browser/interactiveSessionFollowups.ts | 7 ++++--- .../browser/interactiveSessionListRenderer.ts | 2 ++ .../browser/interactiveSessionWidget.ts | 2 +- .../browser/media/interactiveSession.css | 11 +++++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts index bf91e5c6dca8..5da4093047ca 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; import * as dom from 'vs/base/browser/dom'; +import { Button, IButtonOptions } from 'vs/base/browser/ui/button/button'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IInteractiveSessionFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService'; -import { Button } from 'vs/base/browser/ui/button/button'; const $ = dom.$; @@ -14,6 +14,7 @@ export class InteractiveSessionFollowups constructor( container: HTMLElement, followups: T[], + private readonly options: IButtonOptions, private readonly clickHandler: (followup: T) => void, ) { super(); @@ -23,7 +24,7 @@ export class InteractiveSessionFollowups } private renderFollowup(container: HTMLElement, followup: T): void { - const button = this._register(new Button(container, { supportIcons: typeof followup !== 'string' })); + const button = this._register(new Button(container, this.options)); const label = followup.kind === 'reply' ? '$(wand) ' + (followup.title || followup.message) : followup.title; diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts index 4450ebdc666d..845437bfa60d 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts @@ -37,6 +37,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILogService } from 'vs/platform/log/common/log'; +import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles'; import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; @@ -231,6 +232,7 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend templateData.elementDisposables.add(new InteractiveSessionFollowups( followupsContainer, element.commandFollowups, + { ...defaultButtonStyles, supportIcons: true }, followup => this.commandService.executeCommand(followup.commandId, ...(followup.args ?? [])))); } } diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts index a94a44960582..77ffe6bcd50e 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts @@ -208,7 +208,7 @@ export class InteractiveSessionWidget extends Disposable implements IInteractive dom.clearNode(this.followupsContainer); if (items) { - this.followupsDisposables.add(new InteractiveSessionFollowups(this.followupsContainer, items, followup => this.acceptInput(followup.message))); + this.followupsDisposables.add(new InteractiveSessionFollowups(this.followupsContainer, items, {}, followup => this.acceptInput(followup.message))); } if (this.bodyDimension) { diff --git a/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css b/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css index 4a2f43789a88..d26082cd1c4d 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css +++ b/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css @@ -226,10 +226,6 @@ .interactive-session .interactive-session-followups .monaco-button { width: initial; - padding: 0px; - font-size: 11px; - font-weight: 600; - border: none; color: var(--vscode-textLink-foreground); justify-content: left; @@ -247,3 +243,10 @@ .interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups { margin-bottom: 8px; } + +.interactive-session .interactive-input-part .interactive-input-followups .interactive-session-followups .monaco-button { + padding: 0px; + font-size: 11px; + font-weight: 600; + border: none; +} From 427c8ceb168cecc0715eb9b41dc538ebbc521655 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 13 Mar 2023 11:33:14 -0700 Subject: [PATCH 3/5] dead code --- .../common/interactiveSessionService.ts | 1 - .../common/interactiveSessionServiceImpl.ts | 21 +------------------ 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionService.ts b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionService.ts index bbf9e6aced75..d73fe0c672ea 100644 --- a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionService.ts +++ b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionService.ts @@ -118,7 +118,6 @@ export interface IInteractiveSessionService { acceptNewSessionState(sessionId: number, state: any): void; addInteractiveRequest(context: any): void; provideSuggestions(providerId: string, token: CancellationToken): Promise; - // provideFollowups(sessionId: number, token: CancellationToken): Promise; onDidPerformUserAction: Event; notifyUserAction(event: IInteractiveSessionUserActionEvent): void; diff --git a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionServiceImpl.ts b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionServiceImpl.ts index 5af2ad4d69f2..21a9aa084fd6 100644 --- a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionServiceImpl.ts @@ -15,7 +15,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ISerializableInteractiveSessionData, ISerializableInteractiveSessionsData, InteractiveSessionModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionModel'; -import { IInteractiveProgress, IInteractiveProvider, IInteractiveSessionFollowup, IInteractiveSessionService, IInteractiveSessionUserActionEvent, IInteractiveSlashCommand } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService'; +import { IInteractiveProgress, IInteractiveProvider, IInteractiveSessionService, IInteractiveSessionUserActionEvent, IInteractiveSlashCommand } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; const serializedInteractiveSessionKey = 'interactive.sessions'; @@ -72,25 +72,6 @@ export class InteractiveSessionService extends Disposable implements IInteractiv })); } - async provideFollowups(sessionId: number, token: CancellationToken): Promise { - this.trace('provideFollowups', `sessionId: ${sessionId}`); - const model = this._sessionModels.get(sessionId); - if (!model) { - throw new Error(`Unknown session: ${sessionId}`); - } - - const provider = this._providers.get(model.providerId); - if (!provider) { - throw new Error(`Unknown provider: ${model.providerId}`); - } - - if (!provider.provideFollowups) { - return; - } - - return withNullAsUndefined(await provider.provideFollowups(model.session, token)); - } - notifyUserAction(action: IInteractiveSessionUserActionEvent): void { this._onDidPerformUserAction.fire(action); } From 1a78f7dc1c1699d01d4fb5cec1a6f80d466daa4e Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 13 Mar 2023 11:33:31 -0700 Subject: [PATCH 4/5] Support serializing followups --- .../interactiveSession/common/interactiveSessionModel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionModel.ts b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionModel.ts index 4ef8f2dec9ee..53e5c4871dc5 100644 --- a/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionModel.ts +++ b/src/vs/workbench/contrib/interactiveSession/common/interactiveSessionModel.ts @@ -143,6 +143,7 @@ export interface ISerializableInteractiveSessionRequestData { message: string; response: string | undefined; responseErrorDetails: IInteractiveResponseErrorDetails | undefined; + followups: IInteractiveSessionFollowup[] | undefined; } export interface ISerializableInteractiveSessionData { @@ -202,7 +203,7 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS return requests.map((raw: ISerializableInteractiveSessionRequestData) => { const request = new InteractiveRequestModel(raw.message, this.session.requesterUsername, this.session.requesterAvatarIconUri); if (raw.response || raw.responseErrorDetails) { - request.response = new InteractiveResponseModel(new MarkdownString(raw.response), this.session.responderUsername, this.providerId, this.session.responderAvatarIconUri, true, raw.providerResponseId, raw.responseErrorDetails); + request.response = new InteractiveResponseModel(new MarkdownString(raw.response), this.session.responderUsername, this.providerId, this.session.responderAvatarIconUri, true, raw.providerResponseId, raw.responseErrorDetails, raw.followups); } return request; }); @@ -275,7 +276,8 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS providerResponseId: r.response?.providerResponseId, message: r.message, response: r.response ? r.response.response.value : undefined, - responseErrorDetails: r.response?.errorDetails + responseErrorDetails: r.response?.errorDetails, + followups: r.response?.followups }; }), providerId: this.providerId, From e73602cf763c3e8adaecaaab4d5a29ee94044dad Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Mon, 13 Mar 2023 11:33:47 -0700 Subject: [PATCH 5/5] Fix command followup styling --- .../browser/interactiveSessionFollowups.ts | 6 +++--- .../browser/interactiveSessionListRenderer.ts | 2 +- .../interactiveSession/browser/interactiveSessionWidget.ts | 2 +- .../interactiveSession/browser/media/interactiveSession.css | 4 ++++ 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts index 5da4093047ca..733e66029b8a 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { Button, IButtonOptions } from 'vs/base/browser/ui/button/button'; +import { Button, IButtonStyles } from 'vs/base/browser/ui/button/button'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInteractiveSessionFollowup } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService'; @@ -14,7 +14,7 @@ export class InteractiveSessionFollowups constructor( container: HTMLElement, followups: T[], - private readonly options: IButtonOptions, + private readonly options: IButtonStyles | undefined, private readonly clickHandler: (followup: T) => void, ) { super(); @@ -24,7 +24,7 @@ export class InteractiveSessionFollowups } private renderFollowup(container: HTMLElement, followup: T): void { - const button = this._register(new Button(container, this.options)); + const button = this._register(new Button(container, { ...this.options, supportIcons: true })); const label = followup.kind === 'reply' ? '$(wand) ' + (followup.title || followup.message) : followup.title; diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts index 845437bfa60d..1b3ee53dd077 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer.ts @@ -232,7 +232,7 @@ export class InteractiveListItemRenderer extends Disposable implements ITreeRend templateData.elementDisposables.add(new InteractiveSessionFollowups( followupsContainer, element.commandFollowups, - { ...defaultButtonStyles, supportIcons: true }, + defaultButtonStyles, followup => this.commandService.executeCommand(followup.commandId, ...(followup.args ?? [])))); } } diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts index 77ffe6bcd50e..cf279daa3dd0 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts +++ b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts @@ -208,7 +208,7 @@ export class InteractiveSessionWidget extends Disposable implements IInteractive dom.clearNode(this.followupsContainer); if (items) { - this.followupsDisposables.add(new InteractiveSessionFollowups(this.followupsContainer, items, {}, followup => this.acceptInput(followup.message))); + this.followupsDisposables.add(new InteractiveSessionFollowups(this.followupsContainer, items, undefined, followup => this.acceptInput(followup.message))); } if (this.bodyDimension) { diff --git a/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css b/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css index d26082cd1c4d..9517164fa9db 100644 --- a/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css +++ b/src/vs/workbench/contrib/interactiveSession/browser/media/interactiveSession.css @@ -236,6 +236,10 @@ margin-left: 0; } +.interactive-session .interactive-response-followups .monaco-button { + padding: 4px 8px; +} + .interactive-session .interactive-input-part .interactive-input-followups { padding: 0px 20px; }