mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-10 05:28:19 -05:00
Agents mobile: phone-aware dialog handler (#323741)
* Agents mobile (prototype): phone-aware dialog handler Render IDialogService confirm/prompt as native bottom sheets on phone layout, covering every modal in the Agents window in one place instead of converting call sites individually. The Agents window now registers a MobileDialogHandlerContribution (in place of the standard web dialog handler) that drains the shared dialog model through a MobileAwareDialogHandler. That handler delegates to the standard BrowserDialogHandler off-phone and for text input / about, and on phone maps the dialog model (message + detail + ordered buttons + optional checkbox) onto a bottom sheet via the existing showMobileContentSheet primitive: full-width stacked buttons at 44px, the safe action styled secondary, focus moved into the sheet and restored on close. Because confirmations from the sessions layer AND inherited chat / workbench dialogs all flow through one handler, this covers them uniformly (e.g. delete session, delete chat, discard changes, sign out) without per-call-site work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Agents mobile: drop the bespoke archive confirm sheet The phone-aware dialog handler now renders every IDialogService.confirm as a bottom sheet on phone, so the per-call-site mobileArchiveConfirmSheet is redundant. Collapse ArchiveSectionAction back to a single dialogService.confirm (matching the group "Mark All as Done" action) and delete the bespoke helper. This also brings the section archive-all in line with the group archive-all: both now flow through the handler and get the same sheet on phone, including the "Do not ask me again" checkbox (safe to surface now that it renders in a proper bottom sheet rather than the previously cramped desktop dialog). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: live checkbox state + dialog aria-describedby - Track the chosen button and checkbox state across the whole interaction so a backdrop / Escape dismiss (or a checkbox toggle) returns the live values instead of a snapshot captured only on button click. - Wire the message / detail to the sheet's role="dialog" element via aria-describedby so screen readers announce them when the sheet opens. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import Severity from '../../../../base/common/severity.js';
|
||||
import { mnemonicButtonLabel } from '../../../../base/common/labels.js';
|
||||
import { localize } from '../../../../nls.js';
|
||||
import { AbstractDialogHandler, DialogType, IConfirmation, IConfirmationResult, IInput, IInputResult, IPrompt, IAsyncPromptResult } from '../../../../platform/dialogs/common/dialogs.js';
|
||||
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { BrowserDialogHandler } from '../../../../workbench/browser/parts/dialogs/dialogHandler.js';
|
||||
import { IWorkbenchLayoutService } from '../../../../workbench/services/layout/browser/layoutService.js';
|
||||
import { isPhoneLayout } from '../mobile/mobileLayout.js';
|
||||
import { IMobileDialogSheetButton, showMobileDialogSheet } from './mobileDialogSheet.js';
|
||||
|
||||
/**
|
||||
* Dialog handler for the Agents window that renders confirmations and prompts
|
||||
* as native bottom sheets on phone layout, and otherwise delegates to the
|
||||
* standard {@link BrowserDialogHandler}.
|
||||
*
|
||||
* Because every `IDialogService.confirm` / `prompt` call (sessions-layer or
|
||||
* inherited from chat / workbench) flows through a single handler, routing it
|
||||
* here gives every modal a phone-appropriate presentation without converting
|
||||
* call sites one by one. Text input and the about dialog keep the desktop
|
||||
* rendering for now.
|
||||
*/
|
||||
export class MobileAwareDialogHandler extends AbstractDialogHandler {
|
||||
|
||||
private readonly _desktop: BrowserDialogHandler;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
) {
|
||||
super();
|
||||
this._desktop = instantiationService.createInstance(BrowserDialogHandler);
|
||||
}
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
if (!isPhoneLayout(this._layoutService)) {
|
||||
return this._desktop.confirm(confirmation);
|
||||
}
|
||||
|
||||
const labels = this.getConfirmationButtons(confirmation); // [primary, cancel]
|
||||
const cancelIndex = labels.length - 1;
|
||||
const { button, checkboxChecked } = await showMobileDialogSheet(this._layoutService, {
|
||||
title: this._titleFor(confirmation.type),
|
||||
message: confirmation.message,
|
||||
detail: confirmation.detail,
|
||||
buttons: this._toSheetButtons(labels, cancelIndex),
|
||||
defaultButtonIndex: cancelIndex,
|
||||
checkbox: confirmation.checkbox,
|
||||
});
|
||||
|
||||
return { confirmed: button === 0, checkboxChecked };
|
||||
}
|
||||
|
||||
async prompt<T>(prompt: IPrompt<T>): Promise<IAsyncPromptResult<T>> {
|
||||
if (!isPhoneLayout(this._layoutService)) {
|
||||
return this._desktop.prompt(prompt);
|
||||
}
|
||||
|
||||
const labels = this.getPromptButtons(prompt);
|
||||
const cancelIndex = prompt.cancelButton ? labels.length - 1 : -1;
|
||||
const { button, checkboxChecked } = await showMobileDialogSheet(this._layoutService, {
|
||||
title: this._titleFor(prompt.type),
|
||||
message: prompt.message,
|
||||
detail: prompt.detail,
|
||||
buttons: this._toSheetButtons(labels, cancelIndex),
|
||||
defaultButtonIndex: cancelIndex >= 0 ? cancelIndex : 0,
|
||||
checkbox: prompt.checkbox,
|
||||
});
|
||||
|
||||
return this.getPromptResult(prompt, button, checkboxChecked);
|
||||
}
|
||||
|
||||
// Text input and the about dialog keep the desktop rendering for now.
|
||||
input(input: IInput): Promise<IInputResult> {
|
||||
return this._desktop.input(input);
|
||||
}
|
||||
|
||||
about(title: string, details: string, detailsToCopy: string): Promise<void> {
|
||||
return this._desktop.about(title, details, detailsToCopy);
|
||||
}
|
||||
|
||||
private _toSheetButtons(labels: string[], cancelIndex: number): IMobileDialogSheetButton[] {
|
||||
return labels.map((label, index) => ({
|
||||
label: mnemonicButtonLabel(label, true),
|
||||
isCancel: index === cancelIndex,
|
||||
}));
|
||||
}
|
||||
|
||||
private _titleFor(type: Severity | DialogType | undefined): string {
|
||||
switch (this.getDialogType(type)) {
|
||||
case 'error': return localize('mobileDialog.error', "Error");
|
||||
case 'warning': return localize('mobileDialog.warning', "Warning");
|
||||
default: return localize('mobileDialog.confirm', "Confirm");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { Lazy } from '../../../../base/common/lazy.js';
|
||||
import { IDialogHandler, IDialogResult, IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
|
||||
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { IProductService } from '../../../../platform/product/common/productService.js';
|
||||
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../../workbench/common/contributions.js';
|
||||
import { IDialogsModel, IDialogViewItem } from '../../../../workbench/common/dialogs.js';
|
||||
import { createBrowserAboutDialogDetails } from '../../../../workbench/browser/parts/dialogs/dialog.js';
|
||||
import { DialogService } from '../../../../workbench/services/dialogs/common/dialogService.js';
|
||||
import { MobileAwareDialogHandler } from './mobileAwareDialogHandler.js';
|
||||
|
||||
/**
|
||||
* Agents-window variant of the workbench `DialogHandlerContribution` that
|
||||
* drains the shared {@link IDialogsModel} through a {@link MobileAwareDialogHandler},
|
||||
* so every confirmation / prompt renders as a bottom sheet on phone layout.
|
||||
*
|
||||
* Registered in place of the standard web dialog-handler contribution (which
|
||||
* the Agents window does not import), so only one handler drains the model.
|
||||
*/
|
||||
export class MobileDialogHandlerContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
static readonly ID = 'workbench.contrib.mobileDialogHandler';
|
||||
|
||||
private readonly model: IDialogsModel;
|
||||
private readonly impl: Lazy<IDialogHandler>;
|
||||
|
||||
private currentDialog: IDialogViewItem | undefined;
|
||||
|
||||
constructor(
|
||||
@IDialogService private dialogService: IDialogService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IProductService private productService: IProductService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.impl = new Lazy(() => instantiationService.createInstance(MobileAwareDialogHandler));
|
||||
this.model = (this.dialogService as DialogService).model;
|
||||
|
||||
this._register(this.model.onWillShowDialog(() => {
|
||||
if (!this.currentDialog) {
|
||||
this.processDialogs();
|
||||
}
|
||||
}));
|
||||
|
||||
this.processDialogs();
|
||||
}
|
||||
|
||||
private async processDialogs(): Promise<void> {
|
||||
while (this.model.dialogs.length) {
|
||||
this.currentDialog = this.model.dialogs[0];
|
||||
|
||||
let result: IDialogResult | Error | undefined = undefined;
|
||||
try {
|
||||
if (this.currentDialog.args.confirmArgs) {
|
||||
const args = this.currentDialog.args.confirmArgs;
|
||||
result = await this.impl.value.confirm(args.confirmation);
|
||||
} else if (this.currentDialog.args.inputArgs) {
|
||||
const args = this.currentDialog.args.inputArgs;
|
||||
result = await this.impl.value.input(args.input);
|
||||
} else if (this.currentDialog.args.promptArgs) {
|
||||
const args = this.currentDialog.args.promptArgs;
|
||||
result = await this.impl.value.prompt(args.prompt);
|
||||
} else {
|
||||
const aboutDialogDetails = createBrowserAboutDialogDetails(this.productService);
|
||||
await this.impl.value.about(aboutDialogDetails.title, aboutDialogDetails.details, aboutDialogDetails.detailsToCopy);
|
||||
}
|
||||
} catch (error) {
|
||||
result = error;
|
||||
}
|
||||
|
||||
this.currentDialog.close(result);
|
||||
this.currentDialog = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerWorkbenchContribution2(
|
||||
MobileDialogHandlerContribution.ID,
|
||||
MobileDialogHandlerContribution,
|
||||
WorkbenchPhase.BlockStartup // Block to allow for dialogs to show before restore finished
|
||||
);
|
||||
133
src/vs/sessions/browser/parts/dialogs/mobileDialogSheet.ts
Normal file
133
src/vs/sessions/browser/parts/dialogs/mobileDialogSheet.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { $, addDisposableListener, append, getActiveElement, isHTMLElement } from '../../../../base/browser/dom.js';
|
||||
import { Button } from '../../../../base/browser/ui/button/button.js';
|
||||
import { DisposableStore } from '../../../../base/common/lifecycle.js';
|
||||
import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js';
|
||||
import { IWorkbenchLayoutService } from '../../../../workbench/services/layout/browser/layoutService.js';
|
||||
import { showMobileContentSheet } from '../mobile/mobilePickerSheet.js';
|
||||
|
||||
/** Monotonic seed for unique aria id wiring across concurrent sheets. */
|
||||
let idSeed = 0;
|
||||
|
||||
/** A single action button rendered in the dialog sheet. */
|
||||
export interface IMobileDialogSheetButton {
|
||||
/** Display label (already stripped of mnemonics). */
|
||||
readonly label: string;
|
||||
/** When true the button is styled as the secondary / safe action. */
|
||||
readonly isCancel: boolean;
|
||||
}
|
||||
|
||||
export interface IMobileDialogSheetOptions {
|
||||
/** Sheet header title (single line). Usually a short category label. */
|
||||
readonly title: string;
|
||||
/** Primary message describing the action (wraps). */
|
||||
readonly message: string;
|
||||
/** Optional muted detail line beneath the message (wraps). */
|
||||
readonly detail?: string;
|
||||
/** Action buttons, in the dialog's canonical order (index is returned). */
|
||||
readonly buttons: readonly IMobileDialogSheetButton[];
|
||||
/** Index of the button to focus on open (typically the safe action). */
|
||||
readonly defaultButtonIndex: number;
|
||||
/** Optional checkbox row (e.g. "Do not ask me again"). */
|
||||
readonly checkbox?: { readonly label: string; readonly checked?: boolean };
|
||||
}
|
||||
|
||||
export interface IMobileDialogSheetResult {
|
||||
/** Index of the chosen button, or the cancel index when dismissed. */
|
||||
readonly button: number;
|
||||
readonly checkboxChecked?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a generic confirmation / prompt as a native mobile bottom sheet.
|
||||
*
|
||||
* Maps the workbench dialog model (message + detail + ordered buttons +
|
||||
* optional checkbox) onto {@link showMobileContentSheet}: full-width stacked
|
||||
* buttons with 44px tap targets, the safe action styled secondary. Tapping a
|
||||
* button resolves with its index; dismissing the sheet (backdrop / Escape)
|
||||
* resolves with the cancel index (or -1 when the dialog has no cancel).
|
||||
*
|
||||
* Focus is moved into the sheet on open (defaulting to the safe action) and
|
||||
* restored to the previously focused element on close, mirroring the desktop
|
||||
* dialog's behavior.
|
||||
*/
|
||||
export async function showMobileDialogSheet(layoutService: IWorkbenchLayoutService, options: IMobileDialogSheetOptions): Promise<IMobileDialogSheetResult> {
|
||||
const cancelIndex = options.buttons.findIndex(button => button.isCancel);
|
||||
|
||||
// Tracked across the whole interaction so both the dismiss path
|
||||
// (backdrop / Escape) and a button tap return the live values, not a
|
||||
// stale snapshot taken at click time.
|
||||
let chosenButton = cancelIndex;
|
||||
let checkboxChecked = options.checkbox?.checked;
|
||||
|
||||
const previouslyFocused = getActiveElement();
|
||||
|
||||
await showMobileContentSheet(
|
||||
layoutService.mainContainer,
|
||||
options.title,
|
||||
(body, api) => {
|
||||
const store = new DisposableStore();
|
||||
|
||||
const id = `mobile-dialog-${++idSeed}`;
|
||||
const describedBy: string[] = [];
|
||||
|
||||
const message = append(body, $('.mobile-content-sheet-message'));
|
||||
message.id = `${id}-message`;
|
||||
message.textContent = options.message;
|
||||
describedBy.push(message.id);
|
||||
|
||||
if (options.detail) {
|
||||
const detail = append(body, $('.mobile-content-sheet-detail'));
|
||||
detail.id = `${id}-detail`;
|
||||
detail.textContent = options.detail;
|
||||
describedBy.push(detail.id);
|
||||
}
|
||||
|
||||
// Associate the message / detail with the sheet's dialog element so
|
||||
// screen readers announce them when the sheet opens (the shell only
|
||||
// sets an aria-label from the title).
|
||||
body.closest('[role="dialog"]')?.setAttribute('aria-describedby', describedBy.join(' '));
|
||||
|
||||
if (options.checkbox) {
|
||||
const row = append(body, $('label.mobile-content-sheet-checkbox'));
|
||||
const checkbox = append(row, $('input')) as HTMLInputElement;
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.checked = !!options.checkbox.checked;
|
||||
append(row, $('span')).textContent = options.checkbox.label;
|
||||
store.add(addDisposableListener(checkbox, 'change', () => { checkboxChecked = checkbox.checked; }));
|
||||
}
|
||||
|
||||
const actions = append(body, $('.mobile-content-sheet-actions'));
|
||||
|
||||
let buttonToFocus: Button | undefined;
|
||||
options.buttons.forEach((descriptor, index) => {
|
||||
const button = store.add(new Button(actions, { ...defaultButtonStyles, secondary: descriptor.isCancel }));
|
||||
button.label = descriptor.label;
|
||||
store.add(button.onDidClick(() => {
|
||||
chosenButton = index;
|
||||
api.close();
|
||||
}));
|
||||
if (index === options.defaultButtonIndex) {
|
||||
buttonToFocus = button;
|
||||
}
|
||||
});
|
||||
|
||||
// Move focus into the modal sheet for keyboard / screen reader users.
|
||||
buttonToFocus?.focus();
|
||||
|
||||
return store;
|
||||
},
|
||||
{ hideDoneButton: true },
|
||||
);
|
||||
|
||||
if (isHTMLElement(previouslyFocused) && previouslyFocused.isConnected) {
|
||||
previouslyFocused.focus();
|
||||
}
|
||||
|
||||
return { button: chosenButton, checkboxChecked };
|
||||
}
|
||||
|
||||
@@ -284,6 +284,25 @@
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
/* Optional checkbox row (e.g. "Do not ask me again") for confirm-style
|
||||
* content sheets. Comfortable tap target with the control and label inline. */
|
||||
.mobile-content-sheet-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px 0;
|
||||
min-height: 44px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile-content-sheet-checkbox input {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* iOS grouped-list section header. The HIG uses a regular-case
|
||||
* footnote-sized label in secondary color — not the uppercased small
|
||||
* caps that older Settings rows used. */
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { $, append, getActiveElement, isHTMLElement } from '../../../../../base/browser/dom.js';
|
||||
import { Button } from '../../../../../base/browser/ui/button/button.js';
|
||||
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
|
||||
import { localize } from '../../../../../nls.js';
|
||||
import { defaultButtonStyles } from '../../../../../platform/theme/browser/defaultStyles.js';
|
||||
import { IWorkbenchLayoutService } from '../../../../../workbench/services/layout/browser/layoutService.js';
|
||||
import { showMobileContentSheet } from '../../../../browser/parts/mobile/mobilePickerSheet.js';
|
||||
|
||||
export interface IMobileArchiveConfirmOptions {
|
||||
/** Sheet header title (single line). */
|
||||
readonly title: string;
|
||||
/** Bold message describing the scope of the action (wraps). */
|
||||
readonly message: string;
|
||||
/** Muted detail line beneath the message (wraps). */
|
||||
readonly detail: string;
|
||||
/** Label for the primary, destructive action button. */
|
||||
readonly primaryLabel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Phone-only confirmation for a destructive "Mark All as Done" bulk action.
|
||||
* Presents a native bottom sheet (matching the other Agents-window mobile
|
||||
* surfaces) with an explicit, full-width destructive action and Cancel,
|
||||
* instead of squeezing the desktop modal dialog onto a phone.
|
||||
*
|
||||
* Resolves `true` only when the user taps the destructive action; any other
|
||||
* dismissal (Cancel, backdrop tap, Escape) resolves `false`.
|
||||
*
|
||||
* Unlike the desktop dialog, the sheet intentionally omits the "Do not ask
|
||||
* me again" opt-out: the persisted skip flag is shared across layouts, and
|
||||
* letting a mis-tap permanently disable confirmation for a destructive bulk
|
||||
* action is exactly the footgun this mobile treatment avoids.
|
||||
*/
|
||||
export async function confirmArchiveOnPhone(layoutService: IWorkbenchLayoutService, options: IMobileArchiveConfirmOptions): Promise<boolean> {
|
||||
let confirmed = false;
|
||||
|
||||
// Remember what had focus so we can restore it when the sheet closes,
|
||||
// mirroring `IDialogService.confirm`'s focus handling.
|
||||
const previouslyFocused = getActiveElement();
|
||||
|
||||
await showMobileContentSheet(
|
||||
layoutService.mainContainer,
|
||||
options.title,
|
||||
(body, api) => {
|
||||
const store = new DisposableStore();
|
||||
|
||||
const message = append(body, $('.mobile-content-sheet-message'));
|
||||
message.textContent = options.message;
|
||||
|
||||
const detail = append(body, $('.mobile-content-sheet-detail'));
|
||||
detail.textContent = options.detail;
|
||||
|
||||
const actions = append(body, $('.mobile-content-sheet-actions'));
|
||||
|
||||
const archiveButton = store.add(new Button(actions, { ...defaultButtonStyles }));
|
||||
archiveButton.label = options.primaryLabel;
|
||||
store.add(archiveButton.onDidClick(() => {
|
||||
confirmed = true;
|
||||
api.close();
|
||||
}));
|
||||
|
||||
const cancelButton = store.add(new Button(actions, { ...defaultButtonStyles, secondary: true }));
|
||||
cancelButton.label = localize('mobileArchiveConfirm.cancel', "Cancel");
|
||||
store.add(cancelButton.onDidClick(() => {
|
||||
confirmed = false;
|
||||
api.close();
|
||||
}));
|
||||
|
||||
// Move focus into the modal sheet for keyboard / screen reader
|
||||
// users, defaulting to the safe action so an accidental Enter
|
||||
// cancels rather than performing the destructive action.
|
||||
cancelButton.focus();
|
||||
|
||||
return store;
|
||||
},
|
||||
{ hideDoneButton: true },
|
||||
);
|
||||
|
||||
if (isHTMLElement(previouslyFocused) && previouslyFocused.isConnected) {
|
||||
previouslyFocused.focus();
|
||||
}
|
||||
|
||||
return confirmed;
|
||||
}
|
||||
@@ -33,9 +33,6 @@ import { ActiveSessionContextKeys } from '../../../changes/common/changes.js';
|
||||
import { hasActiveSessionFailedCIChecks } from '../../../changes/browser/checksActions.js';
|
||||
import { ISessionsPartService } from '../../../../services/sessions/browser/sessionsPartService.js';
|
||||
import { ISessionsService } from '../../../../services/sessions/browser/sessionsService.js';
|
||||
import { IWorkbenchLayoutService } from '../../../../../workbench/services/layout/browser/layoutService.js';
|
||||
import { isPhoneLayout } from '../../../../browser/parts/mobile/mobileLayout.js';
|
||||
import { confirmArchiveOnPhone } from '../mobile/mobileArchiveConfirmSheet.js';
|
||||
|
||||
const CLOSE_SESSION_COMMAND_ID = 'sessionsViewPane.closeSession';
|
||||
registerAction2(class CloseSessionAction extends Action2 {
|
||||
@@ -515,37 +512,24 @@ registerAction2(class ArchiveSectionAction extends Action2 {
|
||||
const sessionsManagementService = accessor.get(ISessionsManagementService);
|
||||
const dialogService = accessor.get(IDialogService);
|
||||
const storageService = accessor.get(IStorageService);
|
||||
const layoutService = accessor.get(IWorkbenchLayoutService);
|
||||
|
||||
const skipConfirmation = storageService.getBoolean(ConfirmArchiveStorageKey, StorageScope.PROFILE, false);
|
||||
if (!skipConfirmation) {
|
||||
if (isPhoneLayout(layoutService)) {
|
||||
const confirmed = await confirmArchiveOnPhone(layoutService, {
|
||||
title: localize('archiveSectionSheet.title', "Mark All as Done"),
|
||||
message: getArchiveSectionConfirmationMessage(context),
|
||||
detail: localize('archiveSectionSessions.detail', "You can restore sessions later if needed from the sessions view."),
|
||||
primaryLabel: localize('archiveSectionSessions.archive', "Mark All as Done"),
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
const confirmed = await dialogService.confirm({
|
||||
message: getArchiveSectionConfirmationMessage(context),
|
||||
detail: localize('archiveSectionSessions.detail', "You can restore sessions later if needed from the sessions view."),
|
||||
primaryButton: localize('archiveSectionSessions.archive', "Mark All as Done"),
|
||||
checkbox: {
|
||||
label: localize('doNotAskAgain', "Do not ask me again")
|
||||
}
|
||||
} else {
|
||||
const confirmed = await dialogService.confirm({
|
||||
message: getArchiveSectionConfirmationMessage(context),
|
||||
detail: localize('archiveSectionSessions.detail', "You can restore sessions later if needed from the sessions view."),
|
||||
primaryButton: localize('archiveSectionSessions.archive', "Mark All as Done"),
|
||||
checkbox: {
|
||||
label: localize('doNotAskAgain', "Do not ask me again")
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (!confirmed.confirmed) {
|
||||
return;
|
||||
}
|
||||
if (!confirmed.confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmed.checkboxChecked) {
|
||||
storageService.store(ConfirmArchiveStorageKey, true, StorageScope.PROFILE, StorageTarget.USER);
|
||||
}
|
||||
if (confirmed.checkboxChecked) {
|
||||
storageService.store(ConfirmArchiveStorageKey, true, StorageScope.PROFILE, StorageTarget.USER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ import './sessions.common.main.js';
|
||||
|
||||
//#region --- workbench parts
|
||||
|
||||
import '../workbench/browser/parts/dialogs/dialog.web.contribution.js';
|
||||
// Agents window uses a phone-aware dialog handler (bottom sheets on phone)
|
||||
// in place of the standard web dialog handler.
|
||||
import './browser/parts/dialogs/mobileDialog.web.contribution.js';
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user