mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-19 09:35:36 -05:00
Add more actions to cell (#3217)
* Added toggle more actions to cell * Resolve PR comments -- Added INotificationService for notification msg * Reduced ToggleMoreAction to smaller size. So the dropdown could be displayed closer to it instead of at the buttom of the cell.
This commit is contained in:
@@ -9,4 +9,6 @@
|
||||
</div>
|
||||
<div #editor class="editor" style="flex: 1 1 auto; overflow: hidden;">
|
||||
</div>
|
||||
<div #moreactions class="toolbar" style="flex: 0 0 auto; display: flex; flex-flow:column; width: 20px; min-height: 20px; max-height: 20px; padding-top: 10px; orientation: portrait">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
@@ -26,7 +29,11 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { RunCellAction } from 'sql/parts/notebook/cellViews/codeActions';
|
||||
import { RunCellAction, DeleteCellAction, AddCellAction } from 'sql/parts/notebook/cellViews/codeActions';
|
||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||
import { ToggleMoreWidgetAction } from 'sql/parts/dashboard/common/actions';
|
||||
import { CellTypes } from 'sql/parts/notebook/models/contracts';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export const CODE_SELECTOR: string = 'code-component';
|
||||
|
||||
@@ -36,16 +43,24 @@ export const CODE_SELECTOR: string = 'code-component';
|
||||
})
|
||||
export class CodeComponent extends AngularDisposable implements OnInit {
|
||||
@ViewChild('toolbar', { read: ElementRef }) private toolbarElement: ElementRef;
|
||||
@ViewChild('moreactions', { read: ElementRef }) private moreactionsElement: ElementRef;
|
||||
@ViewChild('editor', { read: ElementRef }) private codeElement: ElementRef;
|
||||
@Input() cellModel: ICellModel;
|
||||
|
||||
@Output() public onContentChanged = new EventEmitter<void>();
|
||||
|
||||
@Input() set model(value: NotebookModel) {
|
||||
this._model = value;
|
||||
}
|
||||
|
||||
protected _actionBar: Taskbar;
|
||||
protected _moreActions: ActionBar;
|
||||
private readonly _minimumHeight = 30;
|
||||
private _editor: QueryTextEditor;
|
||||
private _editorInput: UntitledEditorInput;
|
||||
private _editorModel: ITextModel;
|
||||
private _uri: string;
|
||||
private _model: NotebookModel;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||
@@ -55,7 +70,8 @@ export class CodeComponent extends AngularDisposable implements OnInit {
|
||||
@Inject(IModelService) private _modelService: IModelService,
|
||||
@Inject(IModeService) private _modeService: IModeService,
|
||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService
|
||||
@Inject(IContextViewService) private contextViewService: IContextViewService,
|
||||
@Inject(INotificationService) private notificationService: INotificationService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -78,6 +94,10 @@ export class CodeComponent extends AngularDisposable implements OnInit {
|
||||
}));
|
||||
}
|
||||
|
||||
get model(): NotebookModel {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
private createEditor(): void {
|
||||
let instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleProgressService()]));
|
||||
this._editor = instantiationService.createInstance(QueryTextEditor);
|
||||
@@ -119,6 +139,19 @@ export class CodeComponent extends AngularDisposable implements OnInit {
|
||||
this._actionBar.setContent([
|
||||
{ action: runCellAction }
|
||||
]);
|
||||
|
||||
let moreActionsElement = <HTMLElement>this.moreactionsElement.nativeElement;
|
||||
this._moreActions = new ActionBar(moreActionsElement, { orientation: ActionsOrientation.VERTICAL });
|
||||
this._moreActions.context = { target: moreActionsElement };
|
||||
|
||||
let actions: Action[] = [];
|
||||
actions.push(this._instantiationService.createInstance(AddCellAction, 'codeBefore', localize('codeBefore', 'Insert Code before'), CellTypes.Code, false, this.notificationService));
|
||||
actions.push(this._instantiationService.createInstance(AddCellAction, 'codeAfter', localize('codeAfter', 'Insert Code after'), CellTypes.Code, true, this.notificationService));
|
||||
actions.push(this._instantiationService.createInstance(AddCellAction, 'markdownBefore', localize('markdownBefore', 'Insert Markdown before'), CellTypes.Markdown, false, this.notificationService));
|
||||
actions.push(this._instantiationService.createInstance(AddCellAction, 'markdownAfter', localize('markdownAfter', 'Insert Markdown after'), CellTypes.Markdown, true, this.notificationService));
|
||||
actions.push(this._instantiationService.createInstance(DeleteCellAction, 'delete', localize('delete', 'Delete'), CellTypes.Code, false, this.notificationService));
|
||||
|
||||
this._moreActions.push(this._instantiationService.createInstance(ToggleMoreWidgetAction, actions, this.model, this.contextMenuService), { icon: true, label: false });
|
||||
}
|
||||
|
||||
private createUri(): URI {
|
||||
@@ -146,5 +179,9 @@ export class CodeComponent extends AngularDisposable implements OnInit {
|
||||
private updateTheme(theme: IColorTheme): void {
|
||||
let toolbarEl = <HTMLElement>this.toolbarElement.nativeElement;
|
||||
toolbarEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||
|
||||
let moreactionsEl = <HTMLElement>this.moreactionsElement.nativeElement;
|
||||
moreactionsEl.style.borderRightColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ code-component .carbon-taskbar .icon {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
code-component .action-label.icon.toggle-more {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
code-component .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container
|
||||
{
|
||||
padding-left: 10px
|
||||
|
||||
@@ -6,7 +6,14 @@
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { localize } from 'vs/nls';
|
||||
import { CellType } from 'sql/parts/notebook/models/contracts';
|
||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||
import { getErrorMessage } from 'sql/parts/notebook/notebookUtils';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { NOTFOUND } from 'dns';
|
||||
import { NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService';
|
||||
|
||||
let notebookMoreActionMsg = localize('notebook.failed', "Please select active cell and try again");
|
||||
export class RunCellAction extends Action {
|
||||
public static ID = 'jobaction.notebookRunCell';
|
||||
public static LABEL = 'Run cell';
|
||||
@@ -14,7 +21,7 @@ export class RunCellAction extends Action {
|
||||
constructor(
|
||||
) {
|
||||
super(RunCellAction.ID, '', 'toolbarIconRun');
|
||||
this.tooltip = localize('runCell','Run cell');
|
||||
this.tooltip = localize('runCell', 'Run cell');
|
||||
}
|
||||
|
||||
public run(context: any): TPromise<boolean> {
|
||||
@@ -26,4 +33,74 @@ export class RunCellAction extends Action {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class AddCellAction extends Action {
|
||||
constructor(
|
||||
id: string, label: string, private cellType: CellType, private isAfter: boolean, private notificationService: INotificationService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
public run(model: NotebookModel): TPromise<boolean> {
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
try {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
if (model.activeCell === undefined) {
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: notebookMoreActionMsg
|
||||
});
|
||||
}
|
||||
else {
|
||||
let index = model.cells.findIndex((cell) => cell.id === model.activeCell.id);
|
||||
if (index !== undefined && this.isAfter) {
|
||||
index += 1;
|
||||
}
|
||||
model.addCell(this.cellType, index);
|
||||
}
|
||||
} catch (error) {
|
||||
let message = getErrorMessage(error);
|
||||
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class DeleteCellAction extends Action {
|
||||
constructor(
|
||||
id: string, label: string, private cellType: CellType, private isAfter: boolean, private notificationService: INotificationService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
public run(model: NotebookModel): TPromise<boolean> {
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
try {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
if (model.activeCell === undefined) {
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: notebookMoreActionMsg
|
||||
});
|
||||
}
|
||||
else {
|
||||
model.deleteCell(model.activeCell);
|
||||
}
|
||||
} catch (error) {
|
||||
let message = getErrorMessage(error);
|
||||
|
||||
this.notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
-->
|
||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||
<div class="notebook-code" style="flex: 0 0 auto;">
|
||||
<code-component [cellModel]="cellModel"></code-component>
|
||||
<code-component [cellModel]="cellModel" [model]="model"></code-component>
|
||||
</div>
|
||||
<div class="notebook-output" style="flex: 0 0 auto;">
|
||||
<output-area-component *ngIf="cellModel.outputs && cellModel.outputs.length > 0" [cellModel]="cellModel">
|
||||
|
||||
@@ -12,6 +12,7 @@ import { CellView } from 'sql/parts/notebook/cellViews/interfaces';
|
||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import * as themeColors from 'vs/workbench/common/theme';
|
||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||
|
||||
|
||||
export const CODE_SELECTOR: string = 'code-cell-component';
|
||||
@@ -21,7 +22,13 @@ export const CODE_SELECTOR: string = 'code-cell-component';
|
||||
templateUrl: decodeURI(require.toUrl('./codeCell.component.html'))
|
||||
})
|
||||
export class CodeCellComponent extends CellView implements OnInit {
|
||||
private _model: NotebookModel;
|
||||
|
||||
@Input() cellModel: ICellModel;
|
||||
@Input() set model(value: NotebookModel) {
|
||||
this._model = value;
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||
@@ -41,4 +48,9 @@ export class CodeCellComponent extends CellView implements OnInit {
|
||||
|
||||
private updateTheme(theme: IColorTheme): void {
|
||||
}
|
||||
|
||||
get model(): NotebookModel {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -304,9 +304,9 @@ export interface INotebookModel {
|
||||
changeContext(host: string): void;
|
||||
|
||||
/**
|
||||
* Adds a cell to the end of the model
|
||||
* Adds a cell to the index of the model
|
||||
*/
|
||||
addCell(cellType: CellType): void;
|
||||
addCell(cellType: CellType, index?: number): void;
|
||||
|
||||
/**
|
||||
* Deletes a cell
|
||||
|
||||
@@ -79,6 +79,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
private readonly _nbformatMinor: number = nbversion.MINOR_VERSION;
|
||||
private _hadoopConnection: NotebookConnection;
|
||||
private _defaultKernel: nb.IKernelSpec;
|
||||
private _activeCell: ICellModel;
|
||||
|
||||
constructor(private notebookOptions: INotebookModelOptions, startSessionImmediately?: boolean, private connectionProfile?: IConnectionProfile) {
|
||||
super();
|
||||
@@ -207,17 +208,25 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
}
|
||||
}
|
||||
|
||||
public addCell(cellType: CellType): void {
|
||||
if (this.inErrorState || !this._cells) {
|
||||
return;
|
||||
}
|
||||
let cell = this.createCell(cellType);
|
||||
this._cells.push(cell);
|
||||
this._contentChangedEmitter.fire({
|
||||
changeType: NotebookChangeType.CellsAdded,
|
||||
cells: [cell]
|
||||
});
|
||||
}
|
||||
public addCell(cellType: CellType, index?: number): void {
|
||||
if (this.inErrorState || !this._cells) {
|
||||
return;
|
||||
}
|
||||
let cell = this.createCell(cellType);
|
||||
|
||||
if (index !== undefined && index !== null && index >= 0 && index < this._cells.length) {
|
||||
this._cells.splice(index, 0, cell);
|
||||
} else {
|
||||
this._cells.push(cell);
|
||||
index = undefined;
|
||||
}
|
||||
|
||||
this._contentChangedEmitter.fire({
|
||||
changeType: NotebookChangeType.CellsAdded,
|
||||
cells: [cell],
|
||||
cellIndex: index
|
||||
});
|
||||
}
|
||||
|
||||
private createCell(cellType: CellType): ICellModel {
|
||||
let singleCell: nb.ICell = {
|
||||
@@ -229,7 +238,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
return this.notebookOptions.factory.createCell(singleCell, { notebook: this, isTrusted: true });
|
||||
}
|
||||
|
||||
deleteCell(cellModel: CellModel): void {
|
||||
deleteCell(cellModel: ICellModel): void {
|
||||
if (this.inErrorState || !this._cells) {
|
||||
return;
|
||||
}
|
||||
@@ -246,6 +255,14 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
}
|
||||
}
|
||||
|
||||
public get activeCell(): ICellModel {
|
||||
return this._activeCell;
|
||||
}
|
||||
|
||||
public set activeCell(value: ICellModel) {
|
||||
this._activeCell = value;
|
||||
}
|
||||
|
||||
private notifyError(error: string): void {
|
||||
this.onErrorEmitter.fire({ message: error, severity: Severity.Error });
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="scrollable" style="flex: 1 1 auto; position: relative">
|
||||
<loading-spinner [loading]="isLoading"></loading-spinner>
|
||||
<div class="notebook-cell" *ngFor="let cell of cells" (click)="selectCell(cell)" [class.active]="cell.active" (keydown)="onKeyDown($event)">
|
||||
<code-cell-component *ngIf="cell.cellType === 'code'" [cellModel]="cell">
|
||||
<code-cell-component *ngIf="cell.cellType === 'code'" [cellModel]="cell" [model]="model">
|
||||
</code-cell-component>
|
||||
<text-cell-component *ngIf="cell.cellType === 'markdown'" [cellModel]="cell">
|
||||
</text-cell-component>
|
||||
|
||||
@@ -79,6 +79,10 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
this.doLoad();
|
||||
}
|
||||
|
||||
public get model(): NotebookModel {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
public get modelRegistered(): Promise<NotebookModel> {
|
||||
return this._modelRegisteredDeferred.promise;
|
||||
}
|
||||
@@ -99,6 +103,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit {
|
||||
}
|
||||
this._activeCell = cell;
|
||||
this._activeCell.active = true;
|
||||
this._model.activeCell = this._activeCell;
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user