mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Notebook toolbar extensibility (#3362)
* Notebook Toolbar Contribution * Address CR comments, ensure CSS can be passed in for contributed items
This commit is contained in:
@@ -32,6 +32,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, SaveNotebookAction } from 'sql/parts/notebook/notebookActions';
|
||||||
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { MenuId, IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||||
|
import { IAction, Action, IActionItem } from 'vs/base/common/actions';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
|
import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
@@ -72,7 +77,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
||||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||||
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService
|
@Inject(IConnectionDialogService) private connectionDialogService: IConnectionDialogService,
|
||||||
|
@Inject(IContextKeyService) private contextKeyService: IContextKeyService,
|
||||||
|
@Inject(IMenuService) private menuService: IMenuService,
|
||||||
|
@Inject(IKeybindingService) private keybindingService: IKeybindingService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.updateProfile();
|
this.updateProfile();
|
||||||
@@ -273,8 +281,19 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
|
|
||||||
let saveNotebookButton = this.instantiationService.createInstance(SaveNotebookAction, 'notebook.SaveNotebook', localize('save', 'Save'), 'notebook-button icon-save');
|
let saveNotebookButton = this.instantiationService.createInstance(SaveNotebookAction, 'notebook.SaveNotebook', localize('save', 'Save'), 'notebook-button icon-save');
|
||||||
|
|
||||||
|
// Get all of the menu contributions that use the ID 'notebook/toolbar'.
|
||||||
|
// Then, find all groups (currently we don't leverage the contributed
|
||||||
|
// groups functionality for the notebook toolbar), and fill in the 'primary'
|
||||||
|
// array with items that don't list a group. Finally, add any actions from
|
||||||
|
// the primary array to the end of the toolbar.
|
||||||
|
const notebookBarMenu = this.menuService.createMenu(MenuId.NotebookToolbar, this.contextKeyService);
|
||||||
|
let groups = notebookBarMenu.getActions({ arg: null, shouldForwardArgs: true });
|
||||||
|
let primary: IAction[] = [];
|
||||||
|
let secondary: IAction[] = [];
|
||||||
|
fillInActions(groups, {primary, secondary}, false, (group: string) => group === undefined);
|
||||||
|
|
||||||
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
let taskbar = <HTMLElement>this.toolbar.nativeElement;
|
||||||
this._actionBar = new Taskbar(taskbar, this.contextMenuService);
|
this._actionBar = new Taskbar(taskbar, this.contextMenuService, { actionItemProvider: action => this.actionItemProvider(action as Action)});
|
||||||
this._actionBar.context = this;
|
this._actionBar.context = this;
|
||||||
this._actionBar.setContent([
|
this._actionBar.setContent([
|
||||||
{ element: kernelContainer },
|
{ element: kernelContainer },
|
||||||
@@ -284,6 +303,12 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
{ action: saveNotebookButton },
|
{ action: saveNotebookButton },
|
||||||
{ action: this._trustedAction }
|
{ action: this._trustedAction }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Primary actions are categorized as those that are added to the 'horizontal' group.
|
||||||
|
// For the vertical toolbar, we can do the same thing and instead use the 'vertical' group.
|
||||||
|
for (let action of primary) {
|
||||||
|
this._actionBar.addAction(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async save(): Promise<boolean> {
|
public async save(): Promise<boolean> {
|
||||||
@@ -303,5 +328,13 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private actionItemProvider(action: Action): IActionItem {
|
||||||
|
// Check extensions to create ActionItem; otherwise, return undefined
|
||||||
|
// This is similar behavior that exists in MenuItemActionItem
|
||||||
|
if (action instanceof MenuItemAction) {
|
||||||
|
return new LabeledMenuItemActionItem(action, this.keybindingService, this.notificationService, this.contextMenuService, 'notebook-button');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,3 +288,63 @@ export class ContextAwareMenuItemActionItem extends MenuItemActionItem {
|
|||||||
.done(undefined, err => this._notificationService.error(err));
|
.done(undefined, err => this._notificationService.error(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always show label for action items, instead of whether they don't have
|
||||||
|
// an icon/CSS class. Useful for some toolbar scenarios in particular with
|
||||||
|
// contributed actions from other extensions
|
||||||
|
export class LabeledMenuItemActionItem extends MenuItemActionItem {
|
||||||
|
private _labeledItemClassDispose: IDisposable;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public _action: MenuItemAction,
|
||||||
|
@IKeybindingService private readonly _labeledkeybindingService: IKeybindingService,
|
||||||
|
@INotificationService protected _notificationService: INotificationService,
|
||||||
|
@IContextMenuService private readonly _labeledcontextMenuService: IContextMenuService,
|
||||||
|
private readonly _defaultCSSClassToAdd: string = ''
|
||||||
|
) {
|
||||||
|
super(_action, _labeledkeybindingService, _notificationService, _labeledcontextMenuService);
|
||||||
|
}
|
||||||
|
_updateLabel(): void {
|
||||||
|
this.$e.text(this._commandAction.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite item class to ensure that we can pass in a CSS class that other items use
|
||||||
|
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
|
||||||
|
_updateItemClass(item: ICommandAction): void {
|
||||||
|
dispose(this._labeledItemClassDispose);
|
||||||
|
this._labeledItemClassDispose = undefined;
|
||||||
|
|
||||||
|
if (item.iconLocation) {
|
||||||
|
let iconClass: string;
|
||||||
|
|
||||||
|
const iconPathMapKey = item.iconLocation.dark.toString();
|
||||||
|
|
||||||
|
if (MenuItemActionItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
|
||||||
|
iconClass = MenuItemActionItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey);
|
||||||
|
} else {
|
||||||
|
iconClass = ids.nextId();
|
||||||
|
createCSSRule(`.icon.${iconClass}`, `background-image: url("${(item.iconLocation.light || item.iconLocation.dark).toString()}")`);
|
||||||
|
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: url("${item.iconLocation.dark.toString()}")`);
|
||||||
|
MenuItemActionItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$e.getHTMLElement().classList.add('icon', iconClass);
|
||||||
|
this.$e.getHTMLElement().classList.add(this._defaultCSSClassToAdd);
|
||||||
|
this._labeledItemClassDispose = {
|
||||||
|
dispose: () => {
|
||||||
|
this.$e.getHTMLElement().classList.remove('icon', iconClass);
|
||||||
|
this.$e.getHTMLElement().classList.remove(this._defaultCSSClassToAdd);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): void {
|
||||||
|
if (this._labeledItemClassDispose) {
|
||||||
|
dispose(this._labeledItemClassDispose);
|
||||||
|
this._labeledItemClassDispose = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ export class MenuId {
|
|||||||
static readonly MenubarHelpMenu = new MenuId();
|
static readonly MenubarHelpMenu = new MenuId();
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
static readonly ObjectExplorerItemContext = new MenuId();
|
static readonly ObjectExplorerItemContext = new MenuId();
|
||||||
|
static readonly NotebookToolbar = new MenuId();
|
||||||
|
|
||||||
|
|
||||||
readonly id: string = String(MenuId.ID++);
|
readonly id: string = String(MenuId.ID++);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ namespace schema {
|
|||||||
case 'view/item/context': return MenuId.ViewItemContext;
|
case 'view/item/context': return MenuId.ViewItemContext;
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
case 'objectExplorer/item/context': return MenuId.ObjectExplorerItemContext;
|
case 'objectExplorer/item/context': return MenuId.ObjectExplorerItemContext;
|
||||||
|
case 'notebook/toolbar': return MenuId.NotebookToolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
return void 0;
|
return void 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user