mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 16:50:30 -04:00
Merge from vscode 9bc92b48d945144abb405b9e8df05e18accb9148
This commit is contained in:
@@ -12,9 +12,9 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { StatusbarAlignment, IStatusbarService } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity';
|
||||
import { INotificationService, Severity, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification';
|
||||
import { INotificationService, Severity, INotificationHandle } from 'vs/platform/notification/common/notification';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { Dialog } from 'vs/base/browser/ui/dialog/dialog';
|
||||
@@ -143,10 +143,72 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
}
|
||||
}
|
||||
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
const toDispose = new DisposableStore();
|
||||
private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<IProgressStep>) => P, onDidCancel?: (choice?: number) => void): P {
|
||||
|
||||
const progressStateModel = new class extends Disposable {
|
||||
|
||||
private readonly _onDidReport = this._register(new Emitter<IProgressStep>());
|
||||
readonly onDidReport = this._onDidReport.event;
|
||||
|
||||
private readonly _onDispose = this._register(new Emitter<void>());
|
||||
readonly onDispose = this._onDispose.event;
|
||||
|
||||
private _step: IProgressStep | undefined = undefined;
|
||||
get step() { return this._step; }
|
||||
|
||||
private _done = false;
|
||||
get done() { return this._done; }
|
||||
|
||||
readonly promise: P;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.promise = callback(this);
|
||||
|
||||
this.promise.finally(() => {
|
||||
this.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
report(step: IProgressStep): void {
|
||||
this._step = step;
|
||||
|
||||
this._onDidReport.fire(step);
|
||||
}
|
||||
|
||||
cancel(choice?: number): void {
|
||||
onDidCancel?.(choice);
|
||||
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._done = true;
|
||||
this._onDispose.fire();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
const createWindowProgress = () => {
|
||||
this.withWindowProgress<R>({
|
||||
location: ProgressLocation.Window,
|
||||
title: options.title
|
||||
}, progress => {
|
||||
if (progressStateModel.step) {
|
||||
progress.report(progressStateModel.step);
|
||||
}
|
||||
|
||||
const disposable = progressStateModel.onDidReport(step => progress.report(step));
|
||||
Event.once(progressStateModel.onDispose)(() => disposable.dispose());
|
||||
|
||||
return progressStateModel.promise;
|
||||
});
|
||||
};
|
||||
|
||||
const createNotification = (message: string, increment?: number): INotificationHandle => {
|
||||
const notificationDisposables = new DisposableStore();
|
||||
|
||||
const primaryActions = options.primaryActions ? Array.from(options.primaryActions) : [];
|
||||
const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : [];
|
||||
@@ -158,16 +220,11 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
super(`progress.button.${button}`, button, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel(index);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
async run(): Promise<any> {
|
||||
progressStateModel.cancel(index);
|
||||
}
|
||||
};
|
||||
|
||||
toDispose.add(buttonAction);
|
||||
notificationDisposables.add(buttonAction);
|
||||
|
||||
primaryActions.push(buttonAction);
|
||||
});
|
||||
@@ -179,31 +236,35 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
super('progress.cancel', localize('cancel', "Cancel"), undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<any> {
|
||||
if (typeof onDidCancel === 'function') {
|
||||
onDidCancel();
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
async run(): Promise<any> {
|
||||
progressStateModel.cancel();
|
||||
}
|
||||
};
|
||||
toDispose.add(cancelAction);
|
||||
notificationDisposables.add(cancelAction);
|
||||
|
||||
primaryActions.push(cancelAction);
|
||||
}
|
||||
|
||||
const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions };
|
||||
const handle = this.notificationService.notify({
|
||||
severity: Severity.Info,
|
||||
message,
|
||||
source: options.source,
|
||||
actions
|
||||
actions: { primary: primaryActions, secondary: secondaryActions }
|
||||
});
|
||||
|
||||
updateProgress(handle, increment);
|
||||
|
||||
Event.once(handle.onDidClose)(() => {
|
||||
toDispose.dispose();
|
||||
|
||||
// Switch to window based progress once the notification
|
||||
// is being closed even though still running and not
|
||||
// cancelled.
|
||||
if (!progressStateModel.done) {
|
||||
createWindowProgress();
|
||||
}
|
||||
|
||||
// Clear disposables
|
||||
notificationDisposables.dispose();
|
||||
});
|
||||
|
||||
return handle;
|
||||
@@ -218,60 +279,54 @@ export class ProgressService extends Disposable implements IProgressService {
|
||||
}
|
||||
};
|
||||
|
||||
let handle: INotificationHandle | undefined;
|
||||
let handleSoon: any | undefined;
|
||||
|
||||
let notificationHandle: INotificationHandle | undefined;
|
||||
let notificationTimeout: any | undefined;
|
||||
let titleAndMessage: string | undefined; // hoisted to make sure a delayed notification shows the most recent message
|
||||
|
||||
const updateNotification = (message?: string, increment?: number): void => {
|
||||
const updateNotification = (step?: IProgressStep): void => {
|
||||
|
||||
// full message (inital or update)
|
||||
if (message && options.title) {
|
||||
titleAndMessage = `${options.title}: ${message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932)
|
||||
if (step?.message && options.title) {
|
||||
titleAndMessage = `${options.title}: ${step.message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932)
|
||||
} else {
|
||||
titleAndMessage = options.title || message;
|
||||
titleAndMessage = options.title || step?.message;
|
||||
}
|
||||
|
||||
if (!handle && titleAndMessage) {
|
||||
if (!notificationHandle && titleAndMessage) {
|
||||
|
||||
// create notification now or after a delay
|
||||
if (typeof options.delay === 'number' && options.delay > 0) {
|
||||
if (typeof handleSoon !== 'number') {
|
||||
handleSoon = setTimeout(() => handle = createNotification(titleAndMessage!, increment), options.delay);
|
||||
if (typeof notificationTimeout !== 'number') {
|
||||
notificationTimeout = setTimeout(() => notificationHandle = createNotification(titleAndMessage!, step?.increment), options.delay);
|
||||
}
|
||||
} else {
|
||||
handle = createNotification(titleAndMessage, increment);
|
||||
notificationHandle = createNotification(titleAndMessage, step?.increment);
|
||||
}
|
||||
}
|
||||
|
||||
if (handle) {
|
||||
if (notificationHandle) {
|
||||
if (titleAndMessage) {
|
||||
handle.updateMessage(titleAndMessage);
|
||||
notificationHandle.updateMessage(titleAndMessage);
|
||||
}
|
||||
if (typeof increment === 'number') {
|
||||
updateProgress(handle, increment);
|
||||
|
||||
if (typeof step?.increment === 'number') {
|
||||
updateProgress(notificationHandle, step.increment);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Show initially
|
||||
updateNotification();
|
||||
|
||||
// Update based on progress
|
||||
const promise = callback({
|
||||
report: progress => {
|
||||
updateNotification(progress.message, progress.increment);
|
||||
}
|
||||
});
|
||||
updateNotification(progressStateModel.step);
|
||||
const listener = progressStateModel.onDidReport(step => updateNotification(step));
|
||||
Event.once(progressStateModel.onDispose)(() => listener.dispose());
|
||||
|
||||
// Show progress for at least 800ms and then hide once done or canceled
|
||||
Promise.all([timeout(800), promise]).finally(() => {
|
||||
clearTimeout(handleSoon);
|
||||
if (handle) {
|
||||
handle.close();
|
||||
}
|
||||
Promise.all([timeout(800), progressStateModel.promise]).finally(() => {
|
||||
clearTimeout(notificationTimeout);
|
||||
notificationHandle?.close();
|
||||
});
|
||||
|
||||
return promise;
|
||||
return progressStateModel.promise;
|
||||
}
|
||||
|
||||
private withViewletProgress<P extends Promise<R>, R = unknown>(viewletId: string, task: (progress: IProgress<IProgressStep>) => P, options: IProgressCompositeOptions): P {
|
||||
|
||||
Reference in New Issue
Block a user