Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f5cfdc2c8 | ||
|
|
1d6427ce89 | ||
|
|
4356e49793 | ||
|
|
12662f7427 | ||
|
|
6e1f995286 | ||
|
|
c5508cf46a | ||
|
|
3f10d89db3 | ||
|
|
419c2324c9 | ||
|
|
166faccf1e | ||
|
|
e5f9790ed1 | ||
|
|
e7fbedfe65 | ||
|
|
e291a25104 | ||
|
|
4d3787dbc0 | ||
|
|
56cc1202d5 | ||
|
|
e3b238c017 | ||
|
|
ed5bb14b11 |
@@ -16,6 +16,8 @@ const externals = {
|
||||
'bufferutil': 'commonjs bufferutil',
|
||||
'utf-8-validate': 'commonjs utf-8-validate',
|
||||
'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
|
||||
|
||||
@@ -181,17 +181,22 @@ export function registerAzureResourceCommands(appContext: AppContext, azureViewT
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
const treeItem: azdata.TreeItem = await node.getTreeItem();
|
||||
if (!treeItem.payload) {
|
||||
return;
|
||||
let connectionProfile: azdata.IConnectionProfile = undefined;
|
||||
if (node instanceof TreeNode) {
|
||||
const treeItem: azdata.TreeItem = await node.getTreeItem();
|
||||
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 });
|
||||
if (conn) {
|
||||
vscode.commands.executeCommand('workbench.view.connections');
|
||||
|
||||
@@ -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 prefShell = shells.splice(idx, 1);
|
||||
@@ -157,7 +157,7 @@ class AzureTerminal implements vscode.Pseudoterminal {
|
||||
}
|
||||
|
||||
async open(initialDimensions: vscode.TerminalDimensions): Promise<void> {
|
||||
this.setDimensions(initialDimensions);
|
||||
await this.setDimensions(initialDimensions);
|
||||
}
|
||||
|
||||
close(): void {
|
||||
@@ -167,14 +167,19 @@ class AzureTerminal implements vscode.Pseudoterminal {
|
||||
this.socket.removeAllListeners('message');
|
||||
this.socket.removeAllListeners('close');
|
||||
|
||||
this.socket.terminate();
|
||||
this.socket.close();
|
||||
|
||||
if (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> {
|
||||
if (!dimensions) {
|
||||
if (!dimensions || this.areSameDimensions(this.terminalDimensions, dimensions)) {
|
||||
return;
|
||||
}
|
||||
this.terminalDimensions = dimensions;
|
||||
|
||||
@@ -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)
|
||||
(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));
|
||||
@@ -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 notebookPath: string;
|
||||
// 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) {
|
||||
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
|
||||
if (bookItem?.contextValue && bookItem.contextValue !== 'pinnedNotebook') {
|
||||
// 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;
|
||||
}
|
||||
|
||||
async findAndExpandParentNode(notebookPath: string): Promise<BookTreeItem | undefined> {
|
||||
async findAndExpandParentNode(notebookPath: string, shouldFocus: boolean): Promise<BookTreeItem | undefined> {
|
||||
notebookPath = notebookPath.replace(/\\/g, '/');
|
||||
const parentBook = this.books.find(b => notebookPath.indexOf(b.bookPath) > -1);
|
||||
if (!parentBook) {
|
||||
@@ -470,7 +477,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
}
|
||||
try {
|
||||
// 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) {
|
||||
console.error(e);
|
||||
|
||||
@@ -150,9 +150,9 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
||||
|
||||
azdata.nb.onDidChangeActiveNotebookEditor(e => {
|
||||
if (e.document.uri.scheme === 'untitled') {
|
||||
providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false);
|
||||
providedBookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
||||
} else {
|
||||
bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false);
|
||||
bookTreeViewProvider.revealDocumentInTreeView(e.document.uri, false, false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ describe('BooksTreeViewTests', function () {
|
||||
|
||||
it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => {
|
||||
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();
|
||||
equalBookItems(currentSelection, expectedNotebook1);
|
||||
});
|
||||
@@ -329,7 +329,7 @@ describe('BooksTreeViewTests', function () {
|
||||
|
||||
it('revealActiveDocumentInViewlet should return correct bookItem for highlight', async () => {
|
||||
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();
|
||||
equalBookItems(currentSelection, expectedNotebook1);
|
||||
});
|
||||
|
||||
@@ -221,8 +221,8 @@ export class SchemaCompareDialog {
|
||||
this.sourceDacpacComponent = this.createFileBrowser(false, this.schemaCompareMainWindow.sourceEndpointInfo);
|
||||
this.targetDacpacComponent = this.createFileBrowser(true, this.schemaCompareMainWindow.targetEndpointInfo);
|
||||
|
||||
let sourceRadioButtons = this.createSourceRadiobuttons();
|
||||
let targetRadioButtons = this.createTargetRadiobuttons();
|
||||
let sourceRadioButtons = this.createSourceRadioButtons();
|
||||
let targetRadioButtons = this.createTargetRadioButtons();
|
||||
|
||||
let sourceComponents = [];
|
||||
let targetComponents = [];
|
||||
@@ -336,7 +336,7 @@ export class SchemaCompareDialog {
|
||||
};
|
||||
}
|
||||
|
||||
private createSourceRadiobuttons(): azdata.FormComponent {
|
||||
private createSourceRadioButtons(): azdata.FormComponent {
|
||||
this.sourceDacpacRadioButton = this.view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
name: 'source',
|
||||
@@ -365,8 +365,7 @@ export class SchemaCompareDialog {
|
||||
this.formBuilder.insertFormItem(this.sourceDatabaseComponent, 3, { horizontal: true, titleFontSize: titleFontSize });
|
||||
this.formBuilder.removeFormItem(this.sourceDacpacComponent);
|
||||
|
||||
this.populateServerDropdown(false);
|
||||
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
|
||||
await this.populateServerDropdown(false);
|
||||
});
|
||||
|
||||
// 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()
|
||||
.withProperties({
|
||||
name: 'target',
|
||||
@@ -418,8 +417,7 @@ export class SchemaCompareDialog {
|
||||
this.formBuilder.addFormItem(this.targetServerComponent, { horizontal: true, titleFontSize: titleFontSize });
|
||||
this.formBuilder.addFormItem(this.targetDatabaseComponent, { horizontal: true, titleFontSize: titleFontSize });
|
||||
|
||||
this.populateServerDropdown(true);
|
||||
this.dialog.okButton.enabled = await this.shouldEnableOkayButton();
|
||||
await this.populateServerDropdown(true);
|
||||
});
|
||||
|
||||
// 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> {
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,15 +73,7 @@ chalk@^2.4.1, chalk@^2.4.2:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chart.js@^2.6.0:
|
||||
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:
|
||||
chart.js@^2.6.0, chart.js@^2.9.4:
|
||||
version "2.9.4"
|
||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
|
||||
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==
|
||||
|
||||
@@ -140,15 +140,7 @@ chalk@^2.4.1, chalk@^2.4.2:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chart.js@^2.6.0:
|
||||
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:
|
||||
chart.js@^2.6.0, chart.js@^2.9.4:
|
||||
version "2.9.4"
|
||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
|
||||
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==
|
||||
|
||||
2
src/bootstrap-window.js
vendored
@@ -97,7 +97,7 @@
|
||||
window['MonacoEnvironment'] = {};
|
||||
|
||||
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`;
|
||||
|
||||
const loaderConfig = {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
164
src/sql/platform/actions/browser/menuEntryActionViewItem.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -440,6 +440,9 @@ export class BackupComponent extends AngularDisposable {
|
||||
|
||||
// Set backup type
|
||||
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.backupNameBox!.focus();
|
||||
|
||||
@@ -43,7 +43,7 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { TaskRegistry } from 'sql/workbench/services/tasks/browser/tasksRegistry';
|
||||
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 { NAV_SECTION } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardNavSection.contribution';
|
||||
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 { attachTabbedPanelStyler } from 'sql/workbench/common/styler';
|
||||
import { focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { LabeledMenuItemActionItem } from 'sql/platform/actions/browser/menuEntryActionViewItem';
|
||||
|
||||
const dashboardRegistry = Registry.as<IDashboardRegistry>(DashboardExtensions.DashboardContributions);
|
||||
const homeTabGroupId = 'home';
|
||||
|
||||
@@ -22,6 +22,7 @@ import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { attachCalloutDialogStyler } from 'sql/workbench/common/styler';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { escapeLabel, escapeUrl } from 'sql/workbench/contrib/notebook/browser/calloutDialog/common/utils';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
export interface ILinkCalloutDialogOptions {
|
||||
insertTitle?: string,
|
||||
@@ -100,6 +101,13 @@ export class LinkCalloutDialog extends Modal {
|
||||
}
|
||||
|
||||
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');
|
||||
DOM.append(container, linkContentColumn);
|
||||
|
||||
@@ -147,7 +155,8 @@ export class LinkCalloutDialog extends Modal {
|
||||
protected onAccept(e?: StandardKeyboardEvent) {
|
||||
// EventHelper.stop() will call preventDefault. Without it, text cell will insert an extra newline when pressing enter on dialog
|
||||
DOM.EventHelper.stop(e, true);
|
||||
this.insert();
|
||||
const keyboardEventExists = !!e;
|
||||
this.insert(keyboardEventExists);
|
||||
}
|
||||
|
||||
protected onClose(e?: StandardKeyboardEvent) {
|
||||
@@ -155,8 +164,10 @@ export class LinkCalloutDialog extends Modal {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
public insert(): void {
|
||||
this.hide('ok');
|
||||
public insert(willHideByKeyboardEvent = false): void {
|
||||
if (!willHideByKeyboardEvent) {
|
||||
this.hide('ok');
|
||||
}
|
||||
let escapedLabel = escapeLabel(this._linkTextInputBox.value);
|
||||
let escapedUrl = escapeUrl(this._linkUrlInputBox.value);
|
||||
|
||||
|
||||
@@ -266,6 +266,15 @@ export class HTMLMarkdownConverter {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -281,10 +290,16 @@ function blankReplacement(content, node) {
|
||||
// When outdenting a nested list, an empty list will still remain. Need to handle this case.
|
||||
if (node.nodeName === 'UL' || node.nodeName === 'OL') {
|
||||
return '\n';
|
||||
} else if (isInsideTable(node)) {
|
||||
return ' ';
|
||||
}
|
||||
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 {
|
||||
if (notebookFolder) {
|
||||
if (contentPath?.scheme === 'file') {
|
||||
|
||||
@@ -41,7 +41,7 @@ import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
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 { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
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';
|
||||
|
||||
|
||||
@@ -68,36 +68,23 @@ rules['tableCell'] = {
|
||||
rules['tableRow'] = {
|
||||
filter: 'tr',
|
||||
replacement: function (content, node) {
|
||||
let borderCells = '';
|
||||
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]);
|
||||
}
|
||||
}
|
||||
const borderCells = isHeadingRow(node) ? constructBorderCells(node) : '';
|
||||
return '\n' + content + (borderCells ? '\n' + borderCells : '');
|
||||
}
|
||||
};
|
||||
|
||||
rules['table'] = {
|
||||
// Only convert tables with a heading row.
|
||||
// Tables with no heading row are kept using `keep` (see below).
|
||||
filter: function (node) {
|
||||
return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0]);
|
||||
return node.nodeName === 'TABLE';
|
||||
},
|
||||
replacement: function (content, node) {
|
||||
// Ensure there are no blank lines
|
||||
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';
|
||||
}
|
||||
};
|
||||
@@ -148,10 +135,25 @@ function cell(content, node) {
|
||||
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) {
|
||||
turndownService.keep(function (node) {
|
||||
return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0]);
|
||||
});
|
||||
for (let key in rules) {
|
||||
turndownService.addRule(key, rules[key]);
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
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', () => {
|
||||
htmlString = '<b>test string</b>';
|
||||
assert.equal(htmlMarkdownConverter.convert(htmlString), '**test string**', 'Basic bold test failed');
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:grey;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -14,8 +14,8 @@
|
||||
circle:nth-child(8) { animation-delay: 0.525s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
0% { opacity: 1; }
|
||||
100% { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -207,7 +207,7 @@ class SharedProcessMain extends Disposable {
|
||||
|
||||
// Application Insights
|
||||
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
|
||||
telemetryAppender = combinedAppender(appInsightsAppender, telemetryAppender);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ class CliMain extends Disposable {
|
||||
const appenders: AppInsightsAppender[] = [];
|
||||
if (isBuilt && !extensionDevelopmentLocationURI && !environmentService.disableTelemetry && product.enableTelemetry) {
|
||||
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 = {
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
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 { IAction, Separator } from 'vs/base/common/actions';
|
||||
import { IdGenerator } from 'vs/base/common/idGenerator'; // {{SQL CARBON EDIT}}
|
||||
import { IDisposable, toDisposable, MutableDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; // {{SQL CARBON EDIT}}
|
||||
import { IDisposable, toDisposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction, Icon } from 'vs/platform/actions/common/actions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -45,8 +44,7 @@ function asDisposable(groups: ReadonlyArray<[string, ReadonlyArray<MenuItemActio
|
||||
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 {
|
||||
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
|
||||
|
||||
let primaryBucket: 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 {
|
||||
|
||||
private _wantsAltCommand: boolean = false;
|
||||
@@ -262,150 +256,3 @@ export function createActionViewItem(instaService: IInstantiationService, action
|
||||
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
|
||||
|
||||
@@ -155,24 +155,25 @@ export interface IExtensionIdentifier {
|
||||
uuid?: string;
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} - ADS only implemented language pack filtering
|
||||
export const EXTENSION_CATEGORIES = [
|
||||
'Azure',
|
||||
'Data Science',
|
||||
'Debuggers',
|
||||
'Extension Packs',
|
||||
'Formatters',
|
||||
'Keymaps',
|
||||
// 'Azure',
|
||||
// 'Data Science',
|
||||
// 'Debuggers',
|
||||
// 'Extension Packs',
|
||||
// 'Formatters',
|
||||
// 'Keymaps',
|
||||
'Language Packs',
|
||||
'Linters',
|
||||
'Machine Learning',
|
||||
'Notebooks',
|
||||
'Programming Languages',
|
||||
'SCM Providers',
|
||||
'Snippets',
|
||||
'Testing',
|
||||
'Themes',
|
||||
'Visualization',
|
||||
'Other',
|
||||
// 'Linters',
|
||||
// 'Machine Learning',
|
||||
// 'Notebooks',
|
||||
// 'Programming Languages',
|
||||
// 'SCM Providers',
|
||||
// 'Snippets',
|
||||
// 'Testing',
|
||||
// 'Themes',
|
||||
// 'Visualization',
|
||||
// 'Other',
|
||||
];
|
||||
|
||||
export interface IExtensionManifest {
|
||||
|
||||
@@ -576,7 +576,7 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
button.label = node.label;
|
||||
button.onDidClick(_ => {
|
||||
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);
|
||||
disposables.add(button);
|
||||
disposables.add(attachButtonStyler(button, this.themeService));
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsServi
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/services/output/common/output';
|
||||
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 { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
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 { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
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 { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
|
||||
@@ -762,6 +762,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||
icon: filterIcon,
|
||||
});
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
|
||||
const showFeaturedExtensionsId = 'extensions.filter.featured';
|
||||
this.registerExtensionAction({
|
||||
id: showFeaturedExtensionsId,
|
||||
@@ -800,6 +801,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||
},
|
||||
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@popular '))
|
||||
});
|
||||
*/
|
||||
|
||||
this.registerExtensionAction({
|
||||
id: 'workbench.extensions.action.showRecommendedExtensions',
|
||||
@@ -820,6 +822,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@recommended '))
|
||||
});
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
|
||||
this.registerExtensionAction({
|
||||
id: 'workbench.extensions.action.recentlyPublishedExtensions',
|
||||
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 '))
|
||||
});
|
||||
*/
|
||||
|
||||
const extensionsCategoryFilterSubMenu = new MenuId('extensionsCategoryFilterSubMenu');
|
||||
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
|
||||
@@ -952,6 +956,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||
run: () => runAction(this.instantiationService.createInstance(SearchExtensionsAction, '@outdated '))
|
||||
});
|
||||
|
||||
/* {{SQL CARBON EDIT}} - Remove the menu items not applicable in ADS
|
||||
const extensionsSortSubMenu = new MenuId('extensionsSortSubMenu');
|
||||
MenuRegistry.appendMenuItem(extensionsFilterSubMenu, <ISubmenuItem>{
|
||||
submenu: extensionsSortSubMenu,
|
||||
@@ -986,6 +991,7 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
|
||||
}
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
this.registerExtensionAction({
|
||||
id: 'workbench.extensions.action.clearExtensionsSearchResults',
|
||||
|
||||
@@ -60,7 +60,7 @@ export function setup() {
|
||||
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;
|
||||
await app.workbench.sqlNotebook.newUntitledNotebook();
|
||||
await app.workbench.sqlNotebook.addCellFromPlaceholder('Markdown');
|
||||
|
||||
10
yarn.lock
@@ -1946,15 +1946,7 @@ charenc@~0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||
|
||||
chart.js@^2.6.0:
|
||||
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:
|
||||
chart.js@^2.6.0, chart.js@^2.9.4:
|
||||
version "2.9.4"
|
||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.4.tgz#0827f9563faffb2dc5c06562f8eb10337d5b9684"
|
||||
integrity sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==
|
||||
|
||||