Support execution count in run button and align correctly (#3979)

Fixes #3931 
- Align run button correctly so it's centered in new cell
- Refactor to support multi-state button.
  - Hidden state is set to show execution count
  - Stopped state shows run button
  - Running state shows stop button
  - Error state (will) show error button. This isn't fully handled right now
- Add execution count to model and to SqlKernel, verify serialization, loading, update matches other notebook viewers

**Notes on implementation**:
I think this is a decent solution for a) showing execution count as text, and b) perfectly centering the run button.
 
The below solution shows count correctly up to 999 runs (that’s clicking 999 times in a single session), the icon lines up juuust about right with [ ] but for other numbers it is pretty close but probably not exactly right. I wish I could solve this to work better but trying to change text float to center etc. really isn’t working.
 
**Screenshots**:
![image](https://user-images.githubusercontent.com/10819925/52466366-e8794200-2b36-11e9-9a50-86893e75d5af.png)

With running cell:
![image](https://user-images.githubusercontent.com/10819925/52466378-f333d700-2b36-11e9-9e6c-3cee098790fd.png)
This commit is contained in:
Kevin Cunnane
2019-02-08 11:05:03 -08:00
committed by GitHub
parent 4c5bf3ad2b
commit ddc4b3dd6e
12 changed files with 254 additions and 45 deletions

View File

@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { ICellModelOptions, IModelFactory, FutureInternal } from './modelInterfaces';
import { ICellModelOptions, IModelFactory, FutureInternal, CellExecutionState } from './modelInterfaces';
import * as notebookUtils from '../notebookUtils';
import { CellTypes, CellType, NotebookChangeType } from 'sql/parts/notebook/models/contracts';
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
@@ -30,11 +30,13 @@ export class CellModel implements ICellModel {
private _isEditMode: boolean;
private _onOutputsChanged = new Emitter<ReadonlyArray<nb.ICellOutput>>();
private _onCellModeChanged = new Emitter<boolean>();
private _onExecutionStateChanged = new Emitter<boolean>();
public id: string;
private _onExecutionStateChanged = new Emitter<CellExecutionState>();
private _isTrusted: boolean;
private _active: boolean;
private _hover: boolean;
private _executionCount: number | undefined;
private _cellUri: URI;
public id: string;
constructor(private factory: IModelFactory, cellData?: nb.ICellContents, private _options?: ICellModelOptions) {
this.id = `${modelId++}`;
@@ -97,6 +99,25 @@ export class CellModel implements ICellModel {
public set active(value: boolean) {
this._active = value;
this.fireExecutionStateChanged();
}
public get hover(): boolean {
return this._hover;
}
public set hover(value: boolean) {
this._hover = value;
this.fireExecutionStateChanged();
}
public get executionCount(): number | undefined {
return this._executionCount;
}
public set executionCount(value: number | undefined) {
this._executionCount = value;
this.fireExecutionStateChanged();
}
public get cellUri(): URI {
@@ -134,12 +155,23 @@ export class CellModel implements ICellModel {
this._language = newLanguage;
}
public get onExecutionStateChange(): Event<boolean> {
public get onExecutionStateChange(): Event<CellExecutionState> {
return this._onExecutionStateChanged.event;
}
public get isRunning(): boolean {
return !!(this._future && this._future.inProgress);
private fireExecutionStateChanged(): void {
this._onExecutionStateChanged.fire(this.executionState);
}
public get executionState(): CellExecutionState {
let isRunning = !!(this._future && this._future.inProgress);
if (isRunning) {
return CellExecutionState.Running;
} else if (this.active || this.hover) {
return CellExecutionState.Stopped;
}
// TODO save error state and show the error
return CellExecutionState.Hidden;
}
public async runCell(notificationService?: INotificationService): Promise<boolean> {
@@ -162,7 +194,7 @@ export class CellModel implements ICellModel {
// TODO update source based on editor component contents
let content = this.source;
if (content) {
this._onExecutionStateChanged.fire(true);
this.fireExecutionStateChanged();
let future = await kernel.requestExecute({
code: content,
stop_on_error: true
@@ -170,7 +202,13 @@ export class CellModel implements ICellModel {
this.setFuture(future as FutureInternal);
// 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;
return result && result.content.status === 'ok' ? true : false;
if (result && result.content) {
this.executionCount = result.content.execution_count;
if (result.content.status !== 'ok') {
// TODO track error state
return false;
}
}
}
}
} catch (error) {
@@ -179,9 +217,10 @@ export class CellModel implements ICellModel {
}
let message = notebookUtils.getErrorMessage(error);
this.sendNotification(notificationService, Severity.Error, message);
// TODO track error state for the cell
throw error;
} finally {
this._onExecutionStateChanged.fire(false);
this.fireExecutionStateChanged();
}
return true;
@@ -361,7 +400,7 @@ export class CellModel implements ICellModel {
if (this._cellType === CellTypes.Code) {
cellJson.metadata.language = this._language,
cellJson.outputs = this._outputs;
cellJson.execution_count = 1; // TODO: keep track of actual execution count
cellJson.execution_count = this.executionCount;
}
return cellJson as nb.ICellContents;
}
@@ -371,6 +410,7 @@ export class CellModel implements ICellModel {
return;
}
this._cellType = cell.cell_type;
this.executionCount = cell.execution_count;
this._source = Array.isArray(cell.source) ? cell.source.join('') : cell.source;
this.setLanguageFromContents(cell);
if (cell.outputs) {

View File

@@ -411,6 +411,13 @@ export interface ICellModelOptions {
isTrusted: boolean;
}
export enum CellExecutionState {
Hidden = 0,
Stopped = 1,
Running = 2,
Error = 3
}
export interface ICellModel {
cellUri: URI;
id: string;
@@ -419,12 +426,14 @@ export interface ICellModel {
cellType: CellType;
trustedMode: boolean;
active: boolean;
hover: boolean;
executionCount: number | undefined;
readonly future: FutureInternal;
readonly outputs: ReadonlyArray<nb.ICellOutput>;
readonly onOutputsChanged: Event<ReadonlyArray<nb.ICellOutput>>;
readonly onExecutionStateChange: Event<boolean>;
readonly onExecutionStateChange: Event<CellExecutionState>;
setFuture(future: FutureInternal): void;
readonly isRunning: boolean;
readonly executionState: CellExecutionState;
runCell(notificationService?: INotificationService): Promise<boolean>;
equals(cellModel: ICellModel): boolean;
toJSON(): nb.ICellContents;