feat - add chat lifecycle handler for shutdown veto (#255617)

This commit is contained in:
Benjamin Pasero
2025-07-13 11:38:25 +02:00
committed by GitHub
parent b8c44fbcab
commit 09a342a67b
3 changed files with 63 additions and 9 deletions
@@ -467,10 +467,10 @@ export class Menubar extends Disposable {
const { response } = await this.nativeHostMainService.showMessageBox(this.windowsMainService.getFocusedWindow()?.id, {
type: 'question',
buttons: [
nls.localize({ key: 'quit', comment: ['&& denotes a mnemonic'] }, "&&Quit"),
isMacintosh ? nls.localize({ key: 'quit', comment: ['&& denotes a mnemonic'] }, "&&Quit") : nls.localize({ key: 'exit', comment: ['&& denotes a mnemonic'] }, "&&Exit"),
nls.localize('cancel', "Cancel")
],
message: nls.localize('quitMessage', "Are you sure you want to quit?")
message: isMacintosh ? nls.localize('quitMessageMac', "Are you sure you want to quit?") : nls.localize('quitMessage', "Are you sure you want to exit?")
});
return response === 0;
@@ -30,6 +30,7 @@ import { ILifecycleService, ShutdownReason } from '../../../services/lifecycle/c
import { IWorkingCopyService } from '../../../services/workingCopy/common/workingCopyService.js';
import { OpaqueEdits, ResourceAttachmentEdit } from './opaqueEdits.js';
import { TextModelEditReason } from '../../../../editor/common/textModelEditReason.js';
import { isMacintosh } from '../../../../base/common/platform.js';
function liftEdits(edits: ResourceEdit[]): ResourceEdit[] {
return edits.map(edit => {
@@ -295,30 +296,24 @@ export class BulkEditService implements IBulkEditService {
private async _shouldVeto(label: string | undefined, reason: ShutdownReason): Promise<boolean> {
let message: string;
let primaryButton: string;
switch (reason) {
case ShutdownReason.CLOSE:
message = localize('closeTheWindow.message', "Are you sure you want to close the window?");
primaryButton = localize({ key: 'closeTheWindow', comment: ['&& denotes a mnemonic'] }, "&&Close Window");
break;
case ShutdownReason.LOAD:
message = localize('changeWorkspace.message', "Are you sure you want to change the workspace?");
primaryButton = localize({ key: 'changeWorkspace', comment: ['&& denotes a mnemonic'] }, "Change &&Workspace");
break;
case ShutdownReason.RELOAD:
message = localize('reloadTheWindow.message', "Are you sure you want to reload the window?");
primaryButton = localize({ key: 'reloadTheWindow', comment: ['&& denotes a mnemonic'] }, "&&Reload Window");
break;
default:
message = localize('quit.message', "Are you sure you want to quit?");
primaryButton = localize({ key: 'quit', comment: ['&& denotes a mnemonic'] }, "&&Quit");
message = isMacintosh ? localize('quitMessageMac', "Are you sure you want to quit?") : localize('quitMessage', "Are you sure you want to exit?");
break;
}
const result = await this._dialogService.confirm({
message,
detail: localize('areYouSureQuiteBulkEdit.detail', "'{0}' is in progress.", label || localize('fileOperation', "File operation")),
primaryButton
});
return !result.confirmed;
@@ -30,6 +30,9 @@ import { ViewContainerLocation } from '../../../common/views.js';
import { INativeHostService } from '../../../../platform/native/common/native.js';
import { IChatService } from '../common/chatService.js';
import { autorun } from '../../../../base/common/observable.js';
import { ILifecycleService, ShutdownReason } from '../../../services/lifecycle/common/lifecycle.js';
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
import { isMacintosh } from '../../../../base/common/platform.js';
class NativeBuiltinToolsContribution extends Disposable implements IWorkbenchContribution {
@@ -130,6 +133,61 @@ class ChatSuspendThrottlingHandler extends Disposable {
}
}
class ChatLifecycleHandler extends Disposable {
static readonly ID = 'workbench.contrib.chatLifecycleHandler';
constructor(
@ILifecycleService lifecycleService: ILifecycleService,
@IChatService private readonly chatService: IChatService,
@IDialogService private readonly dialogService: IDialogService,
@IViewsService private readonly viewsService: IViewsService
) {
super();
this._register(lifecycleService.onBeforeShutdown(e => {
e.veto(this.shouldVetoShutdown(e.reason), 'veto.chat');
}));
}
private shouldVetoShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
const running = this.chatService.requestInProgressObs.read(undefined);
if (!running) {
return false;
}
return this.doShouldVetoShutdown(reason);
}
private async doShouldVetoShutdown(reason: ShutdownReason): Promise<boolean> {
showChatView(this.viewsService);
let message: string;
switch (reason) {
case ShutdownReason.CLOSE:
message = localize('closeTheWindow.message', "A chat request is in progress. Are you sure you want to close the window?");
break;
case ShutdownReason.LOAD:
message = localize('changeWorkspace.message', "A chat request is in progress. Are you sure you want to change the workspace?");
break;
case ShutdownReason.RELOAD:
message = localize('reloadTheWindow.message', "A chat request is in progress. Are you sure you want to reload the window?");
break;
default:
message = isMacintosh ? localize('quit.message', "A chat request is in progress. Are you sure you want to quit?") : localize('exit.message', "A chat request is in progress. Are you sure you want to exit?");
break;
}
const result = await this.dialogService.confirm({
message,
detail: localize('quit.detail', "The chat request will be cancelled if you continue.")
});
return !result.confirmed;
}
}
registerAction2(StartVoiceChatAction);
registerAction2(InstallSpeechProviderForVoiceChatAction);
@@ -151,3 +209,4 @@ registerWorkbenchContribution2(KeywordActivationContribution.ID, KeywordActivati
registerWorkbenchContribution2(NativeBuiltinToolsContribution.ID, NativeBuiltinToolsContribution, WorkbenchPhase.AfterRestored);
registerWorkbenchContribution2(ChatCommandLineHandler.ID, ChatCommandLineHandler, WorkbenchPhase.BlockRestore);
registerWorkbenchContribution2(ChatSuspendThrottlingHandler.ID, ChatSuspendThrottlingHandler, WorkbenchPhase.AfterRestored);
registerWorkbenchContribution2(ChatLifecycleHandler.ID, ChatLifecycleHandler, WorkbenchPhase.AfterRestored);