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;
+}