mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 09:35:39 -05:00
create new notebook editor and add the place holder for toolbar and cell list (#2817)
* create new notebook editor and add the place holder for toolbar and cell list * address comments
This commit is contained in:
16
src/sql/parts/notebook/notebook.component.html
Normal file
16
src/sql/parts/notebook/notebook.component.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||
<div #header class="header" style="flex: 0 0 auto; display: flex; flex-flow: row; width: 100%; align-items: center">
|
||||
<div style="flex: 1 1 auto">
|
||||
PlaceHolder for Toolbar
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex: 1 1 auto; position: relative">
|
||||
Place Holder for cell list
|
||||
</div>
|
||||
</div>
|
||||
43
src/sql/parts/notebook/notebook.component.ts
Normal file
43
src/sql/parts/notebook/notebook.component.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./notebook';
|
||||
|
||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild } from '@angular/core';
|
||||
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
|
||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import * as themeColors from 'vs/workbench/common/theme';
|
||||
|
||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||
|
||||
@Component({
|
||||
selector: NOTEBOOK_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./notebook.component.html'))
|
||||
})
|
||||
export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
@ViewChild('header', { read: ElementRef }) private header: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||
this.updateTheme(this.themeService.getColorTheme());
|
||||
}
|
||||
|
||||
private updateTheme(theme: IColorTheme): void {
|
||||
let headerEl = <HTMLElement>this.header.nativeElement;
|
||||
headerEl.style.borderBottomColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||
headerEl.style.borderBottomWidth = '1px';
|
||||
headerEl.style.borderBottomStyle = 'solid';
|
||||
}
|
||||
}
|
||||
64
src/sql/parts/notebook/notebook.contribution.ts
Normal file
64
src/sql/parts/notebook/notebook.contribution.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
import { NotebookInput, NotebookInputModel } from 'sql/parts/notebook/notebookInput';
|
||||
import { NotebookEditor } from 'sql/parts/notebook/notebookEditor';
|
||||
|
||||
/**
|
||||
* todo: Will remove this code.
|
||||
* This is the entry point to open the new Notebook
|
||||
*/
|
||||
export class OpenNotebookAction extends Action {
|
||||
|
||||
public static ID = 'OpenNotebookAction';
|
||||
public static LABEL = nls.localize('OpenNotebookAction', 'Open Notebook editor');
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IEditorService private _editorService: IEditorService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): TPromise<void> {
|
||||
return new TPromise<void>((resolve, reject) => {
|
||||
let model = new NotebookInputModel('modelViewId', undefined, undefined);
|
||||
let input = new NotebookInput('modelViewId', model);
|
||||
this._editorService.openEditor(input, { pinned: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Model View editor registration
|
||||
const viewModelEditorDescriptor = new EditorDescriptor(
|
||||
NotebookEditor,
|
||||
NotebookEditor.ID,
|
||||
'Notebook'
|
||||
);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(NotebookInput)]);
|
||||
|
||||
// todo: Will remove this code.
|
||||
// this is the entry point to open the new Notebook
|
||||
let actionRegistry = <IWorkbenchActionRegistry>Registry.as(Extensions.WorkbenchActions);
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(
|
||||
OpenNotebookAction,
|
||||
OpenNotebookAction.ID,
|
||||
OpenNotebookAction.LABEL
|
||||
),
|
||||
OpenNotebookAction.LABEL
|
||||
);
|
||||
17
src/sql/parts/notebook/notebook.css
Normal file
17
src/sql/parts/notebook/notebook.css
Normal file
@@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/*
|
||||
.notebookEditor .header .monaco-action-bar .action-label {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.notebookEditor .header .monaco-action-bar .action-item {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.notebookEditor .monaco-action-bar {
|
||||
overflow: visible;
|
||||
}
|
||||
*/
|
||||
67
src/sql/parts/notebook/notebook.module.ts
Normal file
67
src/sql/parts/notebook/notebook.module.ts
Normal file
@@ -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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { forwardRef, NgModule, ComponentFactoryResolver, Inject, ApplicationRef } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
|
||||
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||
import { IBootstrapParams, ISelector, providerIterator } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox.component';
|
||||
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||
import { EditableDropDown } from 'sql/base/browser/ui/editableDropdown/editableDropdown.component';
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox.component';
|
||||
import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
||||
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
export const NotebookModule = (params, selector: string, instantiationService: IInstantiationService): any => {
|
||||
@NgModule({
|
||||
declarations: [
|
||||
Checkbox,
|
||||
SelectBox,
|
||||
EditableDropDown,
|
||||
InputBox,
|
||||
NotebookComponent,
|
||||
ComponentHostDirective
|
||||
],
|
||||
entryComponents: [NotebookComponent],
|
||||
imports: [
|
||||
FormsModule,
|
||||
CommonModule,
|
||||
BrowserModule
|
||||
],
|
||||
providers: [
|
||||
{ provide: APP_BASE_HREF, useValue: '/' },
|
||||
CommonServiceInterface,
|
||||
{ provide: IBootstrapParams, useValue: params },
|
||||
{ provide: ISelector, useValue: selector },
|
||||
...providerIterator(instantiationService)
|
||||
]
|
||||
})
|
||||
class ModuleClass {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
|
||||
@Inject(ISelector) private selector: string
|
||||
) {
|
||||
}
|
||||
|
||||
ngDoBootstrap(appRef: ApplicationRef) {
|
||||
const factoryWrapper: any = this._resolver.resolveComponentFactory(NotebookComponent);
|
||||
factoryWrapper.factory.selector = this.selector;
|
||||
appRef.bootstrap(factoryWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
return ModuleClass;
|
||||
};
|
||||
95
src/sql/parts/notebook/notebookEditor.ts
Normal file
95
src/sql/parts/notebook/notebookEditor.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { $ } from 'vs/base/browser/builder';
|
||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { NotebookInput } from 'sql/parts/notebook/notebookInput';
|
||||
import { NotebookModule } from 'sql/parts/notebook/notebook.module';
|
||||
import { NOTEBOOK_SELECTOR } from 'sql/parts/notebook/notebook.component';
|
||||
|
||||
export class NotebookEditor extends BaseEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.notebookEditor';
|
||||
private _notebookContainer: HTMLElement;
|
||||
protected _input: NotebookInput;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
) {
|
||||
super(NotebookEditor.ID, telemetryService, themeService);
|
||||
}
|
||||
|
||||
public get input(): NotebookInput {
|
||||
return this._input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to create the editor in the parent element.
|
||||
*/
|
||||
public createEditor(parent: HTMLElement): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets focus on this editor. Specifically, it sets the focus on the hosted text editor.
|
||||
*/
|
||||
public focus(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the internal variable keeping track of the editor's size, and re-calculates the sash position.
|
||||
* To be called when the container of this editor changes size.
|
||||
*/
|
||||
public layout(dimension: DOM.Dimension): void {
|
||||
}
|
||||
|
||||
public setInput(input: NotebookInput, options: EditorOptions): TPromise<void> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
|
||||
const parentElement = this.getContainer();
|
||||
|
||||
super.setInput(input, options, CancellationToken.None);
|
||||
|
||||
$(parentElement).clearChildren();
|
||||
|
||||
if (!input.hasBootstrapped) {
|
||||
let container = DOM.$<HTMLElement>('.notebookEditor');
|
||||
container.style.height = '100%';
|
||||
this._notebookContainer = DOM.append(parentElement, container);
|
||||
this.input.container = this._notebookContainer;
|
||||
return TPromise.wrap<void>(this.bootstrapAngular(input));
|
||||
} else {
|
||||
this._notebookContainer = DOM.append(parentElement, this.input.container);
|
||||
return TPromise.wrap<void>(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the angular components and record for this input that we have done so
|
||||
*/
|
||||
private bootstrapAngular(input: NotebookInput): void {
|
||||
// Get the bootstrap params and perform the bootstrap
|
||||
input.hasBootstrapped = true;
|
||||
bootstrapAngular(this.instantiationService,
|
||||
NotebookModule,
|
||||
this._notebookContainer,
|
||||
NOTEBOOK_SELECTOR,
|
||||
undefined,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
124
src/sql/parts/notebook/notebookInput.ts
Normal file
124
src/sql/parts/notebook/notebookInput.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { EditorInput, EditorModel, ConfirmResult } from 'vs/workbench/common/editor';
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
||||
|
||||
export class NotebookInputModel extends EditorModel {
|
||||
private dirty: boolean;
|
||||
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||
get onDidChangeDirty(): Event<void> { return this._onDidChangeDirty.event; }
|
||||
|
||||
constructor(public readonly modelViewId, private readonly handle: number, private saveHandler?: ModeViewSaveHandler) {
|
||||
super();
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
get isDirty(): boolean {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
public setDirty(dirty: boolean): void {
|
||||
if (this.dirty === dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirty = dirty;
|
||||
this._onDidChangeDirty.fire();
|
||||
}
|
||||
|
||||
save(): TPromise<boolean> {
|
||||
if (this.saveHandler) {
|
||||
return TPromise.wrap(this.saveHandler(this.handle));
|
||||
}
|
||||
return TPromise.wrap(true);
|
||||
}
|
||||
}
|
||||
export class NotebookInput extends EditorInput {
|
||||
|
||||
public static ID: string = 'workbench.editorinputs.notebookInput';
|
||||
|
||||
public hasBootstrapped = false;
|
||||
// Holds the HTML content for the editor when the editor discards this input and loads another
|
||||
private _parentContainer: HTMLElement;
|
||||
|
||||
constructor(private _title: string, private _model: NotebookInputModel,
|
||||
) {
|
||||
super();
|
||||
this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire());
|
||||
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
public get modelViewId(): string {
|
||||
return this._model.modelViewId;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return NotebookInput.ID;
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): TPromise<IEditorModel> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposeContainer();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _disposeContainer() {
|
||||
if (!this._parentContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
let parentNode = this._parentContainer.parentNode;
|
||||
if (parentNode) {
|
||||
parentNode.removeChild(this._parentContainer);
|
||||
this._parentContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
set container(container: HTMLElement) {
|
||||
this._disposeContainer();
|
||||
this._parentContainer = container;
|
||||
}
|
||||
|
||||
get container(): HTMLElement {
|
||||
return this._parentContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* An editor that is dirty will be asked to be saved once it closes.
|
||||
*/
|
||||
isDirty(): boolean {
|
||||
return this._model.isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result.
|
||||
*/
|
||||
confirmSave(): TPromise<ConfirmResult> {
|
||||
// TODO #2530 support save on close / confirm save. This is significantly more work
|
||||
// as we need to either integrate with textFileService (seems like this isn't viable)
|
||||
// or register our own complimentary service that handles the lifecycle operations such
|
||||
// as close all, auto save etc.
|
||||
return TPromise.wrap(ConfirmResult.DONT_SAVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
|
||||
*/
|
||||
save(): TPromise<boolean> {
|
||||
return this._model.save();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user