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

@@ -28,6 +28,7 @@ const msgLoadingContexts = localize('loadingContexts', 'Loading contexts...');
const msgAddNewConnection = localize('addNewConnection', 'Add new connection');
const msgSelectConnection = localize('selectConnection', 'Select connection');
const msgLocalHost = localize('localhost', 'localhost');
const HIDE_ICON_CLASS = ' hideIcon';
// Action to add a cell to notebook based on cell type(code/markdown).
export class AddCellAction extends Action {
@@ -104,6 +105,80 @@ export abstract class ToggleableAction extends Action {
}
}
export interface IActionStateData {
className?: string;
label?: string;
tooltip?: string;
hideIcon?: boolean;
}
export class IMultiStateData<T> {
private _stateMap = new Map<T, IActionStateData>();
constructor(mappings: { key: T, value: IActionStateData}[], private _state: T, private _baseClass?: string) {
if (mappings) {
mappings.forEach(s => this._stateMap.set(s.key, s.value));
}
}
public set state(value: T) {
if (!this._stateMap.has(value)) {
throw new Error('State value must be in stateMap');
}
this._state = value;
}
public updateStateData(state: T, updater: (data: IActionStateData) => void): void {
let data = this._stateMap.get(state);
if (data) {
updater(data);
}
}
public get classes(): string {
let classVal = this.getStateValueOrDefault<string>((data) => data.className, '');
let classes = this._baseClass ? `${this._baseClass} ` : '';
classes += classVal;
if (this.getStateValueOrDefault<boolean>((data) => data.hideIcon, false)) {
classes += HIDE_ICON_CLASS;
}
return classes;
}
public get label(): string {
return this.getStateValueOrDefault<string>((data) => data.label, '');
}
public get tooltip(): string {
return this.getStateValueOrDefault<string>((data) => data.tooltip, '');
}
private getStateValueOrDefault<U>(getter: (data: IActionStateData) => U, defaultVal?: U): U {
let data = this._stateMap.get(this._state);
return data ? getter(data) : defaultVal;
}
}
export abstract class MultiStateAction<T> extends Action {
constructor(id: string, protected states: IMultiStateData<T>) {
super(id, '');
this.updateLabelAndIcon();
}
private updateLabelAndIcon() {
this.label = this.states.label;
this.tooltip = this.states.tooltip;
this.class = this.states.classes;
}
protected updateState(state: T): void {
this.states.state = state;
this.updateLabelAndIcon();
}
}
export class TrustedAction extends ToggleableAction {
// Constants
private static readonly trustedLabel = localize('trustLabel', 'Trusted');