diff --git a/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts b/src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionFollowups.ts index bf91e5c6dca8..733e66029b8a 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, IButtonStyles } 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: IButtonStyles | undefined, 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, 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 4450ebdc666d..1b3ee53dd077 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, 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 1b0d2eabc3b4..cf279daa3dd0 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' : ''}`; }, } }); @@ -206,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 4a2f43789a88..9517164fa9db 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; @@ -240,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; } @@ -247,3 +247,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; +} 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, 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); }