Notebooks: Run all after/before (#6239)

* Run all above/below

* PR comments pre tests

* Added integration test
This commit is contained in:
Chris LaFreniere
2019-07-02 16:49:12 -07:00
committed by GitHub
parent 495c9330f6
commit c4bf1b4180
9 changed files with 134 additions and 31 deletions

View File

@@ -155,8 +155,10 @@ export class ExtHostNotebookEditor implements azdata.nb.NotebookEditor, IDisposa
return this._proxy.$runCell(this._id, uri);
}
public runAllCells(): Thenable<boolean> {
return this._proxy.$runAllCells(this._id);
public runAllCells(startCell?: azdata.nb.NotebookCell, endCell?: azdata.nb.NotebookCell): Thenable<boolean> {
let startCellUri = startCell ? startCell.uri : undefined;
let endCellUri = endCell ? endCell.uri : undefined;
return this._proxy.$runAllCells(this._id, startCellUri, endCellUri);
}
public clearOutput(cell: azdata.nb.NotebookCell): Thenable<boolean> {

View File

@@ -132,11 +132,11 @@ class MainThreadNotebookEditor extends Disposable {
return this.editor.runCell(cell);
}
public runAllCells(): Promise<boolean> {
public runAllCells(startCell?: ICellModel, endCell?: ICellModel): Promise<boolean> {
if (!this.editor) {
return Promise.resolve(false);
}
return this.editor.runAllCells();
return this.editor.runAllCells(startCell, endCell);
}
public clearOutput(cell: ICellModel): Promise<boolean> {
@@ -383,12 +383,22 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
return editor.runCell(cell);
}
$runAllCells(id: string): Promise<boolean> {
$runAllCells(id: string, startCellUri?: UriComponents, endCellUri?: UriComponents): Promise<boolean> {
let editor = this.getEditor(id);
if (!editor) {
return Promise.reject(disposed(`TextEditor(${id})`));
}
return editor.runAllCells();
let startCell: ICellModel;
let endCell: ICellModel;
if (startCellUri) {
let uriString = URI.revive(startCellUri).toString();
startCell = editor.cells.find(c => c.cellUri.toString() === uriString);
}
if (endCellUri) {
let uriString = URI.revive(endCellUri).toString();
endCell = editor.cells.find(c => c.cellUri.toString() === uriString);
}
return editor.runAllCells(startCell, endCell);
}
$clearOutput(id: string, cellUri: UriComponents): Promise<boolean> {

View File

@@ -919,7 +919,7 @@ export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string>;
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleNotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
$runAllCells(id: string): Promise<boolean>;
$runAllCells(id: string, startCellUri?: UriComponents, endCellUri?: UriComponents): Promise<boolean>;
$clearOutput(id: string, cellUri: UriComponents): Promise<boolean>;
$clearAllOutputs(id: string): Promise<boolean>;
$changeKernel(id: string, kernel: azdata.nb.IKernelInfo): Promise<boolean>;

View File

@@ -18,6 +18,7 @@ import { NotebookModel } from 'sql/workbench/parts/notebook/models/notebookModel
import { ToggleMoreWidgetAction } from 'sql/workbench/parts/dashboard/common/actions';
import { CellTypes, CellType } from 'sql/workbench/parts/notebook/models/contracts';
import { CellModel } from 'sql/workbench/parts/notebook/models/cell';
import { INotebookService } from 'sql/workbench/services/notebook/common/notebookService';
export const HIDDEN_CLASS = 'actionhidden';
@@ -33,6 +34,8 @@ export class CellToggleMoreActions {
instantiationService.createInstance(AddCellFromContextAction, 'codeAfter', localize('codeAfter', 'Insert Code After'), CellTypes.Code, true),
instantiationService.createInstance(AddCellFromContextAction, 'markdownBefore', localize('markdownBefore', 'Insert Text Before'), CellTypes.Markdown, false),
instantiationService.createInstance(AddCellFromContextAction, 'markdownAfter', localize('markdownAfter', 'Insert Text After'), CellTypes.Markdown, true),
instantiationService.createInstance(RunCellsAction, 'runAllBefore', localize('runAllBefore', "Run Cells Before"), false),
instantiationService.createInstance(RunCellsAction, 'runAllAfter', localize('runAllAfter', "Run Cells After"), true),
instantiationService.createInstance(ClearCellOutputAction, 'clear', localize('clear', 'Clear Output'))
);
}
@@ -141,3 +144,41 @@ export class ClearCellOutputAction extends CellActionBase {
}
}
export class RunCellsAction extends CellActionBase {
constructor(id: string,
label: string,
private isAfter: boolean,
@INotificationService notificationService: INotificationService,
@INotebookService private notebookService: INotebookService,
) {
super(id, label, undefined, notificationService);
}
public canRun(context: CellContext): boolean {
return context.cell && context.cell.cellType === CellTypes.Code;
}
async doRun(context: CellContext): Promise<void> {
try {
let cell = context.cell || context.model.activeCell;
if (cell) {
let editor = this.notebookService.findNotebookEditor(cell.notebookModel.notebookUri);
if (editor) {
if (this.isAfter) {
await editor.runAllCells(cell, undefined);
} else {
await editor.runAllCells(undefined, cell);
}
}
}
} catch (error) {
let message = getErrorMessage(error);
this.notificationService.notify({
severity: Severity.Error,
message: message
});
}
return Promise.resolve();
}
}

View File

@@ -50,6 +50,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { LabeledMenuItemActionItem, fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { isUndefinedOrNull } from 'vs/base/common/types';
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
@@ -523,11 +524,20 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
}
}
public async runAllCells(): Promise<boolean> {
public async runAllCells(startCell?: ICellModel, endCell?: ICellModel): Promise<boolean> {
await this.modelReady;
let codeCells = this._model.cells.filter(cell => cell.cellType === CellTypes.Code);
if (codeCells && codeCells.length) {
for (let i = 0; i < codeCells.length; i++) {
// For the run all cells scenario where neither startId not endId are provided, set defaults
let startIndex = 0;
let endIndex = codeCells.length;
if (!isUndefinedOrNull(startCell)) {
startIndex = codeCells.findIndex(c => c.id === startCell.id);
}
if (!isUndefinedOrNull(endCell)) {
endIndex = codeCells.findIndex(c => c.id === endCell.id);
}
for (let i = startIndex; i < endIndex; i++) {
let cellStatus = await this.runCell(codeCells[i]);
if (!cellStatus) {
return Promise.reject(new Error(localize('cellRunFailed', "Run Cells failed - See error in output of the currently selected cell for more information.")));

View File

@@ -128,7 +128,7 @@ export interface INotebookEditor {
isVisible(): boolean;
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
runCell(cell: ICellModel): Promise<boolean>;
runAllCells(): Promise<boolean>;
runAllCells(startCell?: ICellModel, endCell?: ICellModel): Promise<boolean>;
clearOutput(cell: ICellModel): Promise<boolean>;
clearAllOutputs(): Promise<boolean>;
}