Notebook views UI 2 (#15865)

Provide access to the Notebook Views UI. Feature is hidden behind a feature flag.

Co-authored-by: rkselfhost <rkselfhost@outlook.com>
This commit is contained in:
Daniel Grajeda
2021-08-17 15:15:28 -06:00
committed by GitHub
parent 82576e54a4
commit 640c6f30f4
29 changed files with 989 additions and 140 deletions

View File

@@ -593,6 +593,7 @@ export class CellModel extends Disposable implements ICellModel {
}, false);
this.setFuture(future as FutureInternal);
this.fireExecutionStateChanged();
this.notebookModel.onCellChange(this, NotebookChangeType.CellExecutionStarted);
this._notebookService?.notifyCellExecutionStarted();
// For now, await future completion. Later we should just track and handle cancellation based on model notifications
let result: nb.IExecuteReplyMsg = <nb.IExecuteReplyMsg><any>await future.done;
@@ -920,6 +921,9 @@ export class CellModel extends Disposable implements ICellModel {
}
}
};
this.sendChangeToNotebook(NotebookChangeType.CellAwaitingInput);
return handler();
}

View File

@@ -5,6 +5,7 @@
import { INotebookModel, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
import { deepClone } from 'vs/base/common/objects';
export class NotebookExtension<TNotebookMeta, TCellMeta> {
readonly version = 1;
@@ -32,6 +33,7 @@ export class NotebookExtension<TNotebookMeta, TCellMeta> {
const meta = {};
meta[this.extensionName] = metadata;
cell.metadata[this.extensionNamespace] = meta;
cell.metadata = deepClone(cell.metadata); // creating a new reference for change detection
cell.sendChangeToNotebook(NotebookChangeType.CellsModified);
}
}

View File

@@ -31,11 +31,19 @@ export class NotebookViewModel implements INotebookView {
private _notebookViews: NotebookViewsExtension,
guid?: string
) {
this.guid = generateUuid();
this.guid = guid ?? generateUuid();
}
public initialize(): void {
this._isNew = true;
public static load(guid: string, notebookViews: NotebookViewsExtension): INotebookView {
const view = notebookViews.getViews().find(v => v.guid === guid);
return new NotebookViewModel(view.name, notebookViews, view.guid);
}
public initialize(isNew?: boolean): void {
if (isNew) {
this._isNew = isNew;
}
const cells = this._notebookViews.notebook.cells;
cells.forEach((cell, idx) => { this.initializeCell(cell, idx); });
}
@@ -48,14 +56,21 @@ export class NotebookViewModel implements INotebookView {
meta = this._notebookViews.getCellMetadata(cell);
}
meta.views.push({
guid: this.guid,
hidden: false,
y: idx * DEFAULT_VIEW_CARD_HEIGHT,
x: 0,
width: DEFAULT_VIEW_CARD_WIDTH,
height: DEFAULT_VIEW_CARD_HEIGHT
});
// Ensure that we are not duplicting view entries in cell metadata
if (!meta.views.find(v => v.guid === this.guid)) {
meta.views.push({
guid: this.guid,
hidden: false,
y: idx * DEFAULT_VIEW_CARD_HEIGHT,
x: 0,
width: DEFAULT_VIEW_CARD_WIDTH,
height: DEFAULT_VIEW_CARD_HEIGHT
});
}
}
public cellInitialized(cell: ICellModel): boolean {
return !!this.getCellMetadata(cell);
}
public get name(): string {
@@ -79,7 +94,7 @@ export class NotebookViewModel implements INotebookView {
}
public get hiddenCells(): Readonly<ICellModel[]> {
return this.cells.filter(cell => this.getCellMetadata(cell)?.hidden);
return this.cells.filter(cell => this.getCellMetadata(cell)?.hidden !== false);
}
public get cells(): Readonly<ICellModel[]> {
@@ -94,16 +109,24 @@ export class NotebookViewModel implements INotebookView {
return this._notebookViews.notebook.cells.find(cell => cell.cellGuid === guid);
}
public updateCell(cell: ICellModel, currentView: INotebookView, cellData: INotebookViewCell, override: boolean = false) {
if (!this.cellInitialized(cell)) {
this.initializeCell(cell, 0);
}
this._notebookViews.updateCell(cell, currentView, cellData, override);
}
public insertCell(cell: ICellModel) {
this._notebookViews.updateCell(cell, this, { hidden: false });
this.updateCell(cell, this, { hidden: false });
}
public hideCell(cell: ICellModel) {
this._notebookViews.updateCell(cell, this, { hidden: true });
this.updateCell(cell, this, { hidden: true });
}
public moveCell(cell: ICellModel, x: number, y: number) {
this._notebookViews.updateCell(cell, this, { x, y });
this.updateCell(cell, this, { x, y });
}
public resizeCell(cell: ICellModel, width?: number, height?: number) {
@@ -117,7 +140,7 @@ export class NotebookViewModel implements INotebookView {
data.height = height;
}
this._notebookViews.updateCell(cell, this, data);
this.updateCell(cell, this, data);
}
public getCellSize(cell: ICellModel): any {

View File

@@ -6,23 +6,33 @@
import { ICellModel, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { Event } from 'vs/base/common/event';
export type CellChangeEventType = 'hide' | 'insert' | 'active';
export type CellChangeEventType = 'hide' | 'insert' | 'active' | 'execution' | 'update';
export type CellChangeEvent = {
cell: ICellModel,
event: CellChangeEventType
};
export interface INotebookViews {
onActiveViewChanged: Event<void>;
createNewView(name?: string): INotebookView;
removeView(guid: string): void;
getActiveView(): INotebookView;
setActiveView(view: INotebookView);
viewNameIsTaken(name: string): boolean;
metadata: INotebookViewMetadata;
}
export interface INotebookView {
readonly guid: string;
readonly onDeleted: Event<INotebookView>;
isNew: boolean;
cells: Readonly<ICellModel[]>;
hiddenCells: Readonly<ICellModel[]>;
displayedCells: Readonly<ICellModel[]>;
name: string;
initialize(): void;
initialize(isNew?: boolean): void;
nameAvailable(name: string): boolean;
getCellMetadata(cell: ICellModel): INotebookViewCell;
hideCell(cell: ICellModel): void;

View File

@@ -20,6 +20,7 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
protected _metadata: INotebookViewMetadata;
private _onViewDeleted = new Emitter<void>();
private _onActiveViewChanged = new Emitter<void>();
constructor(protected _notebook: INotebookModel) {
super();
@@ -33,6 +34,8 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
this.initializeNotebook();
this.initializeCells();
this.commit();
} else {
this._metadata.views = this._metadata.views.map(view => NotebookViewModel.load(view.guid, this));
}
}
@@ -63,9 +66,12 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
const viewName = name || this.generateDefaultViewName();
const view = new NotebookViewModel(viewName, this);
view.initialize();
view.initialize(true);
this._metadata.views.push(view);
//Add view to the views metadata
this._metadata = Object.assign({}, this._metadata, { views: [...this._metadata.views, view] });
this.commit();
return view;
}
@@ -76,21 +82,21 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
let removedView = this._metadata.views.splice(viewToRemove, 1);
// Remove view data for each cell
if (removedView.length) {
if (removedView.length === 1) {
this._notebook?.cells.forEach((cell) => {
let meta = this.getCellMetadata(cell);
meta.views.splice(viewToRemove, 1);
meta.views = meta.views.filter(x => x.guid !== removedView[0].guid);
this.setCellMetadata(cell, meta);
});
}
this.setNotebookMetadata(this.notebook, this._metadata);
}
if (guid === this._metadata.activeView) {
this._metadata.activeView = undefined;
}
this._metadata = Object.assign({}, this._metadata);
this._onViewDeleted.fire();
this.commit();
}
@@ -108,11 +114,13 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
public updateCell(cell: ICellModel, currentView: INotebookView, cellData: INotebookViewCell, override: boolean = false) {
const cellMetadata = this.getCellMetadata(cell);
const viewToUpdate = cellMetadata.views.findIndex(view => view.guid === currentView.guid);
if (cellMetadata) {
const viewToUpdate = cellMetadata.views.findIndex(view => view.guid === currentView.guid);
if (viewToUpdate >= 0) {
cellMetadata.views[viewToUpdate] = override ? cellData : { ...cellMetadata.views[viewToUpdate], ...cellData };
this.setCellMetadata(cell, cellMetadata);
if (viewToUpdate >= 0) {
cellMetadata.views[viewToUpdate] = override ? cellData : { ...cellMetadata.views[viewToUpdate], ...cellData };
this.setCellMetadata(cell, cellMetadata);
}
}
}
@@ -124,6 +132,10 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
return this._metadata.views;
}
public get metadata(): INotebookViewMetadata {
return this._metadata;
}
public getCells(): INotebookViewCellMetadata[] {
return this._notebook.cells.map(cell => this.getCellMetadata(cell));
}
@@ -134,9 +146,11 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
public setActiveView(view: INotebookView) {
this._metadata.activeView = view.guid;
this._onActiveViewChanged.fire();
}
public commit() {
this._metadata = Object.assign({}, this._metadata);
this.setNotebookMetadata(this._notebook, this._metadata);
}
@@ -147,4 +161,8 @@ export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetad
public get onViewDeleted(): Event<void> {
return this._onViewDeleted.event;
}
public get onActiveViewChanged(): Event<void> {
return this._onActiveViewChanged.event;
}
}