mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
* #4586: Clear all outputs feature * text change * Adding extensible method with integration tests * Misc change * Misc change * Adding more logging * Change to test * Adding outputs confition in integration tests
This commit is contained in:
@@ -43,6 +43,40 @@ if (context.RunTest) {
|
|||||||
// console.log('Python3 NB done');
|
// console.log('Python3 NB done');
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
// test('Clear all outputs - Python3 notebook ', async function () {
|
||||||
|
// let notebook = await openNotebook(pySparkNotebookContent, pythonKernelMetadata);
|
||||||
|
// //Check if at least one cell with output
|
||||||
|
// let cellWithOutputs = notebook.document.cells.find(cell => cell.contents && cell.contents.outputs && cell.contents.outputs.length > 0);
|
||||||
|
// console.log("Before clearing cell outputs");
|
||||||
|
// if (cellWithOutputs) {
|
||||||
|
// let clearedOutputs = await notebook.clearAllOutputs();
|
||||||
|
// let cells = notebook.document.cells;
|
||||||
|
// cells.forEach(cell => {
|
||||||
|
// assert(cell.contents && cell.contents.outputs && cell.contents.outputs.length === 0, `Expected Output: 0, Acutal: '${cell.contents.outputs.length}'`);
|
||||||
|
// });
|
||||||
|
// assert(clearedOutputs, 'Outputs of all the code cells from Python notebook should be cleared');
|
||||||
|
// console.log("After clearing cell outputs");
|
||||||
|
// }
|
||||||
|
// assert(cellWithOutputs === undefined, 'Could not find notebook cells with outputs');
|
||||||
|
// });
|
||||||
|
|
||||||
|
test('Clear all outputs - SQL notebook ', async function () {
|
||||||
|
let notebook = await openNotebook(sqlNotebookContent, sqlKernelMetadata);
|
||||||
|
let cellWithOutputs = notebook.document.cells.find(cell => cell.contents && cell.contents.outputs && cell.contents.outputs.length > 0);
|
||||||
|
console.log("Before clearing cell outputs");
|
||||||
|
if (cellWithOutputs) {
|
||||||
|
let clearedOutputs = await notebook.clearAllOutputs();
|
||||||
|
let cells = notebook.document.cells;
|
||||||
|
cells.forEach(cell => {
|
||||||
|
assert(cell.contents && cell.contents.outputs && cell.contents.outputs.length === 0, `Expected Output: 0, Acutal: '${cell.contents.outputs.length}'`);
|
||||||
|
});
|
||||||
|
assert(clearedOutputs, 'Outputs of all the code cells from SQL notebook should be cleared');
|
||||||
|
console.log("After clearing cell outputs");
|
||||||
|
}
|
||||||
|
assert(cellWithOutputs === undefined, 'Could not find notebook cells with outputs');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// test('PySpark3 notebook test', async function () {
|
// test('PySpark3 notebook test', async function () {
|
||||||
// this.timeout(12000);
|
// this.timeout(12000);
|
||||||
// let notebook = await openNotebook(pySparkNotebookContent, pySpark3KernelMetadata);
|
// let notebook = await openNotebook(pySparkNotebookContent, pySpark3KernelMetadata);
|
||||||
|
|||||||
6
src/sql/azdata.proposed.d.ts
vendored
6
src/sql/azdata.proposed.d.ts
vendored
@@ -4024,6 +4024,12 @@ declare module 'azdata' {
|
|||||||
* @return A promise that resolves with a value indicating if the cell was run or not.
|
* @return A promise that resolves with a value indicating if the cell was run or not.
|
||||||
*/
|
*/
|
||||||
runCell(cell?: NotebookCell): Thenable<boolean>;
|
runCell(cell?: NotebookCell): Thenable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the outputs of all code cells in a Notebook
|
||||||
|
* @return A promise that resolves with a value indicating if the outputs are cleared or not.
|
||||||
|
*/
|
||||||
|
clearAllOutputs(): Thenable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotebookCell {
|
export interface NotebookCell {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{clip-path:url(#clip-path-2);}.cls-4{clip-path:url(#clip-path-3);}.cls-5{clip-path:url(#clip-path-4);}.cls-6{clip-path:url(#clip-path-5);}.cls-7{clip-path:url(#clip-path-6);}.cls-8{clip-path:url(#clip-path-7);}.cls-9{clip-path:url(#clip-path-8);}.cls-10{fill:#fff;}</style><clipPath id="clip-path"><rect class="cls-1" x="81.22" y="32.62" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-2"><rect class="cls-1" x="-712.01" y="400.9" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-3"><rect class="cls-1" x="-711.01" y="400.9" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-4"><rect class="cls-1" x="-708.37" y="407.17" width="10.73" height="0.43"/></clipPath><clipPath id="clip-path-5"><rect class="cls-1" x="-708.07" y="405.93" width="10.14" height="0.43"/></clipPath><clipPath id="clip-path-6"><rect class="cls-1" x="-707.66" y="404.69" width="9.31" height="0.43"/></clipPath><clipPath id="clip-path-7"><rect class="cls-1" x="-707.25" y="403.46" width="8.5" height="0.43"/></clipPath><clipPath id="clip-path-8"><rect class="cls-1" x="-706.83" y="402.22" width="7.65" height="0.43"/></clipPath></defs><title>clear_results_inverse</title><path class="cls-10" d="M8.71,13.84H12v1H3.54L.39,11.68a1.29,1.29,0,0,1-.29-.44,1.42,1.42,0,0,1,0-1.05,1.34,1.34,0,0,1,.3-.45L9.75.38,16,6.59Zm-1.42,0,1-1L3.5,8l-2.39,2.4a.4.4,0,0,0,0,.55L4,13.84Zm2.46-12L4.2,7.34,9,12.13l5.54-5.54Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
1
src/sql/parts/notebook/media/light/clear_results.svg
Normal file
1
src/sql/parts/notebook/media/light/clear_results.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{clip-path:url(#clip-path-2);}.cls-4{clip-path:url(#clip-path-3);}.cls-5{clip-path:url(#clip-path-4);}.cls-6{clip-path:url(#clip-path-5);}.cls-7{clip-path:url(#clip-path-6);}.cls-8{clip-path:url(#clip-path-7);}.cls-9{clip-path:url(#clip-path-8);}</style><clipPath id="clip-path"><rect class="cls-1" x="81.22" y="51.49" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-2"><rect class="cls-1" x="-712.01" y="419.77" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-3"><rect class="cls-1" x="-711.01" y="419.77" width="15.81" height="13.48"/></clipPath><clipPath id="clip-path-4"><rect class="cls-1" x="-708.37" y="426.05" width="10.73" height="0.43"/></clipPath><clipPath id="clip-path-5"><rect class="cls-1" x="-708.07" y="424.81" width="10.14" height="0.43"/></clipPath><clipPath id="clip-path-6"><rect class="cls-1" x="-707.66" y="423.57" width="9.31" height="0.43"/></clipPath><clipPath id="clip-path-7"><rect class="cls-1" x="-707.25" y="422.33" width="8.5" height="0.43"/></clipPath><clipPath id="clip-path-8"><rect class="cls-1" x="-706.83" y="421.09" width="7.65" height="0.43"/></clipPath></defs><title>clear_results</title><path d="M8.71,13.84H12v1H3.54L.39,11.68a1.29,1.29,0,0,1-.29-.44,1.42,1.42,0,0,1,0-1.05,1.34,1.34,0,0,1,.3-.45L9.75.38,16,6.59Zm-1.42,0,1-1L3.5,8l-2.39,2.4a.4.4,0,0,0,0,.55L4,13.84Zm2.46-12L4.2,7.34,9,12.13l5.54-5.54Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -33,7 +33,7 @@ import * as notebookUtils from 'sql/parts/notebook/notebookUtils';
|
|||||||
import { Deferred } from 'sql/base/common/promise';
|
import { Deferred } from 'sql/base/common/promise';
|
||||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction } from 'sql/parts/notebook/notebookActions';
|
import { KernelsDropdown, AttachToDropdown, AddCellAction, TrustedAction, ClearAllOutputsAction } from 'sql/parts/notebook/notebookActions';
|
||||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService';
|
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService';
|
||||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||||
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ISingleNotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
@@ -41,6 +41,7 @@ import { IConnectionDialogService } from 'sql/workbench/services/connection/comm
|
|||||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
import { CellMagicMapper } from 'sql/parts/notebook/models/cellMagicMapper';
|
import { CellMagicMapper } from 'sql/parts/notebook/models/cellMagicMapper';
|
||||||
import { IExtensionsViewlet, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
import { IExtensionsViewlet, VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
|
import { CellModel } from 'sql/parts/notebook/models/cell';
|
||||||
|
|
||||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||||
|
|
||||||
@@ -371,6 +372,8 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
let addTextCellButton = new AddCellAction('notebook.AddTextCell', localize('text', 'Text'), 'notebook-button icon-add');
|
let addTextCellButton = new AddCellAction('notebook.AddTextCell', localize('text', 'Text'), 'notebook-button icon-add');
|
||||||
addTextCellButton.cellType = CellTypes.Markdown;
|
addTextCellButton.cellType = CellTypes.Markdown;
|
||||||
|
|
||||||
|
let clearResultsButton = new ClearAllOutputsAction('notebook.ClearAllOutputs', localize('clearResults', 'Clear Results'), 'notebook-button icon-clear-results');
|
||||||
|
|
||||||
this._trustedAction = this.instantiationService.createInstance(TrustedAction, 'notebook.Trusted');
|
this._trustedAction = this.instantiationService.createInstance(TrustedAction, 'notebook.Trusted');
|
||||||
this._trustedAction.enabled = false;
|
this._trustedAction.enabled = false;
|
||||||
|
|
||||||
@@ -382,7 +385,8 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
{ element: attachToContainer },
|
{ element: attachToContainer },
|
||||||
{ action: addCodeCellButton },
|
{ action: addCodeCellButton },
|
||||||
{ action: addTextCellButton },
|
{ action: addTextCellButton },
|
||||||
{ action: this._trustedAction }
|
{ action: this._trustedAction },
|
||||||
|
{ action: clearResultsButton }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -479,4 +483,19 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async clearAllOutputs(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await this.modelReady;
|
||||||
|
this._model.cells.forEach(cell => {
|
||||||
|
if (cell.cellType === CellTypes.Code) {
|
||||||
|
(cell as CellModel).clearOutputs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,15 @@
|
|||||||
background-image: url("./media/dark/nottrusted_inverse.svg");
|
background-image: url("./media/dark/nottrusted_inverse.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notebookEditor .notebook-button.icon-clear-results{
|
||||||
|
background-image: url("./media/light/clear_results.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .notebookEditor .notebook-button.icon-clear-results,
|
||||||
|
.hc-black .notebookEditor .notebook-button.icon-clear-results{
|
||||||
|
background-image: url("./media/dark/clear_results_inverse.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.moreActions .action-label.icon.toggle-more {
|
.moreActions .action-label.icon.toggle-more {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { INotificationService, Severity, INotificationActions } from 'vs/platfor
|
|||||||
|
|
||||||
import { SelectBox, ISelectBoxOptionsWithLabel } from 'sql/base/browser/ui/selectBox/selectBox';
|
import { SelectBox, ISelectBoxOptionsWithLabel } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||||
import { INotebookModel } from 'sql/parts/notebook/models/modelInterfaces';
|
import { INotebookModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||||
import { CellType } from 'sql/parts/notebook/models/contracts';
|
import { CellType, CellTypes } from 'sql/parts/notebook/models/contracts';
|
||||||
import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
import { NotebookComponent } from 'sql/parts/notebook/notebook.component';
|
||||||
import { getErrorMessage, formatServerNameWithDatabaseNameForAttachTo, getServerFromFormattedAttachToName, getDatabaseFromFormattedAttachToName } from 'sql/parts/notebook/notebookUtils';
|
import { getErrorMessage, formatServerNameWithDatabaseNameForAttachTo, getServerFromFormattedAttachToName, getDatabaseFromFormattedAttachToName } from 'sql/parts/notebook/notebookUtils';
|
||||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||||
@@ -21,6 +21,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
|
|||||||
import { noKernel } from 'sql/workbench/services/notebook/common/sessionManager';
|
import { noKernel } from 'sql/workbench/services/notebook/common/sessionManager';
|
||||||
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService';
|
||||||
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
import { NotebookModel } from 'sql/parts/notebook/models/notebookModel';
|
||||||
|
import { CellModel } from 'sql/parts/notebook/models/cell';
|
||||||
|
|
||||||
const msgLoading = localize('loading', "Loading kernels...");
|
const msgLoading = localize('loading', "Loading kernels...");
|
||||||
const msgChanging = localize('changing', "Changing kernel...");
|
const msgChanging = localize('changing', "Changing kernel...");
|
||||||
@@ -53,6 +54,19 @@ export class AddCellAction extends Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Action to clear outputs of all code cells.
|
||||||
|
export class ClearAllOutputsAction extends Action {
|
||||||
|
constructor(
|
||||||
|
id: string, label: string, cssClass: string
|
||||||
|
) {
|
||||||
|
super(id, label, cssClass);
|
||||||
|
}
|
||||||
|
public run(context: NotebookComponent): Promise<boolean> {
|
||||||
|
return context.clearAllOutputs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface IToggleableState {
|
export interface IToggleableState {
|
||||||
baseClass?: string;
|
baseClass?: string;
|
||||||
shouldToggleTooltip?: boolean;
|
shouldToggleTooltip?: boolean;
|
||||||
|
|||||||
@@ -156,6 +156,10 @@ export class ExtHostNotebookEditor implements azdata.nb.NotebookEditor, IDisposa
|
|||||||
return this._proxy.$runCell(this._id, uri);
|
return this._proxy.$runCell(this._id, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearAllOutputs(): Thenable<boolean> {
|
||||||
|
return this._proxy.$clearAllOutputs(this._id);
|
||||||
|
}
|
||||||
|
|
||||||
public edit(callback: (editBuilder: azdata.nb.NotebookEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean> {
|
public edit(callback: (editBuilder: azdata.nb.NotebookEditorEdit) => void, options?: { undoStopBefore: boolean; undoStopAfter: boolean; }): Thenable<boolean> {
|
||||||
if (this._disposed) {
|
if (this._disposed) {
|
||||||
return Promise.reject(new Error('NotebookEditor#edit not possible on closed editors'));
|
return Promise.reject(new Error('NotebookEditor#edit not possible on closed editors'));
|
||||||
|
|||||||
@@ -125,6 +125,13 @@ class MainThreadNotebookEditor extends Disposable {
|
|||||||
|
|
||||||
return this.editor.runCell(cell);
|
return this.editor.runCell(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearAllOutputs(): Promise<boolean> {
|
||||||
|
if (!this.editor) {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
return this.editor.clearAllOutputs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function wait(timeMs: number): Promise<void> {
|
function wait(timeMs: number): Promise<void> {
|
||||||
@@ -359,6 +366,14 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
|||||||
return editor.runCell(cell);
|
return editor.runCell(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$clearAllOutputs(id: string): Promise<boolean> {
|
||||||
|
let editor = this.getEditor(id);
|
||||||
|
if (!editor) {
|
||||||
|
return Promise.reject(disposed(`TextEditor(${id})`));
|
||||||
|
}
|
||||||
|
return editor.clearAllOutputs();
|
||||||
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
private async doOpenEditor(resource: UriComponents, options: INotebookShowOptions): Promise<string> {
|
private async doOpenEditor(resource: UriComponents, options: INotebookShowOptions): Promise<string> {
|
||||||
|
|||||||
@@ -866,6 +866,7 @@ export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable
|
|||||||
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string>;
|
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string>;
|
||||||
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleNotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleNotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
||||||
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
||||||
|
$clearAllOutputs(id: string): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostExtensionManagementShape {
|
export interface ExtHostExtensionManagementShape {
|
||||||
|
|||||||
@@ -109,4 +109,5 @@ export interface INotebookEditor {
|
|||||||
isVisible(): boolean;
|
isVisible(): boolean;
|
||||||
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
|
executeEdits(edits: ISingleNotebookEditOperation[]): boolean;
|
||||||
runCell(cell: ICellModel): Promise<boolean>;
|
runCell(cell: ICellModel): Promise<boolean>;
|
||||||
|
clearAllOutputs(): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user