Compare commits

...

16 Commits

Author SHA1 Message Date
Chris LaFreniere
0f5cfdc2c8 Handle key_up in callout dialog (#15472) (#15485) 2021-05-14 12:04:15 -07:00
Charles Gagnon
1d6427ce89 Fix Issue Reporter (#15467) (#15475)
(cherry picked from commit d797ef433a)
2021-05-13 21:44:28 -07:00
Alan Ren
4356e49793 fix animated svg issue (#15471) (#15473) 2021-05-13 20:13:56 -07:00
Hai Cao
12662f7427 Fix link handling in viewPane (#15458) (#15468) 2021-05-13 15:26:01 -07:00
Aditya Bist
6e1f995286 fix azure context menu (#15447) (#15462)
* fix azure context menu

* fix node issue

* change to undefined

* just use interface

* set connection profile

* add save profile
2021-05-13 14:13:32 -07:00
Aditya Bist
c5508cf46a Fix cloud shell (#15452) (#15461)
* fix cloud shell

* better logic for dimensions

* fix dimension type

* change terminate to close
2021-05-13 14:12:08 -07:00
Udeesha Gautam
3f10d89db3 Doing a point fix for backup since select box has impact on other features (#15415) (#15456) 2021-05-13 12:45:24 -07:00
Barbara Valdez
419c2324c9 Notebooks View: Do not recenter view when selecting a notebook that is visible (#15442) (#15455)
* do not focus element when tree item is visible

* reset reveal behavior

* add comment
2021-05-13 10:46:46 -07:00
Benjin Dubishar
166faccf1e added missing await, removed duplicate okay button checks (#15450) (#15454) 2021-05-13 10:46:15 -07:00
Chris LaFreniere
e5f9790ed1 Notebooks: Fix Table Generation into Pure Markdown When No thead Exists (#15423) (#15448)
* works without alignment

* Alignment working

* Add comment

* Remove outdated comment
2021-05-12 17:57:02 -07:00
Charles Gagnon
e7fbedfe65 Fix dashboard icons (#15400) (#15431)
* Fix dashboard icons

* Split out custom SQL menu items

* Put on same line
2021-05-12 14:08:04 -07:00
Charles Gagnon
e291a25104 Fix event prefix (#15429) (#15433) 2021-05-12 13:50:37 -07:00
Lucy Zhang
4d3787dbc0 skip text cell smoketest (#15411) (#15417) 2021-05-12 10:23:11 -07:00
Aditya Bist
56cc1202d5 update remote yarn lock (#15419) (#15424)
* update yarn lock to use 2.9.4 when ^2.6.0 is used

* update main yarn lock

* update yarn lock for remote/web
2021-05-11 20:07:49 -07:00
Alan Ren
e3b238c017 remove the filters not applicable to ads (#15409) (#15418) 2021-05-11 16:27:21 -07:00
Aasim Khan
ed5bb14b11 Adding all the arm libraries as external dependencies in azurecore webpack (#15398) (#15399) 2021-05-11 13:41:38 -07:00
39 changed files with 366 additions and 290 deletions

View File

@@ -16,6 +16,8 @@ const externals = {
'bufferutil': 'commonjs bufferutil', 'bufferutil': 'commonjs bufferutil',
'utf-8-validate': 'commonjs utf-8-validate', 'utf-8-validate': 'commonjs utf-8-validate',
'keytar': 'commonjs keytar', 'keytar': 'commonjs keytar',
'@azure/arm-subscriptions': 'commonjs @azure/arm-subscriptions',
'@azure/arm-resourcegraph': 'commonjs @azure/arm-resourcegraph'
}; };
// conditionally add ws if we are going to be running in a node environment // conditionally add ws if we are going to be running in a node environment

View File

@@ -181,17 +181,22 @@ export function registerAzureResourceCommands(appContext: AppContext, azureViewT
vscode.commands.executeCommand('workbench.actions.modal.linkedAccount'); vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
}); });
vscode.commands.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode | azdata.ObjectExplorerContext) => {
if (!node) { if (!node) {
return; return;
} }
let connectionProfile: azdata.IConnectionProfile = undefined;
const treeItem: azdata.TreeItem = await node.getTreeItem(); if (node instanceof TreeNode) {
if (!treeItem.payload) { const treeItem: azdata.TreeItem = await node.getTreeItem();
return; if (!treeItem.payload) {
return;
}
// Ensure connection is saved to the Connections list, then open connection dialog
connectionProfile = Object.assign({}, treeItem.payload, { saveProfile: true });
} else if (node.isConnectionNode) {
connectionProfile = Object.assign({}, node.connectionProfile, { saveProfile: true });
} }
// Ensure connection is saved to the Connections list, then open connection dialog
let connectionProfile = Object.assign({}, treeItem.payload, { saveProfile: true });
const conn = await azdata.connection.openConnectionDialog(undefined, connectionProfile, { saveConnection: true, showDashboard: true }); const conn = await azdata.connection.openConnectionDialog(undefined, connectionProfile, { saveConnection: true, showDashboard: true });
if (conn) { if (conn) {
vscode.commands.executeCommand('workbench.view.connections'); vscode.commands.executeCommand('workbench.view.connections');

View File

@@ -103,7 +103,7 @@ export class AzureTerminalService implements IAzureTerminalService {
} }
} }
const shells = [new ShellType('PowerShell', 'pwsh'), new ShellType('Bash', 'bash'),]; const shells = [new ShellType('PowerShell', 'pwsh'), new ShellType('Bash', 'bash')];
const idx = shells.findIndex(s => s.value === preferredShell); const idx = shells.findIndex(s => s.value === preferredShell);
const prefShell = shells.splice(idx, 1); const prefShell = shells.splice(idx, 1);
@@ -157,7 +157,7 @@ class AzureTerminal implements vscode.Pseudoterminal {
} }
async open(initialDimensions: vscode.TerminalDimensions): Promise<void> { async open(initialDimensions: vscode.TerminalDimensions): Promise<void> {
this.setDimensions(initialDimensions); await this.setDimensions(initialDimensions);
} }
close(): void { close(): void {
@@ -167,14 +167,19 @@ class AzureTerminal implements vscode.Pseudoterminal {
this.socket.removeAllListeners('message'); this.socket.removeAllListeners('message');
this.socket.removeAllListeners('close'); this.socket.removeAllListeners('close');
this.socket.terminate(); this.socket.close();
if (this.intervalTimer) { if (this.intervalTimer) {
clearInterval(this.intervalTimer); clearInterval(this.intervalTimer);
} }
} }
private areSameDimensions(oldDimensions: vscode.TerminalDimensions | undefined, newDimensions: vscode.TerminalDimensions): boolean {
return oldDimensions?.columns === newDimensions.columns && oldDimensions?.rows === newDimensions.rows;
}
async setDimensions(dimensions: vscode.TerminalDimensions): Promise<void> { async setDimensions(dimensions: vscode.TerminalDimensions): Promise<void> {
if (!dimensions) { if (!dimensions || this.areSameDimensions(this.terminalDimensions, dimensions)) {
return; return;
} }
this.terminalDimensions = dimensions; this.terminalDimensions = dimensions;

View File

@@ -68,7 +68,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
book && // The notebook is part of a book in the viewlet (otherwise nothing to reveal) book && // The notebook is part of a book in the viewlet (otherwise nothing to reveal)
(this._openAsUntitled ? notebookPath?.scheme === 'untitled' : notebookPath?.scheme !== 'untitled')) // The notebook is of the correct type for this tree view (this._openAsUntitled ? notebookPath?.scheme === 'untitled' : notebookPath?.scheme !== 'untitled')) // The notebook is of the correct type for this tree view
{ {
await this.revealDocumentInTreeView(notebookPath); await this.revealDocumentInTreeView(notebookPath, true, true);
} }
}); });
this._extensionContext.subscriptions.push(azdata.nb.registerNavigationProvider(this)); this._extensionContext.subscriptions.push(azdata.nb.registerNavigationProvider(this));
@@ -391,7 +391,13 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
} }
} }
async revealDocumentInTreeView(uri?: vscode.Uri, shouldReveal: boolean = true): Promise<BookTreeItem | undefined> { /**
* Reveals the given uri in the tree view.
* @param uri The path to the notebook. If it's undefined then the current active notebook is revealed in the Tree View.
* @param shouldReveal A boolean to expand the parent node.
* @param shouldFocus A boolean to focus on the tree item.
*/
async revealDocumentInTreeView(uri: vscode.Uri | undefined, shouldReveal: boolean, shouldFocus: boolean): Promise<BookTreeItem | undefined> {
let bookItem: BookTreeItem; let bookItem: BookTreeItem;
let notebookPath: string; let notebookPath: string;
// If no uri is passed in, try to use the current active notebook editor // If no uri is passed in, try to use the current active notebook editor
@@ -405,17 +411,18 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
} }
if (shouldReveal || this._bookViewer?.visible) { if (shouldReveal || this._bookViewer?.visible) {
bookItem = notebookPath ? await this.findAndExpandParentNode(notebookPath) : undefined; bookItem = notebookPath ? await this.findAndExpandParentNode(notebookPath, shouldFocus) : undefined;
// Select + focus item in viewlet if books viewlet is already open, or if we pass in variable // Select + focus item in viewlet if books viewlet is already open, or if we pass in variable
if (bookItem?.contextValue && bookItem.contextValue !== 'pinnedNotebook') { if (bookItem?.contextValue && bookItem.contextValue !== 'pinnedNotebook') {
// Note: 3 is the maximum number of levels that the vscode APIs let you expand to // Note: 3 is the maximum number of levels that the vscode APIs let you expand to
await this._bookViewer.reveal(bookItem, { select: true, focus: true, expand: true }); await this._bookViewer.reveal(bookItem, { select: true, focus: shouldFocus, expand: true });
} }
} }
return bookItem; return bookItem;
} }
async findAndExpandParentNode(notebookPath: string): Promise<BookTreeItem | undefined> { async findAndExpandParentNode(notebookPath: string, shouldFocus: boolean): Promise<BookTreeItem | undefined> {
notebookPath = notebookPath.replace(/\\/g, '/'); notebookPath = notebookPath.replace(/\\/g, '/');
const parentBook = this.books.find(b => notebookPath.indexOf(b.bookPath) > -1); const parentBook = this.books.find(b => notebookPath.indexOf(b.bookPath) > -1);
if (!parentBook) { if (!parentBook) {
@@ -470,7 +477,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
} }
try { try {
// TO DO: Check why the reveal fails during initial load with 'TreeError [bookTreeView] Tree element not found' // TO DO: Check why the reveal fails during initial load with 'TreeError [bookTreeView] Tree element not found'
await this._bookViewer.reveal(bookItemToExpand, { select: false, focus: true, expand: true }); await this._bookViewer.reveal(bookItemToExpand, { select: false, focus: shouldFocus, expand: true });
} }
catch (e) { catch (e) {
console.error(e); console.error(e);

View File

@@ -150,9 +150,9 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
azdata.nb.onDidChangeActiveNotebookEditor(e => { azdata.nb.onDidChangeActiveNotebookEditor(e => {
if (e.document.uri.scheme === 'untitled') { if (e.document.uri.scheme === 'untitled') {
providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false); providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
} else { } else {
bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false); bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
} }
}); });

View File

@@ -244,7 +244,7 @@ describe('BooksTreeViewTests', function () {
it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => { it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => {
let notebook1Path = path.join(rootFolderPath, 'Book', 'content', 'notebook1.ipynb').replace(/\\/g, '/'); let notebook1Path = path.join(rootFolderPath, 'Book', 'content', 'notebook1.ipynb').replace(/\\/g, '/');
let currentSelection = await bookTreeViewProvider.findAndExpandParentNode(notebook1Path); let currentSelection = await bookTreeViewProvider.findAndExpandParentNode(notebook1Path, true);
should(currentSelection).not.be.undefined(); should(currentSelection).not.be.undefined();
equalBookItems(currentSelection, expectedNotebook1); equalBookItems(currentSelection, expectedNotebook1);
}); });
@@ -329,7 +329,7 @@ describe('BooksTreeViewTests', function () {
it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => { it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => {
let notebook1Path = path.join(rootFolderPath, 'Book', 'content', 'notebook1.ipynb').replace(/\\/g, '/'); let notebook1Path = path.join(rootFolderPath, 'Book', 'content', 'notebook1.ipynb').replace(/\\/g, '/');
let currentSelection = await providedbookTreeViewProvider.findAndExpandParentNode(notebook1Path); let currentSelection = await providedbookTreeViewProvider.findAndExpandParentNode(notebook1Path, true);
should(currentSelection).not.be.undefined(); should(currentSelection).not.be.undefined();
equalBookItems(currentSelection, expectedNotebook1); equalBookItems(currentSelection, expectedNotebook1);
}); });

View File

@@ -221,8 +221,8 @@ export class SchemaCompareDialog {
this.sourceDacpacComponent = this.createFileBrowser(false, this.schemaCompareMainWindow.sourceEndpointInfo); this.sourceDacpacComponent = this.createFileBrowser(false, this.schemaCompareMainWindow.sourceEndpointInfo);
this.targetDacpacComponent = this.createFileBrowser(true, this.schemaCompareMainWindow.targetEndpointInfo); this.targetDacpacComponent = this.createFileBrowser(true, this.schemaCompareMainWindow.targetEndpointInfo);
let sourceRadioButtons = this.createSourceRadiobuttons(); let sourceRadioButtons = this.createSourceRadioButtons();
let targetRadioButtons = this.createTargetRadiobuttons(); let targetRadioButtons = this.createTargetRadioButtons();
let sourceComponents = []; let sourceComponents = [];
let targetComponents = []; let targetComponents = [];
@@ -336,7 +336,7 @@ export class SchemaCompareDialog {
}; };
} }
private createSourceRadiobuttons(): azdata.FormComponent { private createSourceRadioButtons(): azdata.FormComponent {
this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton() this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'source', name: 'source',
@@ -365,8 +365,7 @@ export class SchemaCompareDialog {
this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.removeFormItem(this.sourceDacpacComponent); this.formBuilder.removeFormItem(this.sourceDacpacComponent);
this.populateServerDropdown(false); await this.populateServerDropdown(false);
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
// if source is currently a db, show it in the server and db dropdowns // if source is currently a db, show it in the server and db dropdowns
@@ -389,7 +388,7 @@ export class SchemaCompareDialog {
}; };
} }
private createTargetRadiobuttons(): azdata.FormComponent { private createTargetRadioButtons(): azdata.FormComponent {
let dacpacRadioButton = this.view.modelBuilder.radioButton() let dacpacRadioButton = this.view.modelBuilder.radioButton()
.withProperties({ .withProperties({
name: 'target', name: 'target',
@@ -418,8 +417,7 @@ export class SchemaCompareDialog {
this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize });
this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize }); this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize });
this.populateServerDropdown(true); await this.populateServerDropdown(true);
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
}); });
// if target is currently a db, show it in the server and db dropdowns // if target is currently a db, show it in the server and db dropdowns
@@ -445,7 +443,6 @@ export class SchemaCompareDialog {
} }
private async shouldEnableOkayButton(): Promise<boolean> { private async shouldEnableOkayButton(): Promise<boolean> {
let sourcefilled = (this.sourceIsDacpac && await this.existsDacpac(this.sourceTextBox.value)) let sourcefilled = (this.sourceIsDacpac && await this.existsDacpac(this.sourceTextBox.value))
|| (!this.sourceIsDacpac && !isNullOrUndefined(this.sourceDatabaseDropdown.value) && this.sourceDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.sourceDbEditable)) !== -1); || (!this.sourceIsDacpac && !isNullOrUndefined(this.sourceDatabaseDropdown.value) && this.sourceDatabaseDropdown.values.findIndex(x => this.matchesValue(x, this.sourceDbEditable)) !== -1);
let targetfilled = (this.targetIsDacpac && await this.existsDacpac(this.targetTextBox.value)) let targetfilled = (this.targetIsDacpac && await this.existsDacpac(this.targetTextBox.value))
@@ -720,6 +717,7 @@ export class SchemaCompareDialog {
}); });
} }
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
currentDropdown.loading = false; currentDropdown.loading = false;
} }

View File

@@ -73,15 +73,7 @@ chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5" escape-string-regexp "^1.0.5"
supports-color "^5.3.0" supports-color "^5.3.0"
chart.js@^2.6.0: chart.js@^2.6.0, chart.js@^2.9.4:
version "2.9.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.1.tgz#e98893a810d40d1c0a016e6872a13fa5faedcdf8"
integrity sha512-DA5dFt0Bz79oz56ezmrwmZqj0hXGs+i9VbCFOcHqbwrHIGv7RI4YqninJKNIAC0qa29WBI9qYTN7LzULlOeunA==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chart.js@^2.9.4:
version "2.9.4" version "2.9.4"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==

View File

@@ -140,15 +140,7 @@ chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5" escape-string-regexp "^1.0.5"
supports-color "^5.3.0" supports-color "^5.3.0"
chart.js@^2.6.0: chart.js@^2.6.0, chart.js@^2.9.4:
version "2.9.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.1.tgz#e98893a810d40d1c0a016e6872a13fa5faedcdf8"
integrity sha512-DA5dFt0Bz79oz56ezmrwmZqj0hXGs+i9VbCFOcHqbwrHIGv7RI4YqninJKNIAC0qa29WBI9qYTN7LzULlOeunA==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chart.js@^2.9.4:
version "2.9.4" version "2.9.4"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==

View File

@@ -97,7 +97,7 @@
window['MonacoEnvironment'] = {}; window['MonacoEnvironment'] = {};
const baseUrl = useCustomProtocol ? const baseUrl = useCustomProtocol ?
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'azuredatastudio-file', fallbackAuthority: 'azuredatastudio-app' })}/out` : `${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out` :
`${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32' })}/out`; `${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32' })}/out`;
const loaderConfig = { const loaderConfig = {

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,164 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { asCSSUrl, createCSSRule } from 'vs/base/browser/dom';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICommandAction, MenuItemAction } from 'vs/platform/actions/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
const ids = new IdGenerator('menu-item-action-item-icon-');
const ICON_PATH_TO_CSS_RULES = new Map<string /* path*/, string /* CSS rule */>();
/**
* Always show label for action items, instead of whether they don't have
* an icon/CSS class. Useful for some toolbar scenarios in particular with
* contributed actions from other extensions
*/
export class LabeledMenuItemActionItem extends MenuEntryActionViewItem {
private _labeledItemClassDispose?: IDisposable;
constructor(
public _action: MenuItemAction,
@IKeybindingService labeledkeybindingService: IKeybindingService,
@INotificationService protected _notificationService: INotificationService,
private readonly _defaultCSSClassToAdd: string = ''
) {
super(_action, labeledkeybindingService, _notificationService);
}
updateLabel(): void {
if (this.label) {
this.label.innerText = this._commandAction.label;
}
}
// Overwrite item class to ensure that we can pass in a CSS class that other items use
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
protected _updateItemClass(item: ICommandAction): void {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
if (ThemeIcon.isThemeIcon(item.icon)) {
// TODO
} else if (item.icon) {
let iconClass: string;
if (item.icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.light || item.icon.dark)} !important`);
createCSSRule(`.vs-dark .codicon.${iconClass}, .hc-black .codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.dark)} !important`);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {
const iconClasses = iconClass.split(' ');
if (this._defaultCSSClassToAdd) {
iconClasses.push(this._defaultCSSClassToAdd);
}
this.label.classList.add('codicon', ...iconClasses);
this._labeledItemClassDispose = toDisposable(() => {
if (this.label) {
this.label.classList.remove('codicon', ...iconClasses);
}
});
}
}
}
}
dispose(): void {
if (this._labeledItemClassDispose) {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
}
super.dispose();
}
}
/**
* This is a duplicate of LabeledMenuItemActionItem with the following exceptions:
* - Adds CSS class: `masked-icon` to contributed actions label element.
* - Adds style rule for masked-icon.
*/
export class MaskedLabeledMenuItemActionItem extends MenuEntryActionViewItem {
private _labeledItemClassDispose?: IDisposable;
constructor(
public _action: MenuItemAction,
@IKeybindingService labeledkeybindingService: IKeybindingService,
@INotificationService protected _notificationService: INotificationService,
private readonly _defaultCSSClassToAdd: string = ''
) {
super(_action, labeledkeybindingService, _notificationService);
}
updateLabel(): void {
if (this.label) {
this.label.innerText = this._commandAction.label;
}
}
// Overwrite item class to ensure that we can pass in a CSS class that other items use
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
protected _updateItemClass(item: ICommandAction): void {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
if (ThemeIcon.isThemeIcon(item.icon)) {
// TODO
} else if (item.icon) {
let iconClass: string;
if (item.icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.codicon.masked-icon.${iconClass}::before`, `-webkit-mask-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
createCSSRule(`.codicon.masked-icon.${iconClass}::before`, `mask-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {
const iconClasses = iconClass.split(' ');
if (this._defaultCSSClassToAdd) {
iconClasses.push(this._defaultCSSClassToAdd);
}
this.label.classList.add('codicon', ...iconClasses);
this.label.classList.add('masked-icon', ...iconClasses);
this._labeledItemClassDispose = toDisposable(() => {
if (this.label) {
this.label.classList.remove('codicon', ...iconClasses);
}
});
}
}
}
}
dispose(): void {
if (this._labeledItemClassDispose) {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
}
super.dispose();
}
}

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -440,6 +440,9 @@ export class BackupComponent extends AngularDisposable {
// Set backup type // Set backup type
this.backupTypeSelectBox!.setOptions(this.backupTypeOptions, 0); this.backupTypeSelectBox!.setOptions(this.backupTypeOptions, 0);
// The above call does not set the private variable for selectedOption variable in select box
// Doing a point fix for backup since select box changes have wider unwanted impact
this.backupTypeSelectBox!.select(0);
this.setDefaultBackupName(); this.setDefaultBackupName();
this.backupNameBox!.focus(); this.backupNameBox!.focus();

View File

@@ -43,7 +43,7 @@ import * as DOM from 'vs/base/browser/dom';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import { TaskRegistry } from 'sql/workbench/services/tasks/browser/tasksRegistry'; import { TaskRegistry } from 'sql/workbench/services/tasks/browser/tasksRegistry';
import { MenuRegistry, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { MenuRegistry, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { fillInActions, LabeledMenuItemActionItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { NAV_SECTION } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardNavSection.contribution'; import { NAV_SECTION } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardNavSection.contribution';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
@@ -51,6 +51,7 @@ import { DASHBOARD_BORDER, EDITOR_PANE_BACKGROUND, TOOLBAR_OVERFLOW_SHADOW } fro
import { IColorTheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { IColorTheme, registerThemingParticipant, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { attachTabbedPanelStyler } from 'sql/workbench/common/styler'; import { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
import { focusBorder } from 'vs/platform/theme/common/colorRegistry'; import { focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { LabeledMenuItemActionItem } from 'sql/platform/actions/browser/menuEntryActionViewItem';
const dashboardRegistry = Registry.as<IDashboardRegistry>(DashboardExtensions.DashboardContributions); const dashboardRegistry = Registry.as<IDashboardRegistry>(DashboardExtensions.DashboardContributions);
const homeTabGroupId = 'home'; const homeTabGroupId = 'home';

View File

@@ -22,6 +22,7 @@ import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
import { attachCalloutDialogStyler } from 'sql/workbench/common/styler'; import { attachCalloutDialogStyler } from 'sql/workbench/common/styler';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { escapeLabel, escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils'; import { escapeLabel, escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils';
import { KeyCode } from 'vs/base/common/keyCodes';
export interface ILinkCalloutDialogOptions { export interface ILinkCalloutDialogOptions {
insertTitle?: string, insertTitle?: string,
@@ -100,6 +101,13 @@ export class LinkCalloutDialog extends Modal {
} }
protected renderBody(container: HTMLElement) { protected renderBody(container: HTMLElement) {
this._register(DOM.addDisposableListener(document, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Enter)) {
DOM.EventHelper.stop(e, true);
this.hide('ok');
}
}));
let linkContentColumn = DOM.$('.column.insert-link'); let linkContentColumn = DOM.$('.column.insert-link');
DOM.append(container, linkContentColumn); DOM.append(container, linkContentColumn);
@@ -147,7 +155,8 @@ export class LinkCalloutDialog extends Modal {
protected onAccept(e?: StandardKeyboardEvent) { protected onAccept(e?: StandardKeyboardEvent) {
// EventHelper.stop() will call preventDefault. Without it, text cell will insert an extra newline when pressing enter on dialog // EventHelper.stop() will call preventDefault. Without it, text cell will insert an extra newline when pressing enter on dialog
DOM.EventHelper.stop(e, true); DOM.EventHelper.stop(e, true);
this.insert(); const keyboardEventExists = !!e;
this.insert(keyboardEventExists);
} }
protected onClose(e?: StandardKeyboardEvent) { protected onClose(e?: StandardKeyboardEvent) {
@@ -155,8 +164,10 @@ export class LinkCalloutDialog extends Modal {
this.cancel(); this.cancel();
} }
public insert(): void { public insert(willHideByKeyboardEvent = false): void {
this.hide('ok'); if (!willHideByKeyboardEvent) {
this.hide('ok');
}
let escapedLabel = escapeLabel(this._linkTextInputBox.value); let escapedLabel = escapeLabel(this._linkTextInputBox.value);
let escapedUrl = escapeUrl(this._linkUrlInputBox.value); let escapedUrl = escapeUrl(this._linkUrlInputBox.value);

View File

@@ -266,6 +266,15 @@ export class HTMLMarkdownConverter {
return delimiter + leadingSpace + content + trailingSpace + delimiter; return delimiter + leadingSpace + content + trailingSpace + delimiter;
} }
}); });
this.turndownService.addRule('p', {
filter: 'p',
replacement: function (content, node) {
// If inside of a table cell, extra newlines would break table rendering
return isInsideTable(node) ? content : '\n\n' + content + '\n\n';
}
});
this.turndownService.escape = escapeMarkdown; this.turndownService.escape = escapeMarkdown;
} }
} }
@@ -281,10 +290,16 @@ function blankReplacement(content, node) {
// When outdenting a nested list, an empty list will still remain. Need to handle this case. // When outdenting a nested list, an empty list will still remain. Need to handle this case.
if (node.nodeName === 'UL' || node.nodeName === 'OL') { if (node.nodeName === 'UL' || node.nodeName === 'OL') {
return '\n'; return '\n';
} else if (isInsideTable(node)) {
return ' ';
} }
return node.isBlock ? '\n\n' : ''; return node.isBlock ? '\n\n' : '';
} }
function isInsideTable(node): boolean {
return node.parentNode?.nodeName === 'TH' || node.parentNode?.nodeName === 'TD';
}
export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string { export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string {
if (notebookFolder) { if (notebookFolder) {
if (contentPath?.scheme === 'file') { if (contentPath?.scheme === 'file') {

View File

@@ -41,7 +41,7 @@ import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
import { toErrorMessage } from 'vs/base/common/errorMessage'; import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { MaskedLabeledMenuItemActionItem, fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { Button } from 'sql/base/browser/ui/button/button'; import { Button } from 'sql/base/browser/ui/button/button';
import { isUndefinedOrNull } from 'vs/base/common/types'; import { isUndefinedOrNull } from 'vs/base/common/types';
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams'; import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
@@ -52,6 +52,7 @@ import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/not
import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { IColorTheme } from 'vs/platform/theme/common/themeService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CellToolbarComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/cellToolbar.component'; import { CellToolbarComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/cellToolbar.component';
import { MaskedLabeledMenuItemActionItem } from 'sql/platform/actions/browser/menuEntryActionViewItem';
export const NOTEBOOK_SELECTOR: string = 'notebook-component'; export const NOTEBOOK_SELECTOR: string = 'notebook-component';

View File

@@ -68,36 +68,23 @@ rules['tableCell'] = {
rules['tableRow'] = { rules['tableRow'] = {
filter: 'tr', filter: 'tr',
replacement: function (content, node) { replacement: function (content, node) {
let borderCells = ''; const borderCells = isHeadingRow(node) ? constructBorderCells(node) : '';
let alignMap = { left: ':--', right: '--:', center: ':-:' };
if (isHeadingRow(node)) {
for (let i = 0; i < node.childNodes.length; i++) {
let border = '---';
let align = (
node.childNodes[i].getAttribute('align') || ''
).toLowerCase();
if (align) {
border = alignMap[align] || border;
}
borderCells += cell(border, node.childNodes[i]);
}
}
return '\n' + content + (borderCells ? '\n' + borderCells : ''); return '\n' + content + (borderCells ? '\n' + borderCells : '');
} }
}; };
rules['table'] = { rules['table'] = {
// Only convert tables with a heading row.
// Tables with no heading row are kept using `keep` (see below).
filter: function (node) { filter: function (node) {
return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0]); return node.nodeName === 'TABLE';
}, },
replacement: function (content, node) { replacement: function (content, node) {
// Ensure there are no blank lines // Ensure there are no blank lines
content = content.replace('\n\n', '\n'); content = content.replace('\n\n', '\n');
// if the headings are empty, add border line and headings to keep table format
if (!isHeadingRow(node.rows[0])) {
let emptyHeader = '\n\n|' + ' |'.repeat(node.rows[0].childNodes.length) + '\n';
return emptyHeader + constructBorderCells(node.rows[0]) + content + '\n\n';
}
return '\n\n' + content + '\n\n'; return '\n\n' + content + '\n\n';
} }
}; };
@@ -148,10 +135,25 @@ function cell(content, node) {
return prefix + content + ' |'; return prefix + content + ' |';
} }
function constructBorderCells(node): string {
const alignMap = { left: ':--', right: '--:', center: ':-:' };
let borderCells = '';
for (let i = 0; i < node.childNodes.length; i++) {
let border = '---';
let align = (
node.childNodes[i].getAttribute('align') || ''
).toLowerCase();
if (align) {
border = alignMap[align] || border;
}
borderCells += cell(border, node.childNodes[i]);
}
return borderCells;
}
export function tables(turndownService) { export function tables(turndownService) {
turndownService.keep(function (node) {
return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0]);
});
for (let key in rules) { for (let key in rules) {
turndownService.addRule(key, rules[key]); turndownService.addRule(key, rules[key]);
} }

View File

@@ -228,6 +228,38 @@ suite('HTML Markdown Converter', function (): void {
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no thead failed'); assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with no thead failed');
}); });
test('Should transform table with only tbody - typical Office scenario', () => {
htmlString = '<table><tbody><tr>\n<td>test1</td>\n<td>test2</td>\n<td>test3</td>\n</tr></tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |`, 'One row test with only tbody failed');
htmlString = '<table><tbody><tr>\n<td>test1</td>\n</tr></tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| |\n| --- |\n| test1 |`, 'One row one cell test with only tbody failed');
htmlString = '<table><tbody><tr>\n<td>test1</td>\n<td>test2</td>\n<td>test3</td>\n</tr>\n<tr>\n<td>test4</td>\n<td>test5</td>\n<td>test6</td>\n</tr>\n<tr>\n<td>test7</td>\n<td>test8</td>\n<td>test9</td>\n</tr>\n<tr>\n<td>test10</td>\n<td>test11</td>\n<td>test12</td>\n</tr>\n</tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| | | |\n| --- | --- | --- |\n| test1 | test2 | test3 |\n| test4 | test5 | test6 |\n| test7 | test8 | test9 |\n| test10 | test11 | test12 |`, 'Table with no thead failed');
});
test('Should transform table with paragraph cell correctly', () => {
htmlString = '<table><thead><tr><th>Test</th><th>Test2</th></tr></thead><tbody><tr><td><p>testP</p></td><td>test</td></tr></tbody></table>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed');
htmlString = '<table><thead><tr><th><p>Test</p></th><th><p>Test2</p></th></tr></thead><tbody><tr><td><p>testP</p></td><td><p>test</p></td></tr></tbody></table>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with every element with nested paragraph failed');
});
test('Should keep highlight and link tags in tables', () => {
htmlString = '<table><thead><tr><th><mark>Test</mark></th><th>Test2</th></tr></thead><tbody><tr><td><p>testP</p></td><td>test</td></tr></tbody></table>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| <mark>Test</mark> | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with simple nested paragraph failed');
htmlString = '<table><thead><tr><th><p><a href="https://www.microsoft.com/">Test</a></p></th><th><p>Test2</p></th></tr></thead><tbody><tr><td><p>testP</p></td><td><p>test</p></td></tr></tbody></table>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| [Test](https://www.microsoft.com/) | Test2 |\n| --- | --- |\n| testP | test |`, 'Table with link in cell failed');
});
test('Should transform table with column alignment', () => {
htmlString = '<table>\n<thead>\n<tr>\n<th align=right>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| --: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with right align column header failed');
htmlString = '<table>\n<thead>\n<tr>\n<th align=left>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-- | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with left align column header failed');
htmlString = '<table>\n<thead>\n<tr>\n<th align=center>Test</th>\n<th>Test</th>\n<th>Test</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n<tr>\n<td>test</td>\n<td>test</td>\n<td>test</td>\n</tr>\n</tbody></table>\n';
assert.equal(htmlMarkdownConverter.convert(htmlString), `| Test | Test | Test |\n| :-: | --- | --- |\n| test | test | test |\n| test | test | test |\n| test | test | test |\n| test | test | test |`, 'Table with center align column header failed');
});
test('Should transform <b> and <strong> tags', () => { test('Should transform <b> and <strong> tags', () => {
htmlString = '<b>test string</b>'; htmlString = '<b>test string</b>';
assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic bold test failed'); assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic bold test failed');

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:grey;"> <g style="fill:grey;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g style="fill:white;"> <g style="fill:white;">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,8 +14,8 @@
circle:nth-child(8) { animation-delay: 0.525s; } circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball { @keyframes ball {
from { opacity: 1; } 0% { opacity: 1; }
to { opacity: 0.3; } 100% { opacity: 0.3; }
} }
</style> </style>
<g> <g>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -207,7 +207,7 @@ class SharedProcessMain extends Disposable {
// Application Insights // Application Insights
if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) { if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) {
const appInsightsAppender = new AppInsightsAppender('monacoworkbench', null, product.aiConfig.asimovKey); const appInsightsAppender = new AppInsightsAppender('adsworkbench', null, product.aiConfig.asimovKey); // {{SQL CARBON EDIT}} Use our own event prefix
this._register(toDisposable(() => appInsightsAppender.flush())); // Ensure the AI appender is disposed so that it flushes remaining data this._register(toDisposable(() => appInsightsAppender.flush())); // Ensure the AI appender is disposed so that it flushes remaining data
telemetryAppender = combinedAppender(appInsightsAppender, telemetryAppender); telemetryAppender = combinedAppender(appInsightsAppender, telemetryAppender);
} }

View File

@@ -151,7 +151,7 @@ class CliMain extends Disposable {
const appenders: AppInsightsAppender[] = []; const appenders: AppInsightsAppender[] = [];
if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) { if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) {
if (product.aiConfig && product.aiConfig.asimovKey) { if (product.aiConfig && product.aiConfig.asimovKey) {
appenders.push(new AppInsightsAppender('monacoworkbench', null, product.aiConfig.asimovKey)); appenders.push(new AppInsightsAppender('adsworkbench', null, product.aiConfig.asimovKey)); // {{SQL CARBON EDIT}} Use our own event prefix
} }
const config: ITelemetryServiceConfig = { const config: ITelemetryServiceConfig = {

View File

@@ -4,11 +4,10 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./menuEntryActionViewItem'; import 'vs/css!./menuEntryActionViewItem';
import { asCSSUrl, createCSSRule, ModifierKeyEmitter } from 'vs/base/browser/dom'; import { asCSSUrl, ModifierKeyEmitter } from 'vs/base/browser/dom';
import { domEvent } from 'vs/base/browser/event'; import { domEvent } from 'vs/base/browser/event';
import { IAction, Separator } from 'vs/base/common/actions'; import { IAction, Separator } from 'vs/base/common/actions';
import { IdGenerator } from 'vs/base/common/idGenerator'; // {{SQL CARBON EDIT}} import { IDisposable, toDisposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IDisposable, toDisposable, MutableDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; // {{SQL CARBON EDIT}}
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction, Icon } from 'vs/platform/actions/common/actions'; import { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction, Icon } from 'vs/platform/actions/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -45,8 +44,7 @@ function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemActio
return disposables; return disposables;
} }
// {{SQL CARBON EDIT}} add export modifier export function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation', primaryMaxCount: number = Number.MAX_SAFE_INTEGER): void { // {{SQL CARBON EDIT}} add export modifier
export function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemAction | SubmenuItemAction>]>, target: IAction[] | { primary: IAction[]; secondary: IAction[]; }, useAlternativeActions: boolean, isPrimaryGroup: (group: string) => boolean = group => group === 'navigation', primaryMaxCount: number = Number.MAX_SAFE_INTEGER): void {
let primaryBucket: IAction[]; let primaryBucket: IAction[];
let secondaryBucket: IAction[]; let secondaryBucket: IAction[];
@@ -80,10 +78,6 @@ export function fillInActions(groups: ReadonlyArray<[string, ReadonlyArray<MenuI
} }
} }
const ids = new IdGenerator('menu-item-action-item-icon-'); // {{SQL CARBON EDIT}} - add back since custom toolbar menu is using below
const ICON_PATH_TO_CSS_RULES = new Map<string /* path*/, string /* CSS rule */>(); // {{SQL CARBON EDIT}} - add back since custom toolbar menu is using below
export class MenuEntryActionViewItem extends ActionViewItem { export class MenuEntryActionViewItem extends ActionViewItem {
private _wantsAltCommand: boolean = false; private _wantsAltCommand: boolean = false;
@@ -262,150 +256,3 @@ export function createActionViewItem(instaService: IInstantiationService, action
return undefined; return undefined;
} }
} }
// {{SQL CARBON EDIT}} - This is here to use the 'ids' generator above
// Always show label for action items, instead of whether they don't have
// an icon/CSS class. Useful for some toolbar scenarios in particular with
// contributed actions from other extensions
export class LabeledMenuItemActionItem extends MenuEntryActionViewItem {
private _labeledItemClassDispose?: IDisposable;
constructor(
public _action: MenuItemAction,
@IKeybindingService labeledkeybindingService: IKeybindingService,
@INotificationService protected _notificationService: INotificationService,
private readonly _defaultCSSClassToAdd: string = ''
) {
super(_action, labeledkeybindingService, _notificationService);
}
updateLabel(): void {
if (this.label) {
this.label.innerText = this._commandAction.label;
}
}
// Overwrite item class to ensure that we can pass in a CSS class that other items use
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
protected _updateItemClass(item: ICommandAction): void {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
if (ThemeIcon.isThemeIcon(item.icon)) {
// TODO
} else if (item.icon) {
let iconClass: string;
if (item.icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
createCSSRule(`.vs-dark .codicon.${iconClass}, .hc-black .codicon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.dark)}`);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {
const iconClasses = iconClass.split(' ');
if (this._defaultCSSClassToAdd) {
iconClasses.push(this._defaultCSSClassToAdd);
}
this.label.classList.add('codicon', ...iconClasses);
this._labeledItemClassDispose = toDisposable(() => {
if (this.label) {
this.label.classList.remove('codicon', ...iconClasses);
}
});
}
}
}
}
dispose(): void {
if (this._labeledItemClassDispose) {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
}
super.dispose();
}
}
/**
* This is a duplicate of LabeledMenuItemActionItem with the following exceptions:
* - Adds CSS class: `masked-icon` to contributed actions label element.
* - Adds style rule for masked-icon.
*/
export class MaskedLabeledMenuItemActionItem extends MenuEntryActionViewItem {
private _labeledItemClassDispose?: IDisposable;
constructor(
public _action: MenuItemAction,
@IKeybindingService labeledkeybindingService: IKeybindingService,
@INotificationService protected _notificationService: INotificationService,
private readonly _defaultCSSClassToAdd: string = ''
) {
super(_action, labeledkeybindingService, _notificationService);
}
updateLabel(): void {
if (this.label) {
this.label.innerText = this._commandAction.label;
}
}
// Overwrite item class to ensure that we can pass in a CSS class that other items use
// Leverages the _defaultCSSClassToAdd property that's passed into the constructor
protected _updateItemClass(item: ICommandAction): void {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
if (ThemeIcon.isThemeIcon(item.icon)) {
// TODO
} else if (item.icon) {
let iconClass: string;
if (item.icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
if (ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.codicon.masked-icon.${iconClass}::before`, `-webkit-mask-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
createCSSRule(`.codicon.masked-icon.${iconClass}::before`, `mask-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
if (this.label) {
const iconClasses = iconClass.split(' ');
if (this._defaultCSSClassToAdd) {
iconClasses.push(this._defaultCSSClassToAdd);
}
this.label.classList.add('codicon', ...iconClasses);
this.label.classList.add('masked-icon', ...iconClasses);
this._labeledItemClassDispose = toDisposable(() => {
if (this.label) {
this.label.classList.remove('codicon', ...iconClasses);
}
});
}
}
}
}
dispose(): void {
if (this._labeledItemClassDispose) {
dispose(this._labeledItemClassDispose);
this._labeledItemClassDispose = undefined;
}
super.dispose();
}
}
// {{SQL CARBON EDIT}} - End

View File

@@ -155,24 +155,25 @@ export interface IExtensionIdentifier {
uuid?: string; uuid?: string;
} }
// {{SQL CARBON EDIT}} - ADS only implemented language pack filtering
export const EXTENSION_CATEGORIES = [ export const EXTENSION_CATEGORIES = [
'Azure', // 'Azure',
'Data Science', // 'Data Science',
'Debuggers', // 'Debuggers',
'Extension Packs', // 'Extension Packs',
'Formatters', // 'Formatters',
'Keymaps', // 'Keymaps',
'Language Packs', 'Language Packs',
'Linters', // 'Linters',
'Machine Learning', // 'Machine Learning',
'Notebooks', // 'Notebooks',
'Programming Languages', // 'Programming Languages',
'SCM Providers', // 'SCM Providers',
'Snippets', // 'Snippets',
'Testing', // 'Testing',
'Themes', // 'Themes',
'Visualization', // 'Visualization',
'Other', // 'Other',
]; ];
export interface IExtensionManifest { export interface IExtensionManifest {

View File

@@ -576,7 +576,7 @@ export abstract class ViewPane extends Pane implements IView {
button.label = node.label; button.label = node.label;
button.onDidClick(_ => { button.onDidClick(_ => {
this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href }); this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });
this.openerService.open(node.href); this.openerService.open(node.href, { allowCommands: true });
}, null, disposables); }, null, disposables);
disposables.add(button); disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService)); disposables.add(attachButtonStyler(button, this.themeService));

View File

@@ -14,7 +14,7 @@ import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsServi
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, ExtensionsSortByContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { VIEWLET_ID, IExtensionsWorkbenchService, IExtensionsViewPaneContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, INSTALL_EXTENSION_FROM_VSIX_COMMAND_ID, DefaultViewsContext, WORKSPACE_RECOMMENDATIONS_VIEW_ID, IWorkspaceRecommendedExtensionsView, AutoUpdateConfigurationKey, HasOutdatedExtensionsContext, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; //{{SQL CARBON EDIT}}
import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { ReinstallAction, InstallSpecificVersionOfExtensionAction, ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, PromptExtensionInstallFailureAction, SearchExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor'; import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
@@ -67,7 +67,7 @@ import { isArray } from 'vs/base/common/types';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { mnemonicButtonLabel } from 'vs/base/common/labels'; import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery'; // import { Query } from 'vs/workbench/contrib/extensions/common/extensionQuery'; {{SQL CARBON EDIT}}
import { Promises } from 'vs/base/common/async'; import { Promises } from 'vs/base/common/async';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
@@ -762,6 +762,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
icon: filterIcon, icon: filterIcon,
}); });
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
const showFeaturedExtensionsId = 'extensions.filter.featured'; const showFeaturedExtensionsId = 'extensions.filter.featured';
this.registerExtensionAction({ this.registerExtensionAction({
id: showFeaturedExtensionsId, id: showFeaturedExtensionsId,
@@ -800,6 +801,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
}, },
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@popular ')) run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@popular '))
}); });
*/
this.registerExtensionAction({ this.registerExtensionAction({
id: 'workbench.extensions.action.showRecommendedExtensions', id: 'workbench.extensions.action.showRecommendedExtensions',
@@ -820,6 +822,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended ')) run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended '))
}); });
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
this.registerExtensionAction({ this.registerExtensionAction({
id: 'workbench.extensions.action.recentlyPublishedExtensions', id: 'workbench.extensions.action.recentlyPublishedExtensions',
title: { value: localize('recentlyPublishedExtensions', "Show Recently Published Extensions"), original: 'Show Recently Published Extensions' }, title: { value: localize('recentlyPublishedExtensions', "Show Recently Published Extensions"), original: 'Show Recently Published Extensions' },
@@ -838,6 +841,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
}, },
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@sort:publishedDate ')) run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@sort:publishedDate '))
}); });
*/
const extensionsCategoryFilterSubMenu = new MenuId('extensionsCategoryFilterSubMenu'); const extensionsCategoryFilterSubMenu = new MenuId('extensionsCategoryFilterSubMenu');
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{ MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
@@ -952,6 +956,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@outdated ')) run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@outdated '))
}); });
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
const extensionsSortSubMenu = new MenuId('extensionsSortSubMenu'); const extensionsSortSubMenu = new MenuId('extensionsSortSubMenu');
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{ MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
submenu: extensionsSortSubMenu, submenu: extensionsSortSubMenu,
@@ -986,6 +991,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
} }
}); });
}); });
*/
this.registerExtensionAction({ this.registerExtensionAction({
id: 'workbench.extensions.action.clearExtensionsSearchResults', id: 'workbench.extensions.action.clearExtensionsSearchResults',

View File

@@ -60,7 +60,7 @@ export function setup() {
await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor'); await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor');
}); });
it('can perform basic text cell functionality', async function () { it.skip('can perform basic text cell functionality', async function () {
const app = this.app as Application; const app = this.app as Application;
await app.workbench.sqlNotebook.newUntitledNotebook(); await app.workbench.sqlNotebook.newUntitledNotebook();
await app.workbench.sqlNotebook.addCellFromPlaceholder('Markdown'); await app.workbench.sqlNotebook.addCellFromPlaceholder('Markdown');

View File

@@ -1946,15 +1946,7 @@ charenc@~0.0.1:
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
chart.js@^2.6.0: chart.js@^2.6.0, chart.js@^2.9.4:
version "2.7.2"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.7.2.tgz#3c9fde4dc5b95608211bdefeda7e5d33dffa5714"
integrity sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"
chart.js@^2.9.4:
version "2.9.4" version "2.9.4"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A== integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==