From 141226332c4bff112acaa8f2b67e281227d2f759 Mon Sep 17 00:00:00 2001 From: Chris LaFreniere <40371649+chlafreniere@users.noreply.github.com> Date: Tue, 17 Sep 2019 14:16:35 -0700 Subject: [PATCH] Add notebook grid actions (#7181) * Add notebook grid actions * pr comments --- .../browser/cellViews/media/output.css | 6 +++ .../browser/outputs/gridOutput.component.ts | 30 ++++++++++++-- .../parts/query/browser/gridPanel.ts | 40 ++++++++++++++----- .../parts/query/browser/media/gridPanel.css | 15 +++++++ 4 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 src/sql/workbench/parts/query/browser/media/gridPanel.css diff --git a/src/sql/workbench/parts/notebook/browser/cellViews/media/output.css b/src/sql/workbench/parts/notebook/browser/cellViews/media/output.css index b90be6ab6e..3508e34cec 100644 --- a/src/sql/workbench/parts/notebook/browser/cellViews/media/output.css +++ b/src/sql/workbench/parts/notebook/browser/cellViews/media/output.css @@ -468,3 +468,9 @@ plotly-output .plotly-wrapper { display: block; overflow-y: hidden; } + +output-component .grid-panel .action-label.icon { + min-width: 16px; + margin-right: 6px; + margin-bottom: 6px; +} diff --git a/src/sql/workbench/parts/notebook/browser/outputs/gridOutput.component.ts b/src/sql/workbench/parts/notebook/browser/outputs/gridOutput.component.ts index d0ce271d75..e8618fddad 100644 --- a/src/sql/workbench/parts/notebook/browser/outputs/gridOutput.component.ts +++ b/src/sql/workbench/parts/notebook/browser/outputs/gridOutput.component.ts @@ -32,10 +32,11 @@ import { getErrorMessage } from 'vs/base/common/errors'; import { ISerializationService, SerializeDataParams } from 'sql/platform/serialization/common/serializationService'; import { SaveResultAction } from 'sql/workbench/parts/query/browser/actions'; import { ResultSerializer, SaveResultsResponse } from 'sql/workbench/parts/query/common/resultSerializer'; +import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; @Component({ selector: GridOutputComponent.SELECTOR, - template: `
` + template: `
` }) export class GridOutputComponent extends AngularDisposable implements IMimeComponent, OnInit { public static readonly SELECTOR: string = 'grid-output'; @@ -46,6 +47,7 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo private _cellModel: ICellModel; private _bundleOptions: MimeModel.IOptions; private _table: DataResourceTable; + private _hover: boolean; constructor( @Inject(IInstantiationService) private instantiationService: IInstantiationService, @Inject(IThemeService) private readonly themeService: IThemeService @@ -73,6 +75,14 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo } } + @Input() set hover(value: boolean) { + // only reaction on hover changes + if (this._hover !== value) { + this.toggleActionbar(value); + this._hover = value; + } + } + ngOnInit() { this.renderGrid(); } @@ -89,6 +99,8 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo outputElement.appendChild(this._table.element); this._register(attachTableStyler(this._table, this.themeService)); this.layout(); + // By default, do not show the actions + this.toggleActionbar(false); this._table.onAdd(); this._initialized = true; } @@ -97,7 +109,19 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo layout(): void { if (this._table) { let maxSize = Math.min(this._table.maximumSize, 500); - this._table.layout(maxSize); + this._table.layout(maxSize, undefined, ActionsOrientation.HORIZONTAL); + } + } + + private toggleActionbar(visible: boolean) { + let outputElement = this.output.nativeElement; + let actionsContainers: HTMLElement[] = Array.prototype.slice.call(outputElement.getElementsByClassName('actions-container')); + if (actionsContainers && actionsContainers.length) { + if (visible) { + actionsContainers.forEach(container => container.style.visibility = 'visible'); + } else { + actionsContainers.forEach(container => container.style.visibility = 'hidden'); + } } } } @@ -125,7 +149,7 @@ class DataResourceTable extends GridTableBase { } protected getCurrentActions(): IAction[] { - return []; + return this.getContextActions(); } protected getContextActions(): IAction[] { diff --git a/src/sql/workbench/parts/query/browser/gridPanel.ts b/src/sql/workbench/parts/query/browser/gridPanel.ts index 4de22b2052..2674b791b7 100644 --- a/src/sql/workbench/parts/query/browser/gridPanel.ts +++ b/src/sql/workbench/parts/query/browser/gridPanel.ts @@ -3,6 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import 'vs/css!./media/gridPanel'; + import { attachTableStyler } from 'sql/platform/theme/common/styler'; import QueryRunner, { QueryGridDataProvider } from 'sql/platform/query/common/queryRunner'; import { VirtualizedCollection, AsyncDataProvider } from 'sql/base/browser/ui/table/asyncDataView'; @@ -416,7 +418,22 @@ export abstract class GridTableBase extends Disposable implements IView { this.scrolled = false; } - private build(): void { + // actionsOrientation controls the orientation (horizontal or vertical) of the actionBar + private build(actionsOrientation?: ActionsOrientation): void { + + // Default is VERTICAL + if (isUndefinedOrNull(actionsOrientation)) { + actionsOrientation = ActionsOrientation.VERTICAL; + } + + let actionBarContainer = document.createElement('div'); + + // Create a horizontal actionbar if orientation passed in is HORIZONTAL + if (actionsOrientation === ActionsOrientation.HORIZONTAL) { + actionBarContainer.className = 'grid-panel action-bar horizontal'; + this.container.appendChild(actionBarContainer); + } + let tableContainer = document.createElement('div'); tableContainer.style.display = 'inline-block'; tableContainer.style.width = `calc(100% - ${ACTIONBAR_WIDTH}px)`; @@ -459,13 +476,12 @@ export abstract class GridTableBase extends Disposable implements IView { if (this.styles) { this.table.style(this.styles); } - - let actionBarContainer = document.createElement('div'); - actionBarContainer.style.width = ACTIONBAR_WIDTH + 'px'; - actionBarContainer.style.display = 'inline-block'; - actionBarContainer.style.height = '100%'; - actionBarContainer.style.verticalAlign = 'top'; - this.container.appendChild(actionBarContainer); + // If the actionsOrientation passed in is "VERTICAL" (or no actionsOrientation is passed in at all), create a vertical actionBar + if (actionsOrientation === ActionsOrientation.VERTICAL) { + actionBarContainer.className = 'grid-panel action-bar vertical'; + actionBarContainer.style.width = ACTIONBAR_WIDTH + 'px'; + this.container.appendChild(actionBarContainer); + } let context: IGridActionContext = { gridDataProvider: this.gridDataProvider, table: this.table, @@ -474,7 +490,7 @@ export abstract class GridTableBase extends Disposable implements IView { resultId: this.resultSet.id }; this.actionBar = new ActionBar(actionBarContainer, { - orientation: ActionsOrientation.VERTICAL, context: context + orientation: actionsOrientation, context: context }); // update context before we run an action this.selectionModel.onSelectedRangesChanged.subscribe(e => { @@ -602,15 +618,17 @@ export abstract class GridTableBase extends Disposable implements IView { protected abstract getContextActions(): IAction[]; - public layout(size?: number): void { + // The actionsOrientation passed in controls the actionBar orientation + public layout(size?: number, orientation?: Orientation, actionsOrientation?: ActionsOrientation): void { if (!this.table) { - this.build(); + this.build(actionsOrientation); } if (!size) { size = this.currentHeight; } else { this.currentHeight = size; } + // Table is always called with Orientation as VERTICAL this.table.layout(size, Orientation.VERTICAL); } diff --git a/src/sql/workbench/parts/query/browser/media/gridPanel.css b/src/sql/workbench/parts/query/browser/media/gridPanel.css new file mode 100644 index 0000000000..b35e0900cf --- /dev/null +++ b/src/sql/workbench/parts/query/browser/media/gridPanel.css @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.grid-panel.action-bar.vertical { + display : inline-block; + height : 100%; + vertical-align : top; +} + +.grid-panel.action-bar.horizontal { + width : 100%; + display: flex; +}