mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 17:22:45 -05:00
Notebook cell toolbar additions - move cell, convert cell (#11457)
* Notebook cell toolbar additions - move up and move down added. Stubbed out related actions. Cleaned up component code. * Added new more actions menu item: Convert cell. * add move cell support in model * Schema Compare cleanup (#11418) * cleanup async and await stuff * remove awaits * remove more awaits * fix (#11437) * Add some unit tests for PyPiClient. (#11442) * handle invalid character in kubectl version output (#11460) * Add tests for azdata extension (#11423) * Add tests for azdata extension * Fail on stderr * Skip test for not implemented logic * Move executeCommand stub * Add missing packages * let semver to parse the version (#11463) * let semver to parse the version * check * Stop hardcoding python3 (#11464) * Add ConnectControllerDialog tests (#11443) * Automatically fix up arc controller URL * wip * Force tests to pass * Refactor * comment * adds role of button to all links that are buttons (#11465) * Merge from vscode 0a7364f00514c46c9caceece15e1f82f82e3712f * bump smoke extensions * bump node version in builds * bump smoke extensions * Add query-history and sql-assessment to recommended extensions (#11477) * First draft of outputProcessor tests (#11368) * First draft of outputProcessor tests * add return type for a function * pr feedback * comments and Spellings, getRandom ==> getRandomElement * pr feedback * pr feedback * Adds support for installing azdata on Linux (#11469) * Large cleanup of AzureCore - Introduction of getAccountSecurityToken and deprecation of getSecurityToken (#11446) * do a large cleanup of azurecore * Fix tests * Rework Device Code * Fix tests * Fix AE scenario * Fix firewall rule - clenaup logging * Shorthand syntax * Fix firewall tests * Start on tests for azureAuth * Add more tests * Address comments * Add a few more important tests * Don't throw error on old code * Fill in todo * Adding button plugin to table component (#10918) * Added delete plugin to table component * Arc - Remove Azure params from Postgres deployment (#11478) Co-authored-by: Brian Bergeron <brberger@microsoft.com> * tests for KernelsDropdown class (#11476) * add return type for a function * tests for KernelsDropdown class * remove inadvertent change * remove inadvertent change * formatting changes * pr feedback * pr feedback * implement review feedback (#11470) * fix sql proj sqlcmd table showing after loading profile when it shouldn't (#11479) * Feature/outer paths for project (#11445) * allow relative paths in project file outside of project folder * Adding some tests * Adding error string to loc strings * Fixed test * fix error message * PR comments and some more fixes * change userName to match what the azure account display name is (#11484) * change userName to match what the azure account display name is * Handle undefined value * Merge from vscode 8c426f9f3b6b18935cc6c2ec8aa6d45ccd88021e * recomment out integration tests * Fix/open book error (#11379) * add isNotebook param and showPreview option * showPreview changes * update OpenNotebookFolder to open a specific path * added test for showPreviewFile * test name typo * remove isNotebook from openBook * Add test coverage for dacpac wizard import flow (#11483) * Adding importConfig onPageEnter() test * Removing redundancy from dacpac wizard pages * promisifying file selection so it can be awaited in the test * removing debug prints * PR feedback * Remove all accounts regardless of failure in one account (#11431) * distro (#11487) * distro * distro * distro * distro * Adding icons to Database Projects' tree view (#11488) * Add images * Splitting to light and dark mode icons * Hooks up icons to treeItems * updating package.json with new icon and vbump * move icon loader before tree view created * Update Arc extension version and fix Controller connectivity status names (#11498) * Update connectivity mode names (cherry picked from commit f0aabcfa86d178cdf74470f9fdeded19718bcea2) * Bump package version (cherry picked from commit e08370539006c638d6e25c2f4f23fa2754a3377d) * deploy to single existing device (#11494) * deploy to single existing device * comments * Add versioning for accounts (#11497) * Add versioning for accounts * deletion value * Changes to getAccountSecurityToken (#11502) * Hook up convert cell * Fix tests * Add convert cell tests Co-authored-by: chlafreniere <hichise@gmail.com> Co-authored-by: Kim Santiago <31145923+kisantia@users.noreply.github.com> Co-authored-by: Maddy <12754347+MaddyDev@users.noreply.github.com> Co-authored-by: Cory Rivera <corivera@microsoft.com> Co-authored-by: Alan Ren <alanren@microsoft.com> Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> Co-authored-by: Chris LaFreniere <40371649+chlafreniere@users.noreply.github.com> Co-authored-by: v-bbrady <60623315+v-bbrady@users.noreply.github.com> Co-authored-by: ADS Merger <andresse@microsoft.com> Co-authored-by: Arvind Ranasaria <ranasaria@outlook.com> Co-authored-by: Amir Omidi <amomidi@microsoft.com> Co-authored-by: Leila Lali <llali@microsoft.com> Co-authored-by: Brian Bergeron <brian.e.bergeron@gmail.com> Co-authored-by: Brian Bergeron <brberger@microsoft.com> Co-authored-by: Udeesha Gautam <46980425+udeeshagautam@users.noreply.github.com> Co-authored-by: Benjin Dubishar <benjin.dubishar@gmail.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import Severity from 'vs/base/common/severity';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { MoveDirection } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
|
||||
|
||||
export class EditCellAction extends ToggleableAction {
|
||||
@@ -65,6 +66,35 @@ export class EditCellAction extends ToggleableAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class MoveCellAction extends CellActionBase {
|
||||
constructor(
|
||||
id: string,
|
||||
cssClass: string,
|
||||
label: string,
|
||||
@INotificationService notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, undefined, notificationService);
|
||||
this._cssClass = cssClass;
|
||||
this._tooltip = label;
|
||||
this._label = '';
|
||||
}
|
||||
|
||||
doRun(context: CellContext): Promise<void> {
|
||||
let moveDirection = this._cssClass.includes('move-down') ? MoveDirection.Down : MoveDirection.Up;
|
||||
try {
|
||||
context.model.moveCell(context.cell, moveDirection);
|
||||
} catch (error) {
|
||||
let message = getErrorMessage(error);
|
||||
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class DeleteCellAction extends CellActionBase {
|
||||
constructor(
|
||||
id: string,
|
||||
@@ -101,6 +131,8 @@ export class CellToggleMoreActions {
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
this._actions.push(
|
||||
instantiationService.createInstance(ConvertCellAction, 'convertCell', localize('convertCell', "Convert Cell")),
|
||||
new Separator(),
|
||||
instantiationService.createInstance(RunCellsAction, 'runAllAbove', localize('runAllAbove', "Run Cells Above"), false),
|
||||
instantiationService.createInstance(RunCellsAction, 'runAllBelow', localize('runAllBelow', "Run Cells Below"), true),
|
||||
new Separator(),
|
||||
@@ -151,6 +183,28 @@ export function removeDuplicatedAndStartingSeparators(actions: (Action | CellAct
|
||||
}
|
||||
}
|
||||
|
||||
export class ConvertCellAction extends CellActionBase {
|
||||
constructor(id: string, label: string,
|
||||
@INotificationService notificationService: INotificationService
|
||||
) {
|
||||
super(id, label, undefined, notificationService);
|
||||
}
|
||||
|
||||
doRun(context: CellContext): Promise<void> {
|
||||
try {
|
||||
context?.model?.convertCellType(context?.cell);
|
||||
} catch (error) {
|
||||
let message = getErrorMessage(error);
|
||||
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export class AddCellFromContextAction extends CellActionBase {
|
||||
constructor(
|
||||
id: string, label: string, private cellType: CellType, private isAfter: boolean,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { localize } from 'vs/nls';
|
||||
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DeleteCellAction, EditCellAction, CellToggleMoreActions } from 'sql/workbench/contrib/notebook/browser/cellToolbarActions';
|
||||
import { DeleteCellAction, EditCellAction, CellToggleMoreActions, MoveCellAction } from 'sql/workbench/contrib/notebook/browser/cellToolbarActions';
|
||||
import { AddCellAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { DropdownMenuActionViewItem } from 'sql/base/browser/ui/buttonMenu/buttonMenu';
|
||||
@@ -27,10 +27,12 @@ export const CELL_TOOLBAR_SELECTOR: string = 'cell-toolbar-component';
|
||||
export class CellToolbarComponent {
|
||||
@ViewChild('celltoolbar', { read: ElementRef }) private celltoolbar: ElementRef;
|
||||
|
||||
public buttonEdit = localize('buttonEdit', "Edit");
|
||||
public buttonClose = localize('buttonClose', "Close");
|
||||
public buttonAdd = localize('buttonAdd', "Add new cell");
|
||||
public buttonDelete = localize('buttonDelete', "Delete cell");
|
||||
public buttonAdd = localize('buttonAdd', "Add cell");
|
||||
public optionCodeCell = localize('optionCodeCell', "Code cell");
|
||||
public optionTextCell = localize('optionTextCell', "Text cell");
|
||||
public buttonMoveDown = localize('buttonMoveDown', "Move cell down");
|
||||
public buttonMoveUp = localize('buttonMoveUp', "Move cell up");
|
||||
public buttonDelete = localize('buttonDelete', "Delete");
|
||||
|
||||
@Input() cellModel: ICellModel;
|
||||
@Input() model: NotebookModel;
|
||||
@@ -64,17 +66,20 @@ export class CellToolbarComponent {
|
||||
let addTextCellButton = this.instantiationService.createInstance(AddCellAction, 'notebook.AddTextCell', localize('textPreview', "Text cell"), 'notebook-button masked-pseudo markdown');
|
||||
addTextCellButton.cellType = CellTypes.Markdown;
|
||||
|
||||
let deleteButton = this.instantiationService.createInstance(DeleteCellAction, 'delete', 'codicon masked-icon delete', localize('delete', "Delete"));
|
||||
let moveCellDownButton = this.instantiationService.createInstance(MoveCellAction, 'notebook.MoveCellDown', 'masked-icon move-down', this.buttonMoveDown);
|
||||
let moveCellUpButton = this.instantiationService.createInstance(MoveCellAction, 'notebook.MoveCellUp', 'masked-icon move-up', this.buttonMoveUp);
|
||||
|
||||
let deleteButton = this.instantiationService.createInstance(DeleteCellAction, 'notebook.DeleteCell', 'masked-icon delete', this.buttonDelete);
|
||||
|
||||
let moreActionsContainer = DOM.$('li.action-item');
|
||||
this._cellToggleMoreActions = this.instantiationService.createInstance(CellToggleMoreActions);
|
||||
this._cellToggleMoreActions.onInit(moreActionsContainer, context);
|
||||
|
||||
this._editCellAction = this.instantiationService.createInstance(EditCellAction, 'notebook.editCell', true, this.cellModel.isEditMode);
|
||||
this._editCellAction = this.instantiationService.createInstance(EditCellAction, 'notebook.EditCell', true, this.cellModel.isEditMode);
|
||||
this._editCellAction.enabled = true;
|
||||
|
||||
let buttonDropdownContainer = DOM.$('li.action-item');
|
||||
buttonDropdownContainer.setAttribute('role', 'presentation');
|
||||
let addCellDropdownContainer = DOM.$('li.action-item');
|
||||
addCellDropdownContainer.setAttribute('role', 'presentation');
|
||||
let dropdownMenuActionViewItem = new DropdownMenuActionViewItem(
|
||||
addCellsButton,
|
||||
[addCodeCellButton, addTextCellButton],
|
||||
@@ -86,14 +91,17 @@ export class CellToolbarComponent {
|
||||
'',
|
||||
undefined
|
||||
);
|
||||
dropdownMenuActionViewItem.render(buttonDropdownContainer);
|
||||
dropdownMenuActionViewItem.render(addCellDropdownContainer);
|
||||
dropdownMenuActionViewItem.setActionContext(context);
|
||||
|
||||
let taskbarContent: ITaskbarContent[] = [];
|
||||
if (this.cellModel?.cellType === CellTypes.Markdown) {
|
||||
taskbarContent.push({ action: this._editCellAction });
|
||||
}
|
||||
taskbarContent.push({ element: buttonDropdownContainer },
|
||||
taskbarContent.push(
|
||||
{ element: addCellDropdownContainer },
|
||||
{ action: moveCellDownButton },
|
||||
{ action: moveCellUpButton },
|
||||
{ action: deleteButton },
|
||||
{ element: moreActionsContainer });
|
||||
|
||||
|
||||
@@ -319,6 +319,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
this._register(model.contentChanged((change) => this.handleContentChanged(change)));
|
||||
this._register(model.onProviderIdChange((provider) => this.handleProviderIdChanged(provider)));
|
||||
this._register(model.kernelChanged((kernelArgs) => this.handleKernelChanged(kernelArgs)));
|
||||
this._register(model.onCellTypeChanged(() => this.detectChanges()));
|
||||
this._model = this._register(model);
|
||||
await this._model.loadContents(trusted);
|
||||
this.setLoading(false);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as assert from 'assert';
|
||||
import { CellToggleMoreActions, RunCellsAction, removeDuplicatedAndStartingSeparators, AddCellFromContextAction, CollapseCellAction } from 'sql/workbench/contrib/notebook/browser/cellToolbarActions';
|
||||
import { CellToggleMoreActions, RunCellsAction, removeDuplicatedAndStartingSeparators, AddCellFromContextAction, CollapseCellAction, ConvertCellAction } from 'sql/workbench/contrib/notebook/browser/cellToolbarActions';
|
||||
import { NotebookService } from 'sql/workbench/services/notebook/browser/notebookServiceImpl';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
@@ -20,6 +20,16 @@ import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuS
|
||||
import { CellModel } from 'sql/workbench/services/notebook/browser/models/cell';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Separator } from 'vs/base/common/actions';
|
||||
import { INotebookModelOptions } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||
import { NotebookEditorContentManager } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
|
||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { nb } from 'azdata';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { NotebookManagerStub } from 'sql/workbench/contrib/notebook/test/stubs';
|
||||
|
||||
suite('CellToolbarActions', function (): void {
|
||||
suite('removeDuplicatedAndStartingSeparators', function (): void {
|
||||
@@ -115,7 +125,7 @@ suite('CellToolbarActions', function (): void {
|
||||
cellModelMock.setup(x => x.cellType).returns(() => 'code');
|
||||
const action = new CellToggleMoreActions(instantiationService);
|
||||
action.onInit(testContainer, contextMock.object);
|
||||
assert(action['_moreActions']['viewItems'][0]['_action']['_actions'].length === 13, 'Unexpected number of valid elements');
|
||||
assert.equal(action['_moreActions']['viewItems'][0]['_action']['_actions'].length, 15, 'Unexpected number of valid elements');
|
||||
});
|
||||
|
||||
test('CellToggleMoreActions with Markdown CellType', function (): void {
|
||||
@@ -124,7 +134,83 @@ suite('CellToolbarActions', function (): void {
|
||||
const action = new CellToggleMoreActions(instantiationService);
|
||||
action.onInit(testContainer, contextMock.object);
|
||||
// Markdown elements don't show the code-cell related actions such as Run Cell
|
||||
assert(action['_moreActions']['viewItems'][0]['_action']['_actions'].length === 5, 'Unexpected number of valid elements');
|
||||
assert.equal(action['_moreActions']['viewItems'][0]['_action']['_actions'].length, 7, 'Unexpected number of valid elements');
|
||||
});
|
||||
});
|
||||
|
||||
suite('ConvertCellAction', function (): void {
|
||||
let convertCellAction: ConvertCellAction;
|
||||
let notebookModel: NotebookModel;
|
||||
|
||||
suiteSetup(async function (): Promise<void> {
|
||||
convertCellAction = new ConvertCellAction('id', 'label', undefined);
|
||||
notebookModel = await createandLoadNotebookModel();
|
||||
});
|
||||
|
||||
test('No notebook model passed in', async function (): Promise<void> {
|
||||
let cellModel = new CellModel({ cell_type: 'code', source: '' }, { isTrusted: true, notebook: undefined });
|
||||
await convertCellAction.doRun({ cell: cellModel, model: undefined });
|
||||
assert.equal(cellModel.cellType, 'code', 'Cell type should not be affected');
|
||||
});
|
||||
|
||||
test('Convert to code cell', async function (): Promise<void> {
|
||||
await notebookModel.loadContents();
|
||||
await convertCellAction.doRun({ model: notebookModel, cell: notebookModel.cells[0] });
|
||||
assert.equal(notebookModel.cells[0].cellType, 'markdown', 'Cell was not converted correctly');
|
||||
});
|
||||
|
||||
test('Convert to markdown cell', async function (): Promise<void> {
|
||||
await notebookModel.loadContents();
|
||||
notebookModel.cells[0].cellType = 'markdown';
|
||||
await convertCellAction.doRun({ model: notebookModel, cell: notebookModel.cells[0] });
|
||||
assert.equal(notebookModel.cells[0].cellType, 'code', 'Cell was not converted correctly');
|
||||
});
|
||||
|
||||
test('Convert to code cell and back', async function (): Promise<void> {
|
||||
await notebookModel.loadContents();
|
||||
notebookModel.cells[0].cellType = 'markdown';
|
||||
await convertCellAction.doRun({ model: notebookModel, cell: notebookModel.cells[0] });
|
||||
assert.equal(notebookModel.cells[0].cellType, 'code', 'Cell was not converted correctly');
|
||||
await convertCellAction.doRun({ model: notebookModel, cell: notebookModel.cells[0] });
|
||||
assert.equal(notebookModel.cells[0].cellType, 'markdown', 'Cell was not converted correctly second time');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function createandLoadNotebookModel(codeContent?: nb.INotebookContents): Promise<NotebookModel> {
|
||||
let defaultCodeContent: nb.INotebookContents = {
|
||||
cells: [{
|
||||
cell_type: CellTypes.Code,
|
||||
source: [''],
|
||||
metadata: { language: 'python' },
|
||||
execution_count: 1
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python',
|
||||
language: 'python'
|
||||
}
|
||||
},
|
||||
nbformat: 4,
|
||||
nbformat_minor: 5
|
||||
};
|
||||
|
||||
let serviceCollection = new ServiceCollection();
|
||||
let instantiationService = new InstantiationService(serviceCollection, true);
|
||||
let mockContentManager = TypeMoq.Mock.ofType(NotebookEditorContentManager);
|
||||
mockContentManager.setup(c => c.loadContent()).returns(() => Promise.resolve(codeContent ? codeContent : defaultCodeContent));
|
||||
let defaultModelOptions: INotebookModelOptions = {
|
||||
notebookUri: URI.file('/some/path.ipynb'),
|
||||
factory: new ModelFactory(instantiationService),
|
||||
notebookManagers: [new NotebookManagerStub()],
|
||||
contentManager: mockContentManager.object,
|
||||
notificationService: undefined,
|
||||
connectionService: undefined,
|
||||
providerId: 'SQL',
|
||||
cellMagicMapper: undefined,
|
||||
defaultKernel: undefined,
|
||||
layoutChanged: undefined,
|
||||
capabilitiesService: undefined
|
||||
};
|
||||
return new NotebookModel(defaultModelOptions, undefined, undefined, undefined, undefined);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { nb, IConnectionProfile } from 'azdata';
|
||||
import * as vsEvent from 'vs/base/common/event';
|
||||
import { INotebookModel, ICellModel, IClientSession, NotebookContentChange, ISingleNotebookEditOperation } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { INotebookModel, ICellModel, IClientSession, NotebookContentChange, ISingleNotebookEditOperation, MoveDirection } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { INotebookFindModel } from 'sql/workbench/contrib/notebook/browser/models/notebookFindModel';
|
||||
import { NotebookChangeType, CellType } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { INotebookManager, INotebookService, INotebookEditor, ILanguageMagic, INotebookProvider, INavigationProvider, INotebookParams, INotebookSection, ICellEditorProvider, NotebookRange } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
@@ -94,6 +94,9 @@ export class NotebookModelStub implements INotebookModel {
|
||||
addCell(cellType: CellType, index?: number): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
moveCell(cellModel: ICellModel, direction: MoveDirection): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
deleteCell(cellModel: ICellModel): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@@ -118,6 +121,9 @@ export class NotebookModelStub implements INotebookModel {
|
||||
get onActiveCellChanged(): vsEvent.Event<ICellModel> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
get onCellTypeChanged(): vsEvent.Event<ICellModel> {
|
||||
throw new Error('method not implemented.');
|
||||
}
|
||||
updateActiveCell(cell: ICellModel) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -225,6 +225,14 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
return this._cellType;
|
||||
}
|
||||
|
||||
public set cellType(type: CellType) {
|
||||
if (type !== this._cellType) {
|
||||
this._cellType = type;
|
||||
// Regardless, get rid of outputs; this matches Jupyter behavior
|
||||
this._outputs = [];
|
||||
}
|
||||
}
|
||||
|
||||
public get source(): string | string[] {
|
||||
return this._source;
|
||||
}
|
||||
|
||||
@@ -312,6 +312,11 @@ export interface INotebookModel {
|
||||
*/
|
||||
readonly onActiveCellChanged: Event<ICellModel>;
|
||||
|
||||
/**
|
||||
* Event fired on cell type change
|
||||
*/
|
||||
readonly onCellTypeChanged: Event<ICellModel>;
|
||||
|
||||
/**
|
||||
* The trusted mode of the Notebook
|
||||
*/
|
||||
@@ -343,6 +348,12 @@ export interface INotebookModel {
|
||||
*/
|
||||
addCell(cellType: CellType, index?: number): void;
|
||||
|
||||
/**
|
||||
* Moves a cell up/down
|
||||
*/
|
||||
moveCell(cellModel: ICellModel, direction: MoveDirection): void;
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a cell
|
||||
*/
|
||||
@@ -424,6 +435,11 @@ export enum CellExecutionState {
|
||||
Error = 3
|
||||
}
|
||||
|
||||
export enum MoveDirection {
|
||||
Up,
|
||||
Down
|
||||
}
|
||||
|
||||
export interface IOutputChangedEvent {
|
||||
outputs: ReadonlyArray<nb.ICellOutput>;
|
||||
shouldScroll: boolean;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
import { IClientSession, INotebookModel, INotebookModelOptions, ICellModel, NotebookContentChange } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { IClientSession, INotebookModel, INotebookModelOptions, ICellModel, NotebookContentChange, MoveDirection } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookChangeType, CellType, CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
||||
import * as notebookUtils from 'sql/workbench/services/notebook/browser/models/notebookUtils';
|
||||
@@ -59,6 +59,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
private _onProviderIdChanged = new Emitter<string>();
|
||||
private _trustedMode: boolean;
|
||||
private _onActiveCellChanged = new Emitter<ICellModel>();
|
||||
private _onCellTypeChanged = new Emitter<ICellModel>();
|
||||
|
||||
private _cells: ICellModel[];
|
||||
private _defaultLanguageInfo: nb.ILanguageInfo;
|
||||
@@ -271,6 +272,10 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
return this._onActiveCellChanged.event;
|
||||
}
|
||||
|
||||
public get onCellTypeChanged(): Event<ICellModel> {
|
||||
return this._onCellTypeChanged.event;
|
||||
}
|
||||
|
||||
public get standardKernels(): notebookUtils.IStandardKernelWithProvider[] {
|
||||
return this._standardKernels;
|
||||
}
|
||||
@@ -387,6 +392,40 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
return cell;
|
||||
}
|
||||
|
||||
moveCell(cell: ICellModel, direction: MoveDirection): void {
|
||||
if (this.inErrorState) {
|
||||
return null;
|
||||
}
|
||||
let index = this.findCellIndex(cell);
|
||||
|
||||
if ((index === 0 && direction === MoveDirection.Up) || ((index === this._cells.length - 1 && direction === MoveDirection.Down))) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
if (direction === MoveDirection.Down) {
|
||||
this._cells.splice(index, 1);
|
||||
if (index + 1 < this._cells.length) {
|
||||
this._cells.splice(index + 1, 0, cell);
|
||||
} else {
|
||||
this._cells.push(cell);
|
||||
}
|
||||
} else {
|
||||
this._cells.splice(index, 1);
|
||||
this._cells.splice(index - 1, 0, cell);
|
||||
}
|
||||
|
||||
index = this.findCellIndex(cell);
|
||||
|
||||
// Set newly created cell as active cell
|
||||
this.updateActiveCell(cell);
|
||||
this._contentChangedEmitter.fire({
|
||||
changeType: NotebookChangeType.CellsModified,
|
||||
cells: [cell],
|
||||
cellIndex: index
|
||||
});
|
||||
}
|
||||
|
||||
public updateActiveCell(cell: ICellModel): void {
|
||||
if (this._activeCell) {
|
||||
this._activeCell.active = false;
|
||||
@@ -398,6 +437,21 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
this._onActiveCellChanged.fire(cell);
|
||||
}
|
||||
|
||||
public convertCellType(cell: ICellModel): void {
|
||||
if (cell) {
|
||||
let index = this.findCellIndex(cell);
|
||||
if (index > -1) {
|
||||
cell.cellType = cell.cellType === CellTypes.Markdown ? CellTypes.Code : CellTypes.Markdown;
|
||||
this._onCellTypeChanged.fire(cell);
|
||||
this._contentChangedEmitter.fire({
|
||||
changeType: NotebookChangeType.CellsModified,
|
||||
cells: [cell],
|
||||
cellIndex: index
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private createCell(cellType: CellType): ICellModel {
|
||||
let singleCell: nb.ICellContents = {
|
||||
cell_type: cellType,
|
||||
|
||||
Reference in New Issue
Block a user