mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-04 01:25:38 -05:00
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:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user