mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-15 01:25:36 -05:00
Add Notebook Views dropdown (#16228)
This adds the entry point to NVs. It is currently hidden behind a feature flag, which can be enabled in the settings.
This commit is contained in:
@@ -33,6 +33,13 @@
|
||||
background: url("database_inverse.svg") center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .codicon.icon-dashboard-view::before,
|
||||
.hc-black .codicon.icon-dashboard-view::before,
|
||||
.vs .codicon.icon-dashboard-view::before {
|
||||
-webkit-mask-image: url("dashboard_view.svg");
|
||||
mask-image: url("dashboard_view.svg");
|
||||
}
|
||||
|
||||
.vs .codicon.error,
|
||||
.vs-dark .codicon.error,
|
||||
.hc-black .codicon.error {
|
||||
|
||||
3
src/sql/media/icons/dashboard_view.svg
Normal file
3
src/sql/media/icons/dashboard_view.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4 7H7V16H4V7ZM5 15H6V8H5V15ZM8 9H11V16H8V9ZM9 15H10V10H9V15ZM0 11H3V16H0V11ZM1 15H2V12H1V15ZM12 5H15V16H12V5ZM13 15H14V6H13V15ZM10.8516 4.85156C10.9505 5.0651 11 5.28125 11 5.5C11 5.70833 10.9609 5.90365 10.8828 6.08594C10.8047 6.26823 10.6979 6.42708 10.5625 6.5625C10.4271 6.69792 10.2682 6.80469 10.0859 6.88281C9.90365 6.96094 9.70833 7 9.5 7C9.29167 7 9.09635 6.96094 8.91406 6.88281C8.73177 6.80469 8.57292 6.69792 8.4375 6.5625C8.30208 6.42708 8.19531 6.26823 8.11719 6.08594C8.03906 5.90365 8 5.70833 8 5.5C8 5.46875 8 5.4375 8 5.40625C8 5.375 8.0026 5.34375 8.00781 5.3125L6.53906 4.57812C6.40365 4.71354 6.24479 4.81771 6.0625 4.89062C5.88021 4.96354 5.69271 5 5.5 5C5.28125 5 5.0651 4.95052 4.85156 4.85156L2.85156 6.85156C2.95052 7.0651 3 7.28125 3 7.5C3 7.70833 2.96094 7.90365 2.88281 8.08594C2.80469 8.26823 2.69792 8.42708 2.5625 8.5625C2.42708 8.69792 2.26823 8.80469 2.08594 8.88281C1.90365 8.96094 1.70833 9 1.5 9C1.29167 9 1.09635 8.96094 0.914062 8.88281C0.731771 8.80469 0.572917 8.69792 0.4375 8.5625C0.302083 8.42708 0.195312 8.26823 0.117188 8.08594C0.0390625 7.90365 0 7.70833 0 7.5C0 7.29167 0.0390625 7.09635 0.117188 6.91406C0.195312 6.73177 0.302083 6.57292 0.4375 6.4375C0.572917 6.30208 0.731771 6.19531 0.914062 6.11719C1.09635 6.03906 1.29167 6 1.5 6C1.71875 6 1.9349 6.04948 2.14844 6.14844L4.14844 4.14844C4.04948 3.9349 4 3.71875 4 3.5C4 3.29167 4.03906 3.09635 4.11719 2.91406C4.19531 2.73177 4.30208 2.57292 4.4375 2.4375C4.57292 2.30208 4.73177 2.19531 4.91406 2.11719C5.09635 2.03906 5.29167 2 5.5 2C5.70833 2 5.90365 2.03906 6.08594 2.11719C6.26823 2.19531 6.42708 2.30208 6.5625 2.4375C6.69792 2.57292 6.80469 2.73177 6.88281 2.91406C6.96094 3.09635 7 3.29167 7 3.5C7 3.53125 7 3.5625 7 3.59375C7 3.625 6.9974 3.65625 6.99219 3.6875L8.46094 4.42188C8.59635 4.28646 8.75521 4.18229 8.9375 4.10938C9.11979 4.03646 9.30729 4 9.5 4C9.71875 4 9.9349 4.04948 10.1484 4.14844L12.1484 2.14844C12.0495 1.9349 12 1.71875 12 1.5C12 1.29167 12.0391 1.09635 12.1172 0.914062C12.1953 0.731771 12.3021 0.572917 12.4375 0.4375C12.5729 0.302083 12.7318 0.195312 12.9141 0.117188C13.0964 0.0390625 13.2917 0 13.5 0C13.7083 0 13.9036 0.0390625 14.0859 0.117188C14.2682 0.195312 14.4271 0.302083 14.5625 0.4375C14.6979 0.572917 14.8047 0.731771 14.8828 0.914062C14.9609 1.09635 15 1.29167 15 1.5C15 1.70833 14.9609 1.90365 14.8828 2.08594C14.8047 2.26823 14.6979 2.42708 14.5625 2.5625C14.4271 2.69792 14.2682 2.80469 14.0859 2.88281C13.9036 2.96094 13.7083 3 13.5 3C13.2812 3 13.0651 2.95052 12.8516 2.85156L10.8516 4.85156ZM1.5 8C1.63542 8 1.7526 7.95052 1.85156 7.85156C1.95052 7.7526 2 7.63542 2 7.5C2 7.36458 1.95052 7.2474 1.85156 7.14844C1.7526 7.04948 1.63542 7 1.5 7C1.36458 7 1.2474 7.04948 1.14844 7.14844C1.04948 7.2474 1 7.36458 1 7.5C1 7.63542 1.04948 7.7526 1.14844 7.85156C1.2474 7.95052 1.36458 8 1.5 8ZM13.5 1C13.3646 1 13.2474 1.04948 13.1484 1.14844C13.0495 1.2474 13 1.36458 13 1.5C13 1.63542 13.0495 1.7526 13.1484 1.85156C13.2474 1.95052 13.3646 2 13.5 2C13.6354 2 13.7526 1.95052 13.8516 1.85156C13.9505 1.7526 14 1.63542 14 1.5C14 1.36458 13.9505 1.2474 13.8516 1.14844C13.7526 1.04948 13.6354 1 13.5 1ZM5.5 4C5.63542 4 5.7526 3.95052 5.85156 3.85156C5.95052 3.7526 6 3.63542 6 3.5C6 3.36458 5.95052 3.2474 5.85156 3.14844C5.7526 3.04948 5.63542 3 5.5 3C5.36458 3 5.2474 3.04948 5.14844 3.14844C5.04948 3.2474 5 3.36458 5 3.5C5 3.63542 5.04948 3.7526 5.14844 3.85156C5.2474 3.95052 5.36458 4 5.5 4ZM9.5 6C9.63542 6 9.7526 5.95052 9.85156 5.85156C9.95052 5.7526 10 5.63542 10 5.5C10 5.36458 9.95052 5.2474 9.85156 5.14844C9.7526 5.04948 9.63542 5 9.5 5C9.36458 5 9.2474 5.04948 9.14844 5.14844C9.04948 5.2474 9 5.36458 9 5.5C9 5.63542 9.04948 5.7526 9.14844 5.85156C9.2474 5.95052 9.36458 6 9.5 6Z" fill="#0078D4"/></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -28,7 +28,7 @@ import { INotebookService, INotebookParams, INotebookEditor, INotebookSection, I
|
||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||
import { Deferred } from 'sql/base/common/promise';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { AddCellAction, KernelsDropdown, AttachToDropdown, TrustedAction, RunAllCellsAction, ClearAllOutputsAction, CollapseCellsAction, RunParametersAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
import { AddCellAction, KernelsDropdown, AttachToDropdown, TrustedAction, RunAllCellsAction, ClearAllOutputsAction, CollapseCellsAction, RunParametersAction, NotebookViewsActionProvider } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
import { DropdownMenuActionViewItem } from 'sql/base/browser/ui/buttonMenu/buttonMenu';
|
||||
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
||||
@@ -51,6 +51,7 @@ import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/not
|
||||
import { IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { CellToolbarComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/cellToolbar.component';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
import { MaskedLabeledMenuItemActionItem } from 'sql/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
||||
@@ -70,6 +71,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
@ViewChildren(CellToolbarComponent) private cellToolbar: QueryList<CellToolbarComponent>;
|
||||
|
||||
@Input() _model: NotebookModel;
|
||||
@Input() _views: NotebookViewsExtension;
|
||||
|
||||
protected _actionBar: Taskbar;
|
||||
protected isLoading: boolean;
|
||||
@@ -130,10 +132,14 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
this.notebookService.removeNotebookEditor(this);
|
||||
}
|
||||
}
|
||||
public get model(): NotebookModel | null {
|
||||
public get model(): NotebookModel | undefined {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
public get views(): NotebookViewsExtension | undefined {
|
||||
return this._views;
|
||||
}
|
||||
|
||||
public get activeCellId(): string {
|
||||
return this._model && this._model.activeCell ? this._model.activeCell.id : '';
|
||||
}
|
||||
@@ -442,6 +448,28 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
dropdownMenuActionViewItem.render(buttonDropdownContainer);
|
||||
dropdownMenuActionViewItem.setActionContext(this._notebookParams.notebookUri);
|
||||
|
||||
let viewsDropdownContainer;
|
||||
if (this._configurationService.getValue<boolean>('notebookViews.enabled')) {
|
||||
let viewsContainer = document.createElement('li');
|
||||
let viewsActionsProvider = new NotebookViewsActionProvider(viewsContainer, this.views, this.modelReady, this.notebookService, this.notificationService, this.instantiationService);
|
||||
let viewsButton = new Action('notebook.OpenViews', localize('views', "Views"), 'notebook-button masked-pseudo code');
|
||||
viewsDropdownContainer = DOM.$('li.action-item');
|
||||
viewsDropdownContainer.setAttribute('role', 'presentation');
|
||||
let viewsDropdownMenuActionViewItem = new DropdownMenuActionViewItem(
|
||||
viewsButton,
|
||||
viewsActionsProvider,
|
||||
this.contextMenuService,
|
||||
undefined,
|
||||
this._actionBar.actionRunner,
|
||||
undefined,
|
||||
'codicon notebook-button masked-pseudo masked-pseudo-after icon-dashboard-view dropdown-arrow',
|
||||
localize('editor', "Editor"),
|
||||
undefined
|
||||
);
|
||||
viewsDropdownMenuActionViewItem.render(viewsDropdownContainer);
|
||||
viewsDropdownMenuActionViewItem.setActionContext(this._notebookParams.notebookUri);
|
||||
}
|
||||
|
||||
this._actionBar.setContent([
|
||||
{ element: buttonDropdownContainer },
|
||||
{ action: this._runAllCellsAction },
|
||||
@@ -449,6 +477,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
{ element: kernelContainer },
|
||||
{ element: attachToContainer },
|
||||
{ element: spacerElement },
|
||||
{ element: viewsDropdownContainer },
|
||||
{ action: collapseCellsAction },
|
||||
{ action: clearResultsButton },
|
||||
{ action: this._trustedAction },
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as path from 'vs/base/common/path';
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Action, IAction, Separator } from 'vs/base/common/actions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { INotificationService, Severity, INotificationActions } from 'vs/platform/notification/common/notification';
|
||||
@@ -18,21 +18,25 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
|
||||
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { CellType } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { CellType, NotebookChangeType } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { getErrorMessage } from 'vs/base/common/errors';
|
||||
import { IEditorAction } from 'vs/editor/common/editorCommon';
|
||||
import { IFindNotebookController } from 'sql/workbench/contrib/notebook/browser/find/notebookFindWidget';
|
||||
import { INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { INotebookModel, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
||||
import { TreeUpdateUtils } from 'sql/workbench/services/objectExplorer/browser/treeUpdateUtils';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { CellContext } from 'sql/workbench/contrib/notebook/browser/cellViews/codeActions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IActionProvider } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { KernelsLanguage } from 'sql/workbench/services/notebook/common/notebookConstants';
|
||||
import { INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
|
||||
const msgLoading = localize('loading', "Loading kernels...");
|
||||
export const msgChanging = localize('changing', "Changing kernel...");
|
||||
@@ -178,6 +182,148 @@ export abstract class ToggleableAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookViewsActionProvider implements IActionProvider {
|
||||
private _options: Action[] = [];
|
||||
private views: INotebookViews;
|
||||
private viewMode: ViewMode;
|
||||
private readonly _optionsUpdated = new Emitter<boolean>();
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
views: INotebookViews,
|
||||
modelReady: Promise<INotebookModel>,
|
||||
@INotebookService private _notebookService: INotebookService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService) {
|
||||
|
||||
modelReady?.then((model) => {
|
||||
this.views = views;
|
||||
this.viewMode = model.viewMode;
|
||||
this.updateView();
|
||||
})
|
||||
.catch((err) => {
|
||||
this._notificationService.error(getErrorMessage(err));
|
||||
});
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
public get options(): Action[] {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update SelectBox values
|
||||
*/
|
||||
public updateView() {
|
||||
const backToNotebookButton = this.instantiationService.createInstance(NotebookViewAction, 'notebookView.backToNotebook', localize('notebookViewLabel', 'Editor'), 'notebook-button');
|
||||
const newViewButton = this.instantiationService.createInstance(CreateNotebookViewAction, 'notebookView.newView', localize('newViewLabel', 'Create New View'), 'notebook-button notebook-button-newview');
|
||||
|
||||
const views = this.views.getViews();
|
||||
this._options = [];
|
||||
|
||||
this._options.push(backToNotebookButton);
|
||||
this._options.push(newViewButton);
|
||||
|
||||
if (views.length) {
|
||||
this._options.push(this.instantiationService.createInstance(Separator));
|
||||
}
|
||||
|
||||
views.forEach((view) => {
|
||||
const option = new DashboardViewAction(view.guid, view.name, 'button', this._notebookService, this._notificationService);
|
||||
this._options.push(option);
|
||||
|
||||
if (this.viewMode === ViewMode.Views && this.views.getActiveView() === view) {
|
||||
option.checked = true;
|
||||
option.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (this.viewMode === ViewMode.Notebook) {
|
||||
backToNotebookButton.checked = true;
|
||||
backToNotebookButton.enabled = false;
|
||||
}
|
||||
|
||||
this._optionsUpdated.fire(true);
|
||||
}
|
||||
|
||||
public get onUpdated(): Event<boolean> {
|
||||
return this._optionsUpdated.event;
|
||||
}
|
||||
|
||||
public optionSelected(displayName: string): void {
|
||||
const view = this.views.getViews().find(view => view.name === displayName);
|
||||
this.views.setActiveView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to open a Notebook View
|
||||
*/
|
||||
export class DashboardViewAction extends Action {
|
||||
constructor(
|
||||
id: string, label: string, cssClass: string,
|
||||
@INotebookService private _notebookService: INotebookService,
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
) {
|
||||
super(id, label, cssClass);
|
||||
}
|
||||
|
||||
public override async run(context: URI): Promise<void> {
|
||||
if (context) {
|
||||
const editor = this._notebookService.findNotebookEditor(context);
|
||||
let views = editor.views;
|
||||
const view = views.getViews().find(view => view.guid === this.id);
|
||||
|
||||
if (view) {
|
||||
views.setActiveView(view);
|
||||
editor.model.viewMode = ViewMode.Views;
|
||||
} else {
|
||||
this._notificationService.error(localize('viewNotFound', "Unable to find view: {0}", this.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to open enter the default notebook editor
|
||||
*/
|
||||
export class NotebookViewAction extends Action {
|
||||
constructor(
|
||||
id: string, label: string, cssClass: string,
|
||||
@INotebookService private _notebookService: INotebookService
|
||||
) {
|
||||
super(id, label, cssClass);
|
||||
}
|
||||
public override async run(context: URI): Promise<void> {
|
||||
const editor = this._notebookService.findNotebookEditor(context);
|
||||
editor.model.viewMode = ViewMode.Notebook;
|
||||
}
|
||||
}
|
||||
|
||||
export class CreateNotebookViewAction extends Action {
|
||||
constructor(
|
||||
id: string, label: string, cssClass: string,
|
||||
@INotebookService private _notebookService: INotebookService
|
||||
) {
|
||||
super(id, label, cssClass);
|
||||
}
|
||||
public override async run(context: URI): Promise<void> {
|
||||
if (context) {
|
||||
const editor = this._notebookService.findNotebookEditor(context);
|
||||
const views = editor.views;
|
||||
|
||||
const newView = views.createNewView();
|
||||
views.setActiveView(newView);
|
||||
|
||||
editor.model.viewMode = ViewMode.Views;
|
||||
editor.model.serializationStateChanged(NotebookChangeType.MetadataChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class TrustedAction extends ToggleableAction {
|
||||
// Constants
|
||||
private static readonly trustedLabel = localize('trustLabel', "Trusted");
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<!-- Notebook View -->
|
||||
<notebook-component *ngIf="viewMode === 0" [_model]="model"></notebook-component>
|
||||
<notebook-component *ngIf="viewMode === 0" [_views]="views" [_model]="model"></notebook-component>
|
||||
<!-- Dashboard View: To be implemented-->
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IAction, SubmenuAction } from 'vs/base/common/actions';
|
||||
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
|
||||
export const NOTEBOOKEDITOR_SELECTOR: string = 'notebookeditor-component';
|
||||
|
||||
@@ -36,6 +37,8 @@ export class NotebookEditorComponent extends AngularDisposable {
|
||||
private notebookManagers: INotebookManager[] = [];
|
||||
private _model: NotebookModel;
|
||||
|
||||
public views: NotebookViewsExtension;
|
||||
|
||||
constructor(
|
||||
@Inject(ILogService) private readonly logService: ILogService,
|
||||
@Inject(IBootstrapParams) private _notebookParams: INotebookParams,
|
||||
@@ -104,6 +107,8 @@ export class NotebookEditorComponent extends AngularDisposable {
|
||||
this._model = this._register(model);
|
||||
await this.model.loadContents(trusted);
|
||||
|
||||
this.views = new NotebookViewsExtension(this.model);
|
||||
|
||||
this._register(model.viewModeChanged((mode) => this.onViewModeChanged()));
|
||||
this._register(model.contentChanged((change) => this.handleContentChanged(change)));
|
||||
this._register(model.onCellTypeChanged(() => this.detectChanges()));
|
||||
|
||||
@@ -7,15 +7,15 @@ import * as assert from 'assert';
|
||||
import * as azdata from 'azdata';
|
||||
import * as sinon from 'sinon';
|
||||
import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService';
|
||||
import { AddCellAction, ClearAllOutputsAction, CollapseCellsAction, kernelNotSupported, KernelsDropdown, msgChanging, NewNotebookAction, noKernelName, noParameterCell, noParametersInCell, RunAllCellsAction, RunParametersAction, TrustedAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
import { ClientSessionStub, ContextViewProviderStub, NotebookComponentStub, NotebookModelStub, NotebookServiceStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||
import { AddCellAction, ClearAllOutputsAction, CollapseCellsAction, CreateNotebookViewAction, DashboardViewAction, kernelNotSupported, KernelsDropdown, msgChanging, NewNotebookAction, noKernelName, noParameterCell, noParametersInCell, NotebookViewAction, NotebookViewsActionProvider, RunAllCellsAction, RunParametersAction, TrustedAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
import { ClientSessionStub, ContextViewProviderStub, NotebookComponentStub, NotebookModelStub, NotebookServiceStub, NotebookViewsStub, NotebookViewStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||
import { NotebookEditorStub } from 'sql/workbench/contrib/notebook/test/testCommon';
|
||||
import { ICellModel, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { ICellModel, INotebookModel, ViewMode } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||
import { INotebookEditor, INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { CellType, CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { TestCommandService } from 'vs/editor/test/browser/editorTestServices';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IConfigurationChangeEvent, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -26,6 +26,9 @@ import { workbenchInstantiationService } from 'vs/workbench/test/browser/workben
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { NullAdsTelemetryService } from 'sql/platform/telemetry/common/adsTelemetryService';
|
||||
import { MockQuickInputService } from 'sql/workbench/contrib/notebook/test/common/quickInputServiceMock';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { Separator } from 'vs/base/common/actions';
|
||||
import { INotebookView, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
|
||||
class TestClientSession extends ClientSessionStub {
|
||||
private _errorState: boolean = false;
|
||||
@@ -519,6 +522,50 @@ suite('Notebook Actions', function (): void {
|
||||
assert.strictEqual(actualMsg, expectedMsg);
|
||||
});
|
||||
|
||||
test('notebookViewsActionProvider', async () => {
|
||||
const testGuid = '1';
|
||||
const testName = 'Notebook-0';
|
||||
|
||||
const testNotebookModel: INotebookModel = <INotebookModel>{
|
||||
viewMode: ViewMode.Notebook
|
||||
};
|
||||
|
||||
const notebookEditor = new NotebookEditorStub({ model: testNotebookModel });
|
||||
|
||||
const mockNotification = TypeMoq.Mock.ofType<INotificationService>(TestNotificationService);
|
||||
const notebookViews = TypeMoq.Mock.ofType<INotebookViews>(NotebookViewsStub);
|
||||
|
||||
const notebookView = TypeMoq.Mock.ofType<INotebookView>(NotebookViewStub);
|
||||
notebookView.setup(x => x.guid).returns(() => testGuid);
|
||||
notebookView.setup(x => x.name).returns(() => testName);
|
||||
const views: INotebookView[] = [notebookView.object];
|
||||
|
||||
notebookViews.setup(x => x.getViews()).returns(() => views);
|
||||
notebookViews.setup(x => x.getActiveView()).returns(() => undefined);
|
||||
|
||||
const notebookViewAction = new NotebookViewAction('notebookView.backToNotebook', 'Editor', 'notebook-button', mockNotebookService.object);
|
||||
const createNotebookViewAction = new CreateNotebookViewAction('notebookView.newView', 'Create New View', 'notebook-button notebook-button-newview', mockNotebookService.object);
|
||||
const separator = new Separator();
|
||||
|
||||
// Create a mocked out instantiation service
|
||||
const mockInstantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Strict);
|
||||
mockInstantiationService.setup(x => x.createInstance(TypeMoq.It.isValue(NotebookViewAction), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => notebookViewAction);
|
||||
mockInstantiationService.setup(x => x.createInstance(TypeMoq.It.isValue(CreateNotebookViewAction), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => createNotebookViewAction);
|
||||
mockInstantiationService.setup(x => x.createInstance(TypeMoq.It.isValue(Separator))).returns(() => separator);
|
||||
|
||||
const viewsContainer = document.createElement('li');
|
||||
const viewsActionsProvider = new NotebookViewsActionProvider(viewsContainer, notebookViews.object, notebookEditor.modelReady, mockNotebookService.object, mockNotification.object, mockInstantiationService.object);
|
||||
|
||||
await Event.toPromise(viewsActionsProvider.onUpdated);
|
||||
|
||||
const actions = viewsActionsProvider.getActions();
|
||||
|
||||
// It includes all the options
|
||||
assert.strictEqual(actions.filter(a => a instanceof DashboardViewAction).length, 1);
|
||||
assert.strictEqual(actions.filter(a => a instanceof NotebookViewAction).length, 1);
|
||||
assert.strictEqual(actions.filter(a => a instanceof CreateNotebookViewAction).length, 1);
|
||||
});
|
||||
|
||||
suite('Kernels dropdown', async () => {
|
||||
let kernelsDropdown: KernelsDropdown;
|
||||
let contextViewProvider: ContextViewProviderStub;
|
||||
|
||||
@@ -132,6 +132,7 @@ suite('Notebook Editor Model', function (): void {
|
||||
notebookParams: undefined,
|
||||
modelReady: undefined,
|
||||
model: notebookModel,
|
||||
views: undefined,
|
||||
isDirty: undefined,
|
||||
isActive: undefined,
|
||||
isVisible: undefined,
|
||||
|
||||
@@ -19,6 +19,8 @@ import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryText
|
||||
import { IContextViewProvider, IDelegate } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
import { INotebookView, INotebookViewCell, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
|
||||
export class NotebookModelStub implements INotebookModel {
|
||||
constructor(private _languageInfo?: nb.ILanguageInfo, private _cells?: ICellModel[], private _testContents?: nb.INotebookContents) {
|
||||
@@ -490,6 +492,9 @@ export class NotebookComponentStub implements INotebookEditor {
|
||||
get model(): INotebookModel {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
get views(): NotebookViewsExtension {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
isDirty(): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@@ -684,6 +689,7 @@ export class NotebookEditorStub implements INotebookEditor {
|
||||
cellEditors: CellEditorProviderStub[];
|
||||
modelReady: Promise<INotebookModel>;
|
||||
model: INotebookModel;
|
||||
views: NotebookViewsExtension;
|
||||
viewMode: string;
|
||||
isDirty(): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
@@ -754,3 +760,77 @@ export class ContextViewProviderStub implements IContextViewProvider {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookViewStub implements INotebookView {
|
||||
isNew: boolean;
|
||||
name: string = '';
|
||||
guid: string = '';
|
||||
cells: readonly ICellModel[] = [];
|
||||
hiddenCells: readonly ICellModel[];
|
||||
displayedCells: readonly ICellModel[];
|
||||
|
||||
onDeleted: vsEvent.Event<INotebookView>;
|
||||
initialize(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
nameAvailable(name: string): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getCellMetadata(cell: ICellModel): INotebookViewCell {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
hideCell(cell: ICellModel): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
moveCell(cell: ICellModel, x: number, y: number): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
resizeCell(cell: ICellModel, width: number, height: number): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
compactCells() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
markAsViewed(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getCell(guid: string): Readonly<ICellModel> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
insertCell(cell: ICellModel): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
save(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
delete(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookViewsStub implements INotebookViews {
|
||||
notebook: INotebookModel;
|
||||
onViewDeleted: vsEvent.Event<void>;
|
||||
createNewView(name?: string): INotebookView {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
removeView(guid: string): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
generateDefaultViewName(): string {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getViews(): INotebookView[] {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getActiveView(): INotebookView {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
setActiveView(view: INotebookView): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
viewNameIsTaken(name: string): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,15 +13,17 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { TestEditorGroupsService, TestEditorService, TestTextResourceConfigurationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
|
||||
// Typically you will pass in either editor or the instantiationService parameter.
|
||||
// Leave both undefined when you want the underlying object(s) to have an undefined editor.
|
||||
export class NotebookEditorStub extends stubs.NotebookEditorStub {
|
||||
// Normally one needs to provide either the editor or the instantiationService as the constructor parameter
|
||||
constructor({ cellGuid, instantiationService, editor, model, notebookParams }: { cellGuid?: string; instantiationService?: IInstantiationService; editor?: QueryTextEditor; model?: INotebookModel, notebookParams?: INotebookParams } = {}) {
|
||||
constructor({ cellGuid, instantiationService, editor, model, views, notebookParams }: { cellGuid?: string; instantiationService?: IInstantiationService; editor?: QueryTextEditor; model?: INotebookModel, views?: NotebookViewsExtension, notebookParams?: INotebookParams } = {}) {
|
||||
super();
|
||||
this.cells = [];
|
||||
this.model = model;
|
||||
this.views = views;
|
||||
this.notebookParams = notebookParams;
|
||||
this.cellEditors = [new CellEditorProviderStub({ cellGuid: cellGuid, instantiationService: instantiationService, editor: editor })];
|
||||
this.id = this.notebookParams?.notebookUri?.toString();
|
||||
|
||||
@@ -20,6 +20,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { INotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
|
||||
export const SERVICE_ID = 'sqlNotebookService';
|
||||
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
|
||||
@@ -210,6 +211,7 @@ export interface INotebookEditor {
|
||||
readonly cellEditors: ICellEditorProvider[];
|
||||
readonly modelReady: Promise<INotebookModel>;
|
||||
readonly model: INotebookModel | null;
|
||||
readonly views: NotebookViewsExtension | null;
|
||||
isDirty(): boolean;
|
||||
isActive(): boolean;
|
||||
isVisible(): boolean;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { ICellModel, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export type CellChangeEventType = 'hide' | 'insert' | 'active';
|
||||
@@ -62,3 +62,16 @@ export interface INotebookViewMetadata {
|
||||
export interface INotebookViewCellMetadata {
|
||||
views: INotebookViewCell[];
|
||||
}
|
||||
|
||||
export interface INotebookViews {
|
||||
onViewDeleted: Event<void>;
|
||||
notebook: INotebookModel;
|
||||
|
||||
createNewView(name?: string): INotebookView;
|
||||
removeView(guid: string): void;
|
||||
generateDefaultViewName(): string;
|
||||
getViews(): INotebookView[];
|
||||
getActiveView(): INotebookView;
|
||||
setActiveView(view: INotebookView): void;
|
||||
viewNameIsTaken(name: string): boolean;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { localize } from 'vs/nls';
|
||||
import { NotebookViewModel } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel';
|
||||
import { NotebookExtension } from 'sql/workbench/services/notebook/browser/models/notebookExtension';
|
||||
import { INotebookView, INotebookViewCell, INotebookViewCellMetadata, INotebookViewMetadata } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
import { INotebookView, INotebookViewCell, INotebookViewCellMetadata, INotebookViewMetadata, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
|
||||
export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetadata, INotebookViewCellMetadata> {
|
||||
export class NotebookViewsExtension extends NotebookExtension<INotebookViewMetadata, INotebookViewCellMetadata> implements INotebookViews {
|
||||
static readonly defaultViewName = localize('notebookView.untitledView', "Untitled View");
|
||||
|
||||
readonly maxNameIterationAttempts = 100;
|
||||
|
||||
Reference in New Issue
Block a user