mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 02:48:30 -05:00
Merge from vscode 33a65245075e4d18908652865a79cf5489c30f40 (#9279)
* Merge from vscode 33a65245075e4d18908652865a79cf5489c30f40 * remove github
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { posix } from 'vs/base/common/path';
|
||||
import { dirname, isEqual, basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { IconLabel, IIconLabelValueOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
@@ -323,7 +324,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
}
|
||||
|
||||
notifyUntitledLabelChange(resource: URI): void {
|
||||
if (resources.isEqual(resource, this.label?.resource)) {
|
||||
if (isEqual(resource, this.label?.resource)) {
|
||||
this.render(false);
|
||||
}
|
||||
}
|
||||
@@ -340,19 +341,19 @@ class ResourceLabelWidget extends IconLabel {
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
name = resources.basenameOrAuthority(resource);
|
||||
name = basenameOrAuthority(resource);
|
||||
}
|
||||
}
|
||||
|
||||
let description: string | undefined;
|
||||
if (!options?.hidePath) {
|
||||
description = this.labelService.getUriLabel(resources.dirname(resource), { relative: true });
|
||||
description = this.labelService.getUriLabel(dirname(resource), { relative: true });
|
||||
}
|
||||
|
||||
this.setResource({ resource, name, description }, options);
|
||||
}
|
||||
|
||||
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void {
|
||||
setResource(label: IResourceLabelProps, options: IResourceLabelOptions = Object.create(null)): void {
|
||||
if (label.resource?.scheme === Schemas.untitled) {
|
||||
// Untitled labels are very dynamic because they may change
|
||||
// whenever the content changes (unless a path is associated).
|
||||
@@ -368,17 +369,20 @@ class ResourceLabelWidget extends IconLabel {
|
||||
}
|
||||
|
||||
if (typeof label.description === 'string') {
|
||||
let untitledDescription: string;
|
||||
if (untitledModel.hasAssociatedFilePath) {
|
||||
untitledDescription = this.labelService.getUriLabel(resources.dirname(untitledModel.resource), { relative: true });
|
||||
} else {
|
||||
untitledDescription = untitledModel.resource.path;
|
||||
}
|
||||
|
||||
let untitledDescription = untitledModel.resource.path;
|
||||
if (label.name !== untitledDescription) {
|
||||
label.description = untitledDescription;
|
||||
} else if (label.description === posix.sep) {
|
||||
label.description = undefined; // unset showing just "/" for untitled without associated resource
|
||||
}
|
||||
}
|
||||
|
||||
let untitledTitle = untitledModel.resource.path;
|
||||
if (untitledModel.name !== untitledTitle) {
|
||||
options.title = `${untitledModel.name} • ${untitledTitle}`;
|
||||
} else {
|
||||
options.title = untitledTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,16 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
} else {
|
||||
this.moveComposite(dragData.id, targetCompositeId);
|
||||
}
|
||||
} else {
|
||||
const draggedViews = this.viewDescriptorService.getViewDescriptors(currentContainer).allViewDescriptors;
|
||||
if (draggedViews.length === 1 && draggedViews[0].canMoveView) {
|
||||
dragData.type = 'view';
|
||||
dragData.id = draggedViews[0].id;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (dragData.type === 'view') {
|
||||
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dragData.id);
|
||||
if (viewDescriptor && viewDescriptor.canMoveView) {
|
||||
if (targetCompositeId) {
|
||||
@@ -105,7 +113,21 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
|
||||
// ... across view containers but without a destination composite
|
||||
if (!targetCompositeId) {
|
||||
return false;
|
||||
const draggedViews = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors;
|
||||
if (draggedViews.some(vd => !vd.canMoveView)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (draggedViews.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const defaultLocation = viewContainerRegistry.getViewContainerLocation(this.viewDescriptorService.getDefaultContainer(draggedViews[0].id)!);
|
||||
if (this.targetContainerLocation === ViewContainerLocation.Sidebar && this.targetContainerLocation !== defaultLocation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ... from panel to the sidebar
|
||||
@@ -241,10 +263,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
const draggedCompositeId = data[0].id;
|
||||
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
|
||||
|
||||
const targetItem = this.model.visibleItems[this.model.visibleItems.length - 1];
|
||||
if (targetItem && targetItem.id !== draggedCompositeId) {
|
||||
this.move(draggedCompositeId, targetItem.id);
|
||||
}
|
||||
this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
protected readonly onDidCompositeClose = this._register(new Emitter<IComposite>());
|
||||
|
||||
protected toolBar: ToolBar | undefined;
|
||||
protected titleLabelElement: HTMLElement | undefined;
|
||||
|
||||
private mapCompositeToCompositeContainer = new Map<string, HTMLElement>();
|
||||
private mapActionsBindingToComposite = new Map<string, () => void>();
|
||||
@@ -402,6 +403,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
protected createTitleLabel(parent: HTMLElement): ICompositeTitleLabel {
|
||||
const titleContainer = append(parent, $('.title-label'));
|
||||
const titleLabel = append(titleContainer, $('h2'));
|
||||
this.titleLabelElement = titleLabel;
|
||||
|
||||
const $this = this;
|
||||
return {
|
||||
|
||||
@@ -16,6 +16,9 @@ import { Event } from 'vs/base/common/event';
|
||||
import { isEmptyObject } from 'vs/base/common/types';
|
||||
import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { MementoObject } from 'vs/workbench/common/memento';
|
||||
import { isEqualOrParent, joinPath } from 'vs/base/common/resources';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { indexOfPath } from 'vs/base/common/extpath';
|
||||
|
||||
/**
|
||||
* The base class of editors in the workbench. Editors register themselves for specific editor inputs.
|
||||
@@ -249,6 +252,34 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
}
|
||||
}
|
||||
|
||||
moveEditorState(source: URI, target: URI): void {
|
||||
const cache = this.doLoad();
|
||||
|
||||
const cacheKeys = cache.keys();
|
||||
for (const cacheKey of cacheKeys) {
|
||||
const resource = URI.parse(cacheKey);
|
||||
|
||||
if (!isEqualOrParent(resource, source)) {
|
||||
continue; // not matching our resource
|
||||
}
|
||||
|
||||
// Determine new resulting target resource
|
||||
let targetResource: URI;
|
||||
if (source.toString() === resource.toString()) {
|
||||
targetResource = target; // file got moved
|
||||
} else {
|
||||
const index = indexOfPath(resource.path, source.path, !isLinux);
|
||||
targetResource = joinPath(target, resource.path.substr(index + source.path.length + 1)); // parent folder got moved
|
||||
}
|
||||
|
||||
const value = cache.get(cacheKey);
|
||||
if (value) {
|
||||
cache.delete(cacheKey);
|
||||
cache.set(targetResource.toString(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private doGetResource(resourceOrEditor: URI | EditorInput): URI | undefined {
|
||||
if (resourceOrEditor instanceof EditorInput) {
|
||||
return resourceOrEditor.resource;
|
||||
|
||||
@@ -1227,7 +1227,9 @@ export class ChangeEOLAction extends Action {
|
||||
const activeCodeEditor = getCodeEditor(this.editorService.activeTextEditorWidget);
|
||||
if (activeCodeEditor?.hasModel() && !this.editorService.activeEditor?.isReadonly()) {
|
||||
textModel = activeCodeEditor.getModel();
|
||||
textModel.pushStackElement();
|
||||
textModel.pushEOL(eol.eol);
|
||||
textModel.pushStackElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,9 +204,6 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
|
||||
return this.editorControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the text editor view state for the given resource.
|
||||
*/
|
||||
protected saveTextEditorViewState(resource: URI): void {
|
||||
const editorViewState = this.retrieveTextEditorViewState(resource);
|
||||
if (!editorViewState || !this.group) {
|
||||
@@ -248,22 +245,20 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
|
||||
return control.saveViewState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the text editor view state for the given resources.
|
||||
*/
|
||||
protected loadTextEditorViewState(resource: URI): IEditorViewState | undefined {
|
||||
return this.group ? this.editorMemento.loadEditorState(this.group, resource) : undefined;
|
||||
}
|
||||
|
||||
protected moveTextEditorViewState(source: URI, target: URI): void {
|
||||
return this.editorMemento.moveEditorState(source, target);
|
||||
}
|
||||
|
||||
protected clearTextEditorViewState(resources: URI[], group?: IEditorGroup): void {
|
||||
resources.forEach(resource => {
|
||||
this.editorMemento.clearEditorState(resource, group);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the text editor view state for the given resource and returns it.
|
||||
*/
|
||||
protected loadTextEditorViewState(resource: URI): IEditorViewState | undefined {
|
||||
return this.group ? this.editorMemento.loadEditorState(this.group, resource) : undefined;
|
||||
}
|
||||
|
||||
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {
|
||||
if (!configuration) {
|
||||
const resource = this.getActiveResource();
|
||||
|
||||
@@ -11,7 +11,7 @@ import { INotificationsModel, INotificationChangeEvent, NotificationChangeType }
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { NotificationsCenterVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { NotificationsCenterVisibleContext, INotificationsCenterController } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { addClass, removeClass, isAncestor, Dimension } from 'vs/base/browser/dom';
|
||||
@@ -24,7 +24,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { assertAllDefined, assertIsDefined } from 'vs/base/common/types';
|
||||
|
||||
export class NotificationsCenter extends Themable {
|
||||
export class NotificationsCenter extends Themable implements INotificationsCenterController {
|
||||
|
||||
private static readonly MAX_DIMENSIONS = new Dimension(450, 400);
|
||||
|
||||
@@ -284,8 +284,10 @@ export class NotificationsCenter extends Themable {
|
||||
this.hide();
|
||||
|
||||
// Close all
|
||||
while (this.model.notifications.length) {
|
||||
this.model.notifications[0].close();
|
||||
for (const notification of this.model.notifications) {
|
||||
if (!notification.hasProgress) {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl
|
||||
},
|
||||
handler: (accessor, args?: any) => {
|
||||
const notification = getNotificationFromContext(accessor.get(IListService), args);
|
||||
if (notification) {
|
||||
if (notification && !notification.hasProgress) {
|
||||
notification.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications';
|
||||
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications';
|
||||
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
@@ -12,11 +12,12 @@ import { localize } from 'vs/nls';
|
||||
export class NotificationsStatus extends Disposable {
|
||||
|
||||
private notificationsCenterStatusItem: IStatusbarEntryAccessor | undefined;
|
||||
private currentNotifications = new Set<INotificationViewItem>();
|
||||
private newNotificationsCount = 0;
|
||||
|
||||
private currentStatusMessage: [IStatusMessageViewItem, IDisposable] | undefined;
|
||||
|
||||
private isNotificationsCenterVisible: boolean | undefined;
|
||||
private isNotificationsCenterVisible: boolean = false;
|
||||
private isNotificationsToastsVisible: boolean = false;
|
||||
|
||||
constructor(
|
||||
private model: INotificationsModel,
|
||||
@@ -39,39 +40,56 @@ export class NotificationsStatus extends Disposable {
|
||||
}
|
||||
|
||||
private onDidChangeNotification(e: INotificationChangeEvent): void {
|
||||
if (this.isNotificationsCenterVisible) {
|
||||
return; // no change if notification center is visible
|
||||
}
|
||||
|
||||
// Notification got Added
|
||||
if (e.kind === NotificationChangeType.ADD) {
|
||||
this.currentNotifications.add(e.item);
|
||||
}
|
||||
|
||||
// Notification got Removed
|
||||
else if (e.kind === NotificationChangeType.REMOVE) {
|
||||
this.currentNotifications.delete(e.item);
|
||||
|
||||
// Consider a notification as unread as long as it only
|
||||
// appeared as toast and not in the notification center
|
||||
if (!this.isNotificationsCenterVisible) {
|
||||
if (e.kind === NotificationChangeType.ADD) {
|
||||
this.newNotificationsCount++;
|
||||
} else if (e.kind === NotificationChangeType.REMOVE) {
|
||||
this.newNotificationsCount--;
|
||||
}
|
||||
}
|
||||
|
||||
// Update in status bar
|
||||
this.updateNotificationsCenterStatusItem();
|
||||
}
|
||||
|
||||
private updateNotificationsCenterStatusItem(): void {
|
||||
|
||||
// Figure out how many notifications have progress only if neither
|
||||
// toasts are visible nor center is visible. In that case we still
|
||||
// want to give a hint to the user that something is running.
|
||||
let notificationsInProgress = 0;
|
||||
if (!this.isNotificationsCenterVisible && !this.isNotificationsToastsVisible) {
|
||||
for (const notification of this.model.notifications) {
|
||||
if (notification.hasProgress) {
|
||||
notificationsInProgress++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const statusProperties: IStatusbarEntry = {
|
||||
text: this.currentNotifications.size === 0 ? '$(bell)' : `$(bell) ${this.currentNotifications.size}`,
|
||||
text: `${this.newNotificationsCount === 0 ? '$(bell)' : '$(bell-dot)'}${notificationsInProgress > 0 ? ' $(sync~spin)' : ''}`,
|
||||
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
|
||||
tooltip: this.getTooltip(),
|
||||
tooltip: this.getTooltip(notificationsInProgress),
|
||||
showBeak: this.isNotificationsCenterVisible
|
||||
};
|
||||
|
||||
if (!this.notificationsCenterStatusItem) {
|
||||
this.notificationsCenterStatusItem = this.statusbarService.addEntry(statusProperties, 'status.notifications', localize('status.notifications', "Notifications"), StatusbarAlignment.RIGHT, -Number.MAX_VALUE /* towards the far end of the right hand side */);
|
||||
this.notificationsCenterStatusItem = this.statusbarService.addEntry(
|
||||
statusProperties,
|
||||
'status.notifications',
|
||||
localize('status.notifications', "Notifications"),
|
||||
StatusbarAlignment.RIGHT,
|
||||
-Number.MAX_VALUE /* towards the far end of the right hand side */
|
||||
);
|
||||
} else {
|
||||
this.notificationsCenterStatusItem.update(statusProperties);
|
||||
}
|
||||
}
|
||||
|
||||
private getTooltip(): string {
|
||||
private getTooltip(notificationsInProgress: number): string {
|
||||
if (this.isNotificationsCenterVisible) {
|
||||
return localize('hideNotifications', "Hide Notifications");
|
||||
}
|
||||
@@ -80,23 +98,45 @@ export class NotificationsStatus extends Disposable {
|
||||
return localize('zeroNotifications', "No Notifications");
|
||||
}
|
||||
|
||||
if (this.currentNotifications.size === 0) {
|
||||
return localize('noNotifications', "No New Notifications");
|
||||
if (notificationsInProgress === 0) {
|
||||
if (this.newNotificationsCount === 0) {
|
||||
return localize('noNotifications', "No New Notifications");
|
||||
}
|
||||
|
||||
if (this.newNotificationsCount === 1) {
|
||||
return localize('oneNotification', "1 New Notification");
|
||||
}
|
||||
|
||||
return localize('notifications', "{0} New Notifications", this.newNotificationsCount);
|
||||
}
|
||||
|
||||
if (this.currentNotifications.size === 1) {
|
||||
return localize('oneNotification', "1 New Notification");
|
||||
if (this.newNotificationsCount === 0) {
|
||||
return localize('noNotificationsWithProgress', "No New Notifications ({0} in progress)", notificationsInProgress);
|
||||
}
|
||||
|
||||
return localize('notifications', "{0} New Notifications", this.currentNotifications.size);
|
||||
if (this.newNotificationsCount === 1) {
|
||||
return localize('oneNotificationWithProgress', "1 New Notification ({0} in progress)", notificationsInProgress);
|
||||
}
|
||||
|
||||
return localize('notificationsWithProgress', "{0} New Notifications ({0} in progress)", this.newNotificationsCount, notificationsInProgress);
|
||||
}
|
||||
|
||||
update(isCenterVisible: boolean): void {
|
||||
update(isCenterVisible: boolean, isToastsVisible: boolean): void {
|
||||
let updateNotificationsCenterStatusItem = false;
|
||||
|
||||
if (this.isNotificationsCenterVisible !== isCenterVisible) {
|
||||
this.isNotificationsCenterVisible = isCenterVisible;
|
||||
this.newNotificationsCount = 0; // Showing the notification center resets the unread counter to 0
|
||||
updateNotificationsCenterStatusItem = true;
|
||||
}
|
||||
|
||||
// Showing the notification center resets the counter to 0
|
||||
this.currentNotifications.clear();
|
||||
if (this.isNotificationsToastsVisible !== isToastsVisible) {
|
||||
this.isNotificationsToastsVisible = isToastsVisible;
|
||||
updateNotificationsCenterStatusItem = true;
|
||||
}
|
||||
|
||||
// Update in status bar as needed
|
||||
if (updateNotificationsCenterStatusItem) {
|
||||
this.updateNotificationsCenterStatusItem();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/com
|
||||
import { addClass, removeClass, isAncestor, addDisposableListener, EventType, Dimension } from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { Themable, NOTIFICATIONS_TOAST_BORDER, NOTIFICATIONS_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { widgetShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { NotificationsToastsVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { NotificationsToastsVisibleContext, INotificationsToastController } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Severity, NotificationsFilter } from 'vs/platform/notification/common/notification';
|
||||
@@ -39,7 +39,7 @@ enum ToastVisibility {
|
||||
VISIBLE
|
||||
}
|
||||
|
||||
export class NotificationsToasts extends Themable {
|
||||
export class NotificationsToasts extends Themable implements INotificationsToastController {
|
||||
|
||||
private static readonly MAX_WIDTH = 450;
|
||||
private static readonly MAX_NOTIFICATIONS = 3;
|
||||
@@ -53,6 +53,12 @@ export class NotificationsToasts extends Themable {
|
||||
return intervals;
|
||||
})();
|
||||
|
||||
private readonly _onDidChangeVisibility = this._register(new Emitter<void>());
|
||||
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
|
||||
|
||||
private _isVisible = false;
|
||||
get isVisible(): boolean { return !!this._isVisible; }
|
||||
|
||||
private notificationsToastsContainer: HTMLElement | undefined;
|
||||
private workbenchDimensions: Dimension | undefined;
|
||||
private isNotificationsCenterVisible: boolean | undefined;
|
||||
@@ -125,11 +131,11 @@ export class NotificationsToasts extends Themable {
|
||||
|
||||
private addToast(item: INotificationViewItem): void {
|
||||
if (this.isNotificationsCenterVisible) {
|
||||
return; // do not show toasts while notification center is visibles
|
||||
return; // do not show toasts while notification center is visible
|
||||
}
|
||||
|
||||
if (item.silent) {
|
||||
return; // do not show toats for silenced notifications
|
||||
return; // do not show toasts for silenced notifications
|
||||
}
|
||||
|
||||
// Lazily create toasts containers
|
||||
@@ -174,7 +180,7 @@ export class NotificationsToasts extends Themable {
|
||||
this.mapNotificationToToast.set(item, toast);
|
||||
|
||||
itemDisposables.add(toDisposable(() => {
|
||||
if (this.isVisible(toast) && notificationsToastsContainer) {
|
||||
if (this.isToastVisible(toast) && notificationsToastsContainer) {
|
||||
notificationsToastsContainer.removeChild(toast.container);
|
||||
}
|
||||
}));
|
||||
@@ -229,6 +235,12 @@ export class NotificationsToasts extends Themable {
|
||||
removeClass(notificationToast, 'notification-fade-in');
|
||||
addClass(notificationToast, 'notification-fade-in-done');
|
||||
}));
|
||||
|
||||
// Events
|
||||
if (!this._isVisible) {
|
||||
this._isVisible = true;
|
||||
this._onDidChangeVisibility.fire();
|
||||
}
|
||||
}
|
||||
|
||||
private purgeNotification(item: INotificationViewItem, notificationToastContainer: HTMLElement, notificationList: NotificationsList, disposables: DisposableStore): void {
|
||||
@@ -325,6 +337,12 @@ export class NotificationsToasts extends Themable {
|
||||
|
||||
// Context Key
|
||||
this.notificationsToastsVisibleContextKey.set(false);
|
||||
|
||||
// Events
|
||||
if (this._isVisible) {
|
||||
this._isVisible = false;
|
||||
this._onDidChangeVisibility.fire();
|
||||
}
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
@@ -441,12 +459,12 @@ export class NotificationsToasts extends Themable {
|
||||
notificationToasts.push(toast);
|
||||
break;
|
||||
case ToastVisibility.HIDDEN:
|
||||
if (!this.isVisible(toast)) {
|
||||
if (!this.isToastVisible(toast)) {
|
||||
notificationToasts.push(toast);
|
||||
}
|
||||
break;
|
||||
case ToastVisibility.VISIBLE:
|
||||
if (this.isVisible(toast)) {
|
||||
if (this.isToastVisible(toast)) {
|
||||
notificationToasts.push(toast);
|
||||
}
|
||||
break;
|
||||
@@ -534,7 +552,7 @@ export class NotificationsToasts extends Themable {
|
||||
}
|
||||
|
||||
private setVisibility(toast: INotificationToast, visible: boolean): void {
|
||||
if (this.isVisible(toast) === visible) {
|
||||
if (this.isToastVisible(toast) === visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -546,7 +564,7 @@ export class NotificationsToasts extends Themable {
|
||||
}
|
||||
}
|
||||
|
||||
private isVisible(toast: INotificationToast): boolean {
|
||||
private isToastVisible(toast: INotificationToast): boolean {
|
||||
return !!toast.container.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ export class NotificationTemplateRenderer extends Disposable {
|
||||
// Container
|
||||
toggleClass(this.template.container, 'expanded', notification.expanded);
|
||||
this.inputDisposables.add(addDisposableListener(this.template.container, EventType.MOUSE_UP, e => {
|
||||
if (e.button === 1 /* Middle Button */) {
|
||||
if (!notification.hasProgress && e.button === 1 /* Middle Button */) {
|
||||
EventHelper.stop(e);
|
||||
|
||||
notification.close();
|
||||
@@ -403,8 +403,10 @@ export class NotificationTemplateRenderer extends Disposable {
|
||||
actions.push(notification.expanded ? NotificationTemplateRenderer.collapseNotificationAction : NotificationTemplateRenderer.expandNotificationAction);
|
||||
}
|
||||
|
||||
// Close
|
||||
actions.push(NotificationTemplateRenderer.closeNotificationAction);
|
||||
// Close (unless progress is showing)
|
||||
if (!notification.hasProgress) {
|
||||
actions.push(NotificationTemplateRenderer.closeNotificationAction);
|
||||
}
|
||||
|
||||
this.template.toolbar.clear();
|
||||
this.template.toolbar.context = notification;
|
||||
@@ -453,7 +455,7 @@ export class NotificationTemplateRenderer extends Disposable {
|
||||
private renderProgress(notification: INotificationViewItem): void {
|
||||
|
||||
// Return early if the item has no progress
|
||||
if (!notification.hasProgress()) {
|
||||
if (!notification.hasProgress) {
|
||||
this.template.progress.stop().hide();
|
||||
|
||||
return;
|
||||
|
||||
@@ -33,6 +33,9 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { LayoutPriority } from 'vs/base/browser/ui/grid/grid';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
|
||||
import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
|
||||
export class SidebarPart extends CompositePart<Viewlet> implements IViewletService {
|
||||
|
||||
@@ -163,6 +166,29 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
|
||||
this.onTitleAreaContextMenu(new StandardMouseEvent(e));
|
||||
}));
|
||||
|
||||
this.titleLabelElement!.draggable = true;
|
||||
this._register(addDisposableListener(this.titleLabelElement!, EventType.DRAG_START, e => {
|
||||
const activeViewlet = this.getActiveViewlet();
|
||||
if (activeViewlet) {
|
||||
const visibleViews = activeViewlet.getViewPaneContainer().views.filter(v => v.isVisible());
|
||||
if (visibleViews.length === 1) {
|
||||
LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().setData([new DraggedViewIdentifier(visibleViews[0].id)], DraggedViewIdentifier.prototype);
|
||||
} else {
|
||||
LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().setData([new DraggedCompositeIdentifier(activeViewlet.getId())], DraggedCompositeIdentifier.prototype);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(addDisposableListener(this.titleLabelElement!, EventType.DRAG_END, e => {
|
||||
if (LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().hasData(DraggedViewIdentifier.prototype)) {
|
||||
LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().clearData(DraggedViewIdentifier.prototype);
|
||||
}
|
||||
|
||||
if (LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().hasData(DraggedCompositeIdentifier.prototype)) {
|
||||
LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().clearData(DraggedCompositeIdentifier.prototype);
|
||||
}
|
||||
}));
|
||||
|
||||
return titleArea;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
|
||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
export class CustomTreeViewPane extends ViewPane {
|
||||
|
||||
@@ -59,8 +60,9 @@ export class CustomTreeViewPane extends ViewPane {
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IOpenerService openerService: IOpenerService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
) {
|
||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
|
||||
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
||||
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
|
||||
this.treeView = treeView;
|
||||
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
|
||||
|
||||
@@ -66,6 +66,10 @@ export class DraggedViewIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
type WelcomeActionClassification = {
|
||||
viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
uri: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
|
||||
|
||||
@@ -194,11 +198,12 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
@IKeybindingService protected keybindingService: IKeybindingService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@IConfigurationService protected readonly configurationService: IConfigurationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextKeyService protected contextKeyService: IContextKeyService,
|
||||
@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@IOpenerService protected openerService: IOpenerService,
|
||||
@IThemeService protected themeService: IThemeService,
|
||||
@ITelemetryService protected telemetryService: ITelemetryService,
|
||||
) {
|
||||
super(options);
|
||||
|
||||
@@ -397,7 +402,9 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
addClass(this.bodyContainer, 'welcome');
|
||||
this.viewWelcomeContainer.innerHTML = '';
|
||||
|
||||
for (const { content } of contents) {
|
||||
let buttonIndex = 0;
|
||||
|
||||
for (const { content, preconditions } of contents) {
|
||||
const lines = content.split('\n');
|
||||
|
||||
for (let line of lines) {
|
||||
@@ -416,9 +423,28 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
} else if (linkedText.nodes.length === 1) {
|
||||
const button = new Button(p, { title: node.title });
|
||||
button.label = node.label;
|
||||
button.onDidClick(_ => this.openerService.open(node.href), null, disposables);
|
||||
button.onDidClick(_ => {
|
||||
this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });
|
||||
this.openerService.open(node.href);
|
||||
}, null, disposables);
|
||||
disposables.add(button);
|
||||
disposables.add(attachButtonStyler(button, this.themeService));
|
||||
|
||||
if (preconditions) {
|
||||
const precondition = preconditions[buttonIndex];
|
||||
|
||||
if (precondition) {
|
||||
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
|
||||
updateEnablement();
|
||||
|
||||
const keys = new Set();
|
||||
precondition.keys().forEach(key => keys.add(key));
|
||||
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
|
||||
onDidChangeContext(updateEnablement, null, disposables);
|
||||
}
|
||||
}
|
||||
|
||||
buttonIndex++;
|
||||
} else {
|
||||
const link = this.instantiationService.createInstance(Link, node);
|
||||
append(p, link.el);
|
||||
|
||||
@@ -42,6 +42,19 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
|
||||
key: 'tabDescription'
|
||||
}, "Controls the format of the label for an editor."),
|
||||
},
|
||||
'workbench.editor.untitled.labelFormat': {
|
||||
'type': 'string',
|
||||
'enum': ['content', 'name'],
|
||||
'enumDescriptions': [
|
||||
nls.localize('workbench.editor.untitled.labelFormat.content', "The name of the untitled file is derived from the contents of its first line unless it has an associated file path. It will fallback to the name in case the line is empty or contains no word characters."),
|
||||
nls.localize('workbench.editor.untitled.labelFormat.name', "The name of the untitled file is not derived from the contents of the file."),
|
||||
],
|
||||
'default': 'content',
|
||||
'description': nls.localize({
|
||||
comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'],
|
||||
key: 'untitledLabelFormat'
|
||||
}, "Controls the format of the label for an untitled editor."),
|
||||
},
|
||||
'workbench.editor.tabCloseButton': {
|
||||
'type': 'string',
|
||||
'enum': ['left', 'right', 'off'],
|
||||
|
||||
@@ -386,10 +386,14 @@ export class Workbench extends Layout {
|
||||
|
||||
// Visibility
|
||||
this._register(notificationsCenter.onDidChangeVisibility(() => {
|
||||
notificationsStatus.update(notificationsCenter.isVisible);
|
||||
notificationsStatus.update(notificationsCenter.isVisible, notificationsToasts.isVisible);
|
||||
notificationsToasts.update(notificationsCenter.isVisible);
|
||||
}));
|
||||
|
||||
this._register(notificationsToasts.onDidChangeVisibility(() => {
|
||||
notificationsStatus.update(notificationsCenter.isVisible, notificationsToasts.isVisible);
|
||||
}));
|
||||
|
||||
// Register Commands
|
||||
registerNotificationCommands(notificationsCenter, notificationsToasts);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user