diff --git a/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts b/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts new file mode 100644 index 0000000000..be41c5fd90 --- /dev/null +++ b/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { EditorInput } from 'vs/workbench/common/editor'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { ResourceViewerState } from 'sql/workbench/common/editor/resourceViewer/resourceViewerState'; +import { TableDataView } from 'sql/base/browser/ui/table/tableDataView'; + +export interface ColumnDefinition extends Slick.Column { + name: string; +} + +export class ResourceViewerInput extends EditorInput { + + public static ID: string = 'workbench.editorInput.resourceViewerInput'; + private _data: TableDataView; + private _columns: string[] = []; + private _state: ResourceViewerState; + + private _onColumnsChanged = new Emitter[]>(); + public onColumnsChanged: Event[]> = this._onColumnsChanged.event; + + constructor() { + super(); + this._state = new ResourceViewerState(); + let searchFn = (val: { [x: string]: string }, exp: string): Array => { + let ret = new Array(); + for (let i = 0; i < this._columns.length; i++) { + let colVal = val[this._columns[i]]; + if (colVal && colVal.toLocaleLowerCase().indexOf(exp.toLocaleLowerCase()) > -1) { + ret.push(i); + } + } + return ret; + }; + + this._data = new TableDataView(undefined, searchFn, undefined, undefined); + } + + public getTypeId(): string { + return ResourceViewerInput.ID; + } + + public getName(): string { + return nls.localize('resourceViewerInput.resourceViewer', "Resource Viewer"); + } + + public get data(): TableDataView { + return this._data; + } + + public get columnDefinitions(): ColumnDefinition[] { + if (this._columns) { + return this._columns.map(i => { + return { + id: i, + field: i, + name: i, + sortable: true + }; + }); + } else { + return []; + } + } + + public set columns(columns: Array) { + this._columns = columns; + this._onColumnsChanged.fire(this.columnDefinitions); + } + + public get state(): ResourceViewerState { + return this._state; + } + + isDirty(): boolean { + return false; // TODO chgagnon implement + } + + public get resource(): URI | undefined { + return undefined; + } +} diff --git a/src/sql/workbench/common/editor/resourceViewer/resourceViewerState.ts b/src/sql/workbench/common/editor/resourceViewer/resourceViewerState.ts new file mode 100644 index 0000000000..8f2dba9e37 --- /dev/null +++ b/src/sql/workbench/common/editor/resourceViewer/resourceViewerState.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IDisposable } from 'vs/base/common/lifecycle'; +import { Emitter } from 'vs/base/common/event'; + +export interface IResourceViewerStateChangedEvent { + +} + +export interface INewResourceViewerState { + // TODO - chgagnon implement state +} + +export class ResourceViewerState implements IDisposable { + + private readonly _onResourceViewerStateChange = new Emitter(); + public readonly onResourceViewerStateChange = this._onResourceViewerStateChange.event; + + public dispose(): void { + } + + public change(newState: INewResourceViewerState): void { + let changeEvent: IResourceViewerStateChangedEvent = { + }; + let somethingChanged = false; + + if (somethingChanged) { + this._onResourceViewerStateChange.fire(changeEvent); + } + } +} diff --git a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewer.contribution.ts b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewer.contribution.ts new file mode 100644 index 0000000000..f8ef9a858a --- /dev/null +++ b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewer.contribution.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } from 'vs/workbench/browser/editor'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { ResourceViewerEditor } from 'sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor'; +import { ResourceViewerInput } from 'sql/workbench/browser/editor/resourceViewer/resourceViewerInput'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; + +CommandsRegistry.registerCommand({ + id: 'resourceViewer.newResourceViewer', + handler: (accessor: ServicesAccessor, ...args: any[]): void => { + const instantiationService: IInstantiationService = accessor.get(IInstantiationService); + const editorService: IEditorService = accessor.get(IEditorService); + + const resourceViewerInput = instantiationService.createInstance(ResourceViewerInput); + editorService.openEditor(resourceViewerInput, { pinned: true }, ACTIVE_GROUP); + } +}); + +const resourceViewerDescriptor = EditorDescriptor.create( + ResourceViewerEditor, + ResourceViewerEditor.ID, + 'ResourceViewerEditor' +); + +Registry.as(EditorExtensions.Editors) + .registerEditor(resourceViewerDescriptor, [new SyncDescriptor(ResourceViewerInput)]); + diff --git a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts new file mode 100644 index 0000000000..49b0c27704 --- /dev/null +++ b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import * as DOM from 'vs/base/browser/dom'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { EditorOptions } from 'vs/workbench/common/editor'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IResourceViewerStateChangedEvent } from 'sql/workbench/common/editor/resourceViewer/resourceViewerState'; +import { ResourceViewerInput } from 'sql/workbench/browser/editor/resourceViewer/resourceViewerInput'; +import { ResourceViewerTable } from 'sql/workbench/contrib/resourceViewer/browser/resourceViewerTable'; + +export class ResourceViewerEditor extends BaseEditor { + public static readonly ID: string = 'workbench.editor.resource-viewer'; + + private _container!: HTMLElement; + private _actionBar!: Taskbar; + private _resourceViewerTable!: ResourceViewerTable; + private _inputDisposables = this._register(new DisposableStore()); + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IWorkbenchThemeService themeService: IWorkbenchThemeService, + @IInstantiationService private _instantiationService: IInstantiationService, + @IStorageService storageService: IStorageService + ) { + super(ResourceViewerEditor.ID, telemetryService, themeService, storageService); + } + + protected createEditor(parent: HTMLElement): void { + this._container = document.createElement('div'); + this._container.className = 'resource-viewer'; + parent.appendChild(this._container); + + this._createHeader(); + + let tableContainer = this.createResourceViewerTable(); + + this._container.appendChild(tableContainer); + } + + private _createHeader(): void { + const header = document.createElement('div'); + header.className = 'resource-viewer-header'; + this._container.appendChild(header); + this._actionBar = this._register(new Taskbar(header)); + + this._actionBar.setContent([ + // TODO - chgagnon add actions + ]); + } + + private createResourceViewerTable(): HTMLElement { + let resourceViewerTableContainer = document.createElement('div'); + resourceViewerTableContainer.className = 'resource-viewer-table monaco-editor'; + resourceViewerTableContainer.style.width = '100%'; + resourceViewerTableContainer.style.height = '100%'; + resourceViewerTableContainer.style.overflow = 'hidden'; + resourceViewerTableContainer.style.position = 'relative'; + this._resourceViewerTable = this._register(this._instantiationService.createInstance(ResourceViewerTable, resourceViewerTableContainer)); + return resourceViewerTableContainer; + } + + public get input(): ResourceViewerInput { + return this._input as ResourceViewerInput; + } + + public async setInput(input: ResourceViewerInput, options?: EditorOptions): Promise { + await super.setInput(input, options, CancellationToken.None); + + this._inputDisposables.clear(); + + this._resourceViewerTable.data = input.data; + this._inputDisposables.add(input.onColumnsChanged(columns => { + this._resourceViewerTable.columns = columns; + })); + + this._inputDisposables.add(input.data.onRowCountChange(() => { + this._resourceViewerTable.updateRowCount(); + })); + + this._inputDisposables.add(input.data.onFilterStateChange(() => { + this._resourceViewerTable.invalidateAllRows(); + this._resourceViewerTable.updateRowCount(); + })); + + this._actionBar.context = input; + + this._inputDisposables.add(input.state.onResourceViewerStateChange(e => this.onStateChange(e))); + this.onStateChange({ + }); + + this._resourceViewerTable.focus(); + } + + + private onStateChange(e: IResourceViewerStateChangedEvent): void { + + } + + public layout(dimension: DOM.Dimension): void { + this._container.style.width = dimension.width + 'px'; + this._container.style.height = dimension.height + 'px'; + } +} diff --git a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts new file mode 100644 index 0000000000..d0e76e3f9a --- /dev/null +++ b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts @@ -0,0 +1,67 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Table } from 'sql/base/browser/ui/table/table'; +import { attachTableStyler } from 'sql/platform/theme/common/styler'; +import { RowSelectionModel } from 'sql/base/browser/ui/table/plugins/rowSelectionModel.plugin'; + +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { Dimension } from 'vs/base/browser/dom'; +import { textFormatter, slickGridDataItemColumnValueExtractor } from 'sql/base/browser/ui/table/formatters'; +import { TableDataView } from 'sql/base/browser/ui/table/tableDataView'; +import { Disposable } from 'vs/base/common/lifecycle'; + +export class ResourceViewerTable extends Disposable { + + private _resourceViewerTable!: Table; + private _data: TableDataView | undefined; + + constructor(parent: HTMLElement, @IWorkbenchThemeService private _themeService: IWorkbenchThemeService) { + super(); + this._resourceViewerTable = this._register(new Table(parent, { + sorter: (args) => { + this._data?.sort(args); + } + }, { + dataItemColumnValueExtractor: slickGridDataItemColumnValueExtractor + })); + this._resourceViewerTable.setSelectionModel(new RowSelectionModel()); + attachTableStyler(this._resourceViewerTable, this._themeService); + } + + public set data(data: TableDataView) { + this._data = data; + this._resourceViewerTable.setData(data); + } + + public set columns(columns: Slick.Column[]) { + this._resourceViewerTable.columns = columns.map(column => { + column.formatter = textFormatter; + return column; + }); + this._resourceViewerTable.autosizeColumns(); + } + + public updateRowCount(): void { + this._resourceViewerTable.updateRowCount(); + } + + public invalidateAllRows(): void { + this._resourceViewerTable.grid.invalidateAllRows(); + } + + public autosizeColumns(): void { + this._resourceViewerTable.autosizeColumns(); + } + + public focus(): void { + this._resourceViewerTable.focus(); + } + + public layout(dimension: Dimension): void { + this._resourceViewerTable.layout(dimension); + this._resourceViewerTable.autosizeColumns(); + } +} diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 6384b68a5a..cf65b3bd69 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -438,6 +438,9 @@ import 'sql/workbench/contrib/accounts/browser/accountManagement.contribution'; import 'sql/workbench/contrib/profiler/browser/profiler.contribution'; import 'sql/workbench/contrib/profiler/browser/profilerActions.contribution'; +// resource viewer +import 'sql/workbench/contrib/resourceViewer/browser/resourceViewer.contribution'; + // dashboard import 'sql/workbench/contrib/dashboard/browser/widgets/insights/views/charts/types/barChart.contribution'; import 'sql/workbench/contrib/dashboard/browser/widgets/insights/views/charts/types/doughnutChart.contribution';