Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c2a0f3d40 | ||
|
|
283c851494 | ||
|
|
8e63ca8d0a | ||
|
|
fbce1719c9 | ||
|
|
81ae52f75f | ||
|
|
38ca77c8c5 | ||
|
|
5275bb9e56 | ||
|
|
a6816a5de8 | ||
|
|
728bc76b4b | ||
|
|
21dd79ab03 | ||
|
|
ee60400e3b | ||
|
|
99f37006a5 | ||
|
|
00b08bd677 | ||
|
|
1503e3846f | ||
|
|
370e521910 | ||
|
|
2ef0b7adb8 | ||
|
|
ebd307d78e | ||
|
|
d1251ce57e | ||
|
|
5e91e86360 | ||
|
|
c81f5580d1 | ||
|
|
27e3b4995a | ||
|
|
551536e666 | ||
|
|
f3d4a55bb1 | ||
|
|
4fc9057025 | ||
|
|
c30b8cde42 | ||
|
|
f4464f352f | ||
|
|
2e127582bd | ||
|
|
ae13131370 | ||
|
|
64ccb21d26 | ||
|
|
5b7224fa5e | ||
|
|
f364a60eca | ||
|
|
fc5cf99f02 | ||
|
|
14fdd6f529 | ||
|
|
377a327cac | ||
|
|
139609a7c3 | ||
|
|
b80bc686b2 | ||
|
|
dc7fd013a6 | ||
|
|
5375629585 | ||
|
|
339a3bcbf6 | ||
|
|
e627619c7a | ||
|
|
26870655b6 |
@@ -49,11 +49,12 @@ function getConfig(quality: string): Promise<Config> {
|
||||
query: `SELECT TOP 1 * FROM c WHERE c.id = @quality`,
|
||||
parameters: [
|
||||
{ name: '@quality', value: quality }
|
||||
]
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
return new Promise<Config>((c, e) => {
|
||||
client.queryDocuments(collection, query).toArray((err, results) => {
|
||||
client.queryDocuments(collection, query, { enableCrossPartitionQuery: true }).toArray((err, results) => {
|
||||
if (err && err.code !== 409) { return e(err); }
|
||||
|
||||
c(!results || results.length === 0 ? createDefaultConfig(quality) : results[0] as any as Config);
|
||||
@@ -86,7 +87,7 @@ function createOrUpdate(commit: string, quality: string, platform: string, type:
|
||||
updateTries++;
|
||||
|
||||
return new Promise<void>((c, e) => {
|
||||
client.queryDocuments(collection, updateQuery).toArray((err, results) => {
|
||||
client.queryDocuments(collection, updateQuery, { enableCrossPartitionQuery: true }).toArray((err, results) => {
|
||||
if (err) { return e(err); }
|
||||
if (results.length !== 1) { return e(new Error('No documents')); }
|
||||
|
||||
@@ -217,7 +218,13 @@ async function publish(commit: string, quality: string, platform: string, type:
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Insiders: nightly build from master
|
||||
const isReleased = (quality === 'insider' && /^master$|^refs\/heads\/master$/.test(sourceBranch) && /Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy));
|
||||
const isReleased = (
|
||||
(
|
||||
(quality === 'insider' && /^master$|^refs\/heads\/master$/.test(sourceBranch)) ||
|
||||
(quality === 'rc1' && /^release\/|^refs\/heads\/release\//.test(sourceBranch))
|
||||
) &&
|
||||
/Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy)
|
||||
);
|
||||
|
||||
const release = {
|
||||
id: commit,
|
||||
|
||||
@@ -97,6 +97,8 @@ steps:
|
||||
exec { yarn gulp "vscode-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-web-win32-x64-min-ci" }
|
||||
exec { yarn gulp "vscode-win32-x64-code-helper" }
|
||||
exec { yarn gulp "vscode-win32-x64-inno-updater" }
|
||||
displayName: Build
|
||||
env:
|
||||
VSCODE_MIXIN_PASSWORD: $(github-distro-mixin-password)
|
||||
|
||||
@@ -186,6 +186,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
||||
const checksums = computeChecksums(out, [
|
||||
'vs/workbench/workbench.desktop.main.js',
|
||||
'vs/workbench/workbench.desktop.main.css',
|
||||
'vs/workbench/services/extensions/node/extensionHostProcess.js',
|
||||
'vs/code/electron-browser/workbench/workbench.html',
|
||||
'vs/code/electron-browser/workbench/workbench.js'
|
||||
]);
|
||||
|
||||
@@ -78,6 +78,7 @@ Name: "runcode"; Description: "{cm:RunAfter,{#NameShort}}"; GroupDescription: "{
|
||||
|
||||
[Files]
|
||||
Source: "*"; Excludes: "\CodeSignSummary*.md,\tools,\tools\*,\resources\app\product.json"; DestDir: "{code:GetDestDir}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "tools\*"; DestDir: "{app}\tools"; Flags: ignoreversion
|
||||
Source: "{#ProductJsonPath}"; DestDir: "{code:GetDestDir}\resources\app"; Flags: ignoreversion
|
||||
|
||||
[Icons]
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
},
|
||||
"azure.noSystemKeychain": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"default": true,
|
||||
"description": "%config.noSystemKeychain%",
|
||||
"when": "isLinux || isWeb"
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as keytarType from 'keytar';
|
||||
import { join } from 'path';
|
||||
import { join, parse } from 'path';
|
||||
import { FileDatabase } from './utils/fileDatabase';
|
||||
import * as azdata from 'azdata';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
function getSystemKeytar(): Keytar | undefined | null {
|
||||
try {
|
||||
@@ -22,45 +23,43 @@ export type MultipleAccountsResponse = { account: string, password: string }[];
|
||||
const separator = '§';
|
||||
|
||||
async function getFileKeytar(filePath: string, credentialService: azdata.CredentialProvider): Promise<Keytar | undefined> {
|
||||
// Comment alias: amomidi, PR: 9743 March 26th 2020
|
||||
// const fileName = parse(filePath).base;
|
||||
// const iv = await credentialService.readCredential(`${fileName}-iv`);
|
||||
// const key = await credentialService.readCredential(`${fileName}-key`);
|
||||
// let ivBuffer: Buffer;
|
||||
// let keyBuffer: Buffer;
|
||||
// if (!iv?.password || !key?.password) {
|
||||
// ivBuffer = crypto.randomBytes(16);
|
||||
// keyBuffer = crypto.randomBytes(32);
|
||||
// try {
|
||||
// await credentialService.saveCredential(`${fileName}-iv`, ivBuffer.toString('hex'));
|
||||
// await credentialService.saveCredential(`${fileName}-key`, keyBuffer.toString('hex'));
|
||||
// } catch (ex) {
|
||||
// console.log(ex);
|
||||
// }
|
||||
// } else {
|
||||
// ivBuffer = Buffer.from(iv.password, 'hex');
|
||||
// keyBuffer = Buffer.from(key.password, 'hex');
|
||||
// }
|
||||
const fileName = parse(filePath).base;
|
||||
const iv = await credentialService.readCredential(`${fileName}-iv`);
|
||||
const key = await credentialService.readCredential(`${fileName}-key`);
|
||||
let ivBuffer: Buffer;
|
||||
let keyBuffer: Buffer;
|
||||
if (!iv?.password || !key?.password) {
|
||||
ivBuffer = crypto.randomBytes(16);
|
||||
keyBuffer = crypto.randomBytes(32);
|
||||
try {
|
||||
await credentialService.saveCredential(`${fileName}-iv`, ivBuffer.toString('hex'));
|
||||
await credentialService.saveCredential(`${fileName}-key`, keyBuffer.toString('hex'));
|
||||
} catch (ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
} else {
|
||||
ivBuffer = Buffer.from(iv.password, 'hex');
|
||||
keyBuffer = Buffer.from(key.password, 'hex');
|
||||
}
|
||||
|
||||
// const fileSaver = async (content: string): Promise<string> => {
|
||||
// const cipherIv = crypto.createCipheriv('aes-256-gcm', keyBuffer, ivBuffer);
|
||||
// return `${cipherIv.update(content, 'utf8', 'hex')}${cipherIv.final('hex')}%${cipherIv.getAuthTag().toString('hex')}`;
|
||||
// };
|
||||
const fileSaver = async (content: string): Promise<string> => {
|
||||
const cipherIv = crypto.createCipheriv('aes-256-gcm', keyBuffer, ivBuffer);
|
||||
return `${cipherIv.update(content, 'utf8', 'hex')}${cipherIv.final('hex')}%${cipherIv.getAuthTag().toString('hex')}`;
|
||||
};
|
||||
|
||||
// const fileOpener = async (content: string): Promise<string> => {
|
||||
// const decipherIv = crypto.createDecipheriv('aes-256-gcm', keyBuffer, ivBuffer);
|
||||
const fileOpener = async (content: string): Promise<string> => {
|
||||
const decipherIv = crypto.createDecipheriv('aes-256-gcm', keyBuffer, ivBuffer);
|
||||
|
||||
// const split = content.split('%');
|
||||
// if (split.length !== 2) {
|
||||
// throw new Error('File didn\'t contain the auth tag.');
|
||||
// }
|
||||
// decipherIv.setAuthTag(Buffer.from(split[1], 'hex'));
|
||||
const split = content.split('%');
|
||||
if (split.length !== 2) {
|
||||
throw new Error('File didn\'t contain the auth tag.');
|
||||
}
|
||||
decipherIv.setAuthTag(Buffer.from(split[1], 'hex'));
|
||||
|
||||
// return `${decipherIv.update(split[0], 'hex', 'utf8')}${decipherIv.final('utf8')}`;
|
||||
// };
|
||||
return `${decipherIv.update(split[0], 'hex', 'utf8')}${decipherIv.final('utf8')}`;
|
||||
};
|
||||
|
||||
// const db = new FileDatabase(filePath, fileOpener, fileSaver);
|
||||
const db = new FileDatabase(filePath);
|
||||
const db = new FileDatabase(filePath, fileOpener, fileSaver);
|
||||
await db.initialize();
|
||||
|
||||
const fileKeytar: Keytar = {
|
||||
@@ -142,7 +141,7 @@ export class SimpleTokenCache {
|
||||
}
|
||||
|
||||
async saveCredential(id: string, key: string): Promise<void> {
|
||||
if (key.length > 2500) { // Windows limitation
|
||||
if (!this.forceFileStorage && key.length > 2500) { // Windows limitation
|
||||
throw new Error('Key length is longer than 2500 chars');
|
||||
}
|
||||
|
||||
@@ -160,9 +159,11 @@ export class SimpleTokenCache {
|
||||
async getCredential(id: string): Promise<string | undefined> {
|
||||
try {
|
||||
const result = await this.keytar.getPassword(this.serviceName, id);
|
||||
|
||||
if (result === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (ex) {
|
||||
console.log(`Getting key failed: ${ex}`);
|
||||
|
||||
@@ -80,7 +80,7 @@ export class SimpleWebServer {
|
||||
reject(new Error('Server closed'));
|
||||
});
|
||||
|
||||
this.server.listen(0);
|
||||
this.server.listen(0, '127.0.0.1');
|
||||
});
|
||||
|
||||
const clearPortTimeout = () => {
|
||||
|
||||
@@ -26,6 +26,12 @@ import { AzureAccount, Tenant } from '../account-provider/interfaces';
|
||||
export function registerAzureResourceCommands(appContext: AppContext, tree: AzureResourceTreeProvider): void {
|
||||
appContext.apiWrapper.registerCommand('azure.resource.startterminal', async (node?: TreeNode) => {
|
||||
try {
|
||||
const enablePreviewFeatures = appContext.apiWrapper.getConfiguration('workbench').get('enablePreviewFeatures');
|
||||
if (!enablePreviewFeatures) {
|
||||
const msg = localize('azure.cloudTerminalPreview', "You must enable preview features in order to use Azure Cloud Shell.");
|
||||
appContext.apiWrapper.showInformationMessage(msg);
|
||||
return;
|
||||
}
|
||||
if (!node || !(node instanceof AzureResourceAccountTreeNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1262,7 +1262,7 @@
|
||||
"timeline/item/context": [
|
||||
{
|
||||
"command": "git.timeline.openDiff",
|
||||
"group": "1_actions",
|
||||
"group": "1_timeline",
|
||||
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file\\b/"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -443,7 +443,10 @@ export class Git {
|
||||
);
|
||||
if (networkPath !== undefined) {
|
||||
return path.normalize(
|
||||
repoUri.fsPath.replace(networkPath, `${letter.toLowerCase()}:`),
|
||||
repoUri.fsPath.replace(
|
||||
networkPath,
|
||||
`${letter.toLowerCase()}:${networkPath.endsWith('\\') ? '\\' : ''}`
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch { }
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"description": "%mssql.tabs.databases%",
|
||||
"provider": "*",
|
||||
"title": "%mssql.tabs.databases%",
|
||||
"when": "dashboardContext == 'server'",
|
||||
"when": "dashboardContext == 'server' && !mssql:iscloud && mssql:engineedition != 11",
|
||||
"group": "home",
|
||||
"icon": "resources/database.svg",
|
||||
"container": {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"properties": {
|
||||
"notebook.maxBookSearchDepth": {
|
||||
"type": "number",
|
||||
"default": 5,
|
||||
"default": 10,
|
||||
"description": "%notebook.maxBookSearchDepth.description%"
|
||||
},
|
||||
"notebook.pythonPath": {
|
||||
@@ -203,10 +203,23 @@
|
||||
"light": "resources/light/open_notebook.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.openNotebookFolder",
|
||||
"title": "%title.openNotebookFolder%",
|
||||
"category": "%books-preview-category%",
|
||||
"icon": {
|
||||
"dark": "resources/dark/open_folder_inverse.svg",
|
||||
"light": "resources/light/open_folder.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.closeBook",
|
||||
"title": "%title.closeJupyterBook%"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.closeNotebook",
|
||||
"title": "%title.closeJupyterNotebook%"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.createBook",
|
||||
"title": "%title.createJupyterBook%",
|
||||
@@ -317,6 +330,10 @@
|
||||
"command": "notebook.command.closeBook",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.closeNotebook",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.revealInBooksViewlet",
|
||||
"when": "false"
|
||||
@@ -370,6 +387,10 @@
|
||||
{
|
||||
"command": "notebook.command.closeBook",
|
||||
"when": "view == bookTreeView && viewItem == savedBook"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.closeNotebook",
|
||||
"when": "view == bookTreeView && viewItem == savedNotebook"
|
||||
}
|
||||
],
|
||||
"view/title": [
|
||||
@@ -381,6 +402,11 @@
|
||||
{
|
||||
"command": "notebook.command.createBook",
|
||||
"when": "view == bookTreeView"
|
||||
},
|
||||
{
|
||||
"command": "notebook.command.openNotebookFolder",
|
||||
"when": "view == bookTreeView",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"notebook/toolbar": [
|
||||
@@ -486,7 +512,7 @@
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "books-explorer",
|
||||
"title": "Jupyter Books",
|
||||
"title": "Notebooks",
|
||||
"icon": "resources/dark/JupyterBook_2.svg"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
"title.saveJupyterBook": "Save Book",
|
||||
"title.trustBook": "Trust Book",
|
||||
"title.searchJupyterBook": "Search Book",
|
||||
"title.SavedBooks": "Saved Books",
|
||||
"title.UnsavedBooks": "Unsaved Books",
|
||||
"title.SavedBooks": "Notebooks",
|
||||
"title.UnsavedBooks": "Provided Books",
|
||||
"title.PreviewLocalizedBook": "Get localized SQL Server 2019 guide",
|
||||
"title.openJupyterBook": "Open Jupyter Book",
|
||||
"title.closeJupyterBook": "Close Jupyter Book",
|
||||
"title.closeJupyterNotebook": "Close Jupyter Notebook",
|
||||
"title.revealInBooksViewlet": "Reveal in Books",
|
||||
"title.createJupyterBook": "Create Book (Preview)"
|
||||
"title.createJupyterBook": "Create Book (Preview)",
|
||||
"title.openNotebookFolder": "Open Notebooks in Folder"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5161 6.50115C13.5903 6.50115 13.6642 6.50822 13.7367 6.52218L13.8443 6.54826L13.9492 6.58452C14.516 6.81113 14.8071 7.43239 14.6328 8.00586L14.5994 8.10092L12.8831 12.3939C12.6695 12.9281 12.1711 13.2898 11.604 13.3328L11.4877 13.3373H3.4285C3.4053 13.3373 3.38213 13.3368 3.35899 13.3357L2.83354 13.3343C2.04002 13.3336 1.39066 12.7171 1.3375 11.9367L1.33398 11.834V4.17254C1.33398 3.3796 1.94931 2.73018 2.72882 2.67617L2.83139 2.67254L5.47001 2.66797C5.7779 2.66744 6.07737 2.76163 6.3285 2.93612L6.43304 3.01577L8.01465 4.33401L11.1673 4.33448C11.9251 4.33448 12.5517 4.89646 12.653 5.6264L12.6639 5.73178L12.6673 5.83448V6.50068L13.5161 6.50115ZM4.82389 7.50115C4.63701 7.50115 4.46788 7.60506 4.38213 7.76691L4.35401 7.83023L2.95862 11.6664C2.86422 11.9259 2.99807 12.2128 3.25758 12.3072C3.2941 12.3205 3.33198 12.3294 3.37045 12.3339L11.4901 12.3371C11.5355 12.3371 11.58 12.3309 11.6224 12.3193L11.6826 12.2978C11.7793 12.2568 11.8619 12.1858 11.9168 12.094L11.9526 12.0213L13.6515 7.72915C13.6854 7.64357 13.6435 7.54672 13.5579 7.51284L13.5277 7.5041L13.4965 7.50115H4.82389ZM5.47174 3.66797L2.83312 3.67254C2.5803 3.67298 2.37157 3.861 2.33854 4.10477L2.33398 4.17254L2.33332 10.4586L3.41425 7.48839C3.61637 6.93273 4.12413 6.55124 4.70649 6.50572L4.82389 6.50115L11.6667 6.50064L11.6673 5.83448C11.6673 5.58135 11.4792 5.37215 11.2352 5.33904L11.1673 5.33448H7.65292L5.79275 3.78391C5.72068 3.72383 5.63354 3.68555 5.54152 3.67274L5.47174 3.66797Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
3
extensions/notebook/resources/light/open_folder.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5161 6.50115C13.5903 6.50115 13.6642 6.50822 13.7367 6.52218L13.8443 6.54826L13.9492 6.58452C14.516 6.81113 14.8071 7.43239 14.6328 8.00586L14.5994 8.10092L12.8831 12.3939C12.6695 12.9281 12.1711 13.2898 11.604 13.3328L11.4877 13.3373H3.4285C3.4053 13.3373 3.38213 13.3368 3.35899 13.3357L2.83354 13.3343C2.04002 13.3336 1.39066 12.7171 1.3375 11.9367L1.33398 11.834V4.17254C1.33398 3.3796 1.94931 2.73018 2.72882 2.67617L2.83139 2.67254L5.47001 2.66797C5.7779 2.66744 6.07737 2.76163 6.3285 2.93612L6.43304 3.01577L8.01465 4.33401L11.1673 4.33448C11.9251 4.33448 12.5517 4.89646 12.653 5.6264L12.6639 5.73178L12.6673 5.83448V6.50068L13.5161 6.50115ZM4.82389 7.50115C4.63701 7.50115 4.46788 7.60506 4.38213 7.76691L4.35401 7.83023L2.95862 11.6664C2.86422 11.9259 2.99807 12.2128 3.25758 12.3072C3.2941 12.3205 3.33198 12.3294 3.37045 12.3339L11.4901 12.3371C11.5355 12.3371 11.58 12.3309 11.6224 12.3193L11.6826 12.2978C11.7793 12.2568 11.8619 12.1858 11.9168 12.094L11.9526 12.0213L13.6515 7.72915C13.6854 7.64357 13.6435 7.54672 13.5579 7.51284L13.5277 7.5041L13.4965 7.50115H4.82389ZM5.47174 3.66797L2.83312 3.67254C2.5803 3.67298 2.37157 3.861 2.33854 4.10477L2.33398 4.17254L2.33332 10.4586L3.41425 7.48839C3.61637 6.93273 4.12413 6.55124 4.70649 6.50572L4.82389 6.50115L11.6667 6.50064L11.6673 5.83448C11.6673 5.58135 11.4792 5.37215 11.2352 5.33904L11.1673 5.33448H7.65292L5.79275 3.78391C5.72068 3.72383 5.63354 3.68555 5.54152 3.67274L5.47174 3.66797Z" fill="#212121"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -6,15 +6,12 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as glob from 'fast-glob';
|
||||
import { BookTreeItem, BookTreeItemType } from './bookTreeItem';
|
||||
import { maxBookSearchDepth, notebookConfigKey } from '../common/constants';
|
||||
import * as path from 'path';
|
||||
import * as fileServices from 'fs';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
import { IJupyterBookToc, IJupyterBookSection } from '../contracts/content';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
|
||||
|
||||
@@ -23,24 +20,30 @@ const fsPromises = fileServices.promises;
|
||||
export class BookModel implements azdata.nb.NavigationProvider {
|
||||
private _bookItems: BookTreeItem[];
|
||||
private _allNotebooks = new Map<string, BookTreeItem>();
|
||||
private _tableOfContentPaths: string[] = [];
|
||||
private _tableOfContentsPath: string;
|
||||
readonly providerId: string = 'BookNavigator';
|
||||
|
||||
private _errorMessage: string;
|
||||
private apiWrapper: ApiWrapper = new ApiWrapper();
|
||||
|
||||
constructor(public bookPath: string, public openAsUntitled: boolean, private _extensionContext: vscode.ExtensionContext) {
|
||||
this.bookPath = bookPath;
|
||||
this.openAsUntitled = openAsUntitled;
|
||||
constructor(
|
||||
public readonly bookPath: string,
|
||||
public readonly openAsUntitled: boolean,
|
||||
public readonly isNotebook: boolean,
|
||||
private _extensionContext: vscode.ExtensionContext) {
|
||||
this._bookItems = [];
|
||||
this._extensionContext.subscriptions.push(azdata.nb.registerNavigationProvider(this));
|
||||
}
|
||||
|
||||
public async initializeContents(): Promise<void> {
|
||||
this._tableOfContentPaths = [];
|
||||
this._bookItems = [];
|
||||
await this.getTableOfContentFiles(this.bookPath);
|
||||
await this.readBooks();
|
||||
this._allNotebooks = new Map<string, BookTreeItem>();
|
||||
if (this.isNotebook) {
|
||||
this.readNotebook();
|
||||
} else {
|
||||
await this.loadTableOfContentFiles(this.bookPath);
|
||||
await this.readBooks();
|
||||
}
|
||||
}
|
||||
|
||||
public getAllNotebooks(): Map<string, BookTreeItem> {
|
||||
@@ -51,20 +54,14 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
return this._allNotebooks.get(uri);
|
||||
}
|
||||
|
||||
public async getTableOfContentFiles(folderPath: string): Promise<void> {
|
||||
let notebookConfig = vscode.workspace.getConfiguration(notebookConfigKey);
|
||||
let maxDepth = notebookConfig[maxBookSearchDepth];
|
||||
// Use default value if user enters an invalid value
|
||||
if (isNullOrUndefined(maxDepth) || maxDepth < 0) {
|
||||
maxDepth = 5;
|
||||
} else if (maxDepth === 0) { // No limit of search depth if user enters 0
|
||||
maxDepth = undefined;
|
||||
public async loadTableOfContentFiles(folderPath: string): Promise<void> {
|
||||
if (this.isNotebook) {
|
||||
return;
|
||||
}
|
||||
|
||||
let p: string = path.posix.join(glob.escapePath(folderPath.replace(/\\/g, '/')), '**', '_data', 'toc.yml');
|
||||
let tableOfContentPaths: string[] = await glob(p, { deep: maxDepth });
|
||||
if (tableOfContentPaths.length > 0) {
|
||||
this._tableOfContentPaths = this._tableOfContentPaths.concat(tableOfContentPaths);
|
||||
let tableOfContentsPath: string = path.posix.join(folderPath, '_data', 'toc.yml');
|
||||
if (await fs.pathExists(tableOfContentsPath)) {
|
||||
this._tableOfContentsPath = tableOfContentsPath;
|
||||
vscode.commands.executeCommand('setContext', 'bookOpened', true);
|
||||
} else {
|
||||
this._errorMessage = loc.missingTocError;
|
||||
@@ -72,16 +69,55 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public readNotebook(): BookTreeItem {
|
||||
if (!this.isNotebook) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let pathDetails = path.parse(this.bookPath);
|
||||
let notebookItem = new BookTreeItem({
|
||||
title: pathDetails.name,
|
||||
contentPath: this.bookPath,
|
||||
root: pathDetails.dir,
|
||||
tableOfContents: { sections: undefined },
|
||||
page: { sections: undefined },
|
||||
type: BookTreeItemType.Notebook,
|
||||
treeItemCollapsibleState: vscode.TreeItemCollapsibleState.Expanded,
|
||||
isUntitled: this.openAsUntitled,
|
||||
},
|
||||
{
|
||||
light: this._extensionContext.asAbsolutePath('resources/light/notebook.svg'),
|
||||
dark: this._extensionContext.asAbsolutePath('resources/dark/notebook_inverse.svg')
|
||||
}
|
||||
);
|
||||
this._bookItems.push(notebookItem);
|
||||
if (this.openAsUntitled && !this._allNotebooks.get(pathDetails.base)) {
|
||||
this._allNotebooks.set(pathDetails.base, notebookItem);
|
||||
} else {
|
||||
// convert to URI to avoid casing issue with drive letters when getting navigation links
|
||||
let uriToNotebook: vscode.Uri = vscode.Uri.file(this.bookPath);
|
||||
if (!this._allNotebooks.get(uriToNotebook.fsPath)) {
|
||||
this._allNotebooks.set(uriToNotebook.fsPath, notebookItem);
|
||||
}
|
||||
}
|
||||
return notebookItem;
|
||||
}
|
||||
|
||||
public async readBooks(): Promise<BookTreeItem[]> {
|
||||
for (const contentPath of this._tableOfContentPaths) {
|
||||
let root: string = path.dirname(path.dirname(contentPath));
|
||||
if (this.isNotebook) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this._tableOfContentsPath) {
|
||||
let root: string = path.dirname(path.dirname(this._tableOfContentsPath));
|
||||
try {
|
||||
let fileContents = await fsPromises.readFile(path.join(root, '_config.yml'), 'utf-8');
|
||||
const config = yaml.safeLoad(fileContents.toString());
|
||||
fileContents = await fsPromises.readFile(contentPath, 'utf-8');
|
||||
fileContents = await fsPromises.readFile(this._tableOfContentsPath, 'utf-8');
|
||||
const tableOfContents: any = yaml.safeLoad(fileContents.toString());
|
||||
let book: BookTreeItem = new BookTreeItem({
|
||||
title: config.title,
|
||||
contentPath: this._tableOfContentsPath,
|
||||
root: root,
|
||||
tableOfContents: { sections: this.parseJupyterSections(tableOfContents) },
|
||||
page: tableOfContents,
|
||||
@@ -114,6 +150,7 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
if (sections[i].external) {
|
||||
let externalLink: BookTreeItem = new BookTreeItem({
|
||||
title: sections[i].title,
|
||||
contentPath: undefined,
|
||||
root: root,
|
||||
tableOfContents: tableOfContents,
|
||||
page: sections[i],
|
||||
@@ -136,6 +173,7 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
if (await fs.pathExists(pathToNotebook)) {
|
||||
let notebook = new BookTreeItem({
|
||||
title: sections[i].title,
|
||||
contentPath: pathToNotebook,
|
||||
root: root,
|
||||
tableOfContents: tableOfContents,
|
||||
page: sections[i],
|
||||
@@ -165,6 +203,7 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
} else if (await fs.pathExists(pathToMarkdown)) {
|
||||
let markdown: BookTreeItem = new BookTreeItem({
|
||||
title: sections[i].title,
|
||||
contentPath: pathToMarkdown,
|
||||
root: root,
|
||||
tableOfContents: tableOfContents,
|
||||
page: sections[i],
|
||||
@@ -208,8 +247,8 @@ export class BookModel implements azdata.nb.NavigationProvider {
|
||||
|
||||
}
|
||||
|
||||
public get tableOfContentPaths(): string[] {
|
||||
return this._tableOfContentPaths;
|
||||
public get tableOfContentsPath(): string {
|
||||
return this._tableOfContentsPath;
|
||||
}
|
||||
|
||||
getNavigation(uri: vscode.Uri): Thenable<azdata.nb.NavigationResult> {
|
||||
|
||||
@@ -18,6 +18,7 @@ export enum BookTreeItemType {
|
||||
|
||||
export interface BookTreeItemFormat {
|
||||
title: string;
|
||||
contentPath: string;
|
||||
root: string;
|
||||
tableOfContents: IJupyterBookToc;
|
||||
page: any;
|
||||
@@ -47,6 +48,12 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
} else {
|
||||
if (book.page && book.page.sections && book.page.sections.length > 0) {
|
||||
this.contextValue = 'section';
|
||||
} else if (book.type === BookTreeItemType.Notebook && !book.tableOfContents.sections) {
|
||||
if (book.isUntitled) {
|
||||
this.contextValue = 'unsavedNotebook';
|
||||
} else {
|
||||
this.contextValue = 'savedNotebook';
|
||||
}
|
||||
}
|
||||
this.setPageVariables();
|
||||
this.setCommand();
|
||||
@@ -63,19 +70,19 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
this._sections = this.book.page.sections || this.book.page.subsections;
|
||||
this._uri = this.book.page.url;
|
||||
|
||||
let index = (this.book.tableOfContents.sections.indexOf(this.book.page));
|
||||
this.setPreviousUri(index);
|
||||
this.setNextUri(index);
|
||||
if (this.book.tableOfContents.sections) {
|
||||
let index = (this.book.tableOfContents.sections.indexOf(this.book.page));
|
||||
this.setPreviousUri(index);
|
||||
this.setNextUri(index);
|
||||
}
|
||||
}
|
||||
|
||||
private setCommand() {
|
||||
if (this.book.type === BookTreeItemType.Notebook) {
|
||||
// The Notebook editor expects a posix path for the resource (it will still resolve to the correct fsPath based on OS)
|
||||
const pathToNotebook = path.posix.join(this.book.root, 'content', this._uri.concat('.ipynb'));
|
||||
this.command = { command: this.book.isUntitled ? 'bookTreeView.openUntitledNotebook' : 'bookTreeView.openNotebook', title: loc.openNotebookCommand, arguments: [pathToNotebook], };
|
||||
this.command = { command: this.book.isUntitled ? 'bookTreeView.openUntitledNotebook' : 'bookTreeView.openNotebook', title: loc.openNotebookCommand, arguments: [this.book.contentPath], };
|
||||
} else if (this.book.type === BookTreeItemType.Markdown) {
|
||||
let pathToMarkdown = path.join(this.book.root, 'content', this._uri.concat('.md'));
|
||||
this.command = { command: 'bookTreeView.openMarkdown', title: loc.openMarkdownCommand, arguments: [pathToMarkdown], };
|
||||
this.command = { command: 'bookTreeView.openMarkdown', title: loc.openMarkdownCommand, arguments: [this.book.contentPath], };
|
||||
} else if (this.book.type === BookTreeItemType.ExternalLink) {
|
||||
this.command = { command: 'bookTreeView.openExternalLink', title: loc.openExternalLinkCommand, arguments: [this._uri], };
|
||||
}
|
||||
@@ -146,7 +153,7 @@ export class BookTreeItem extends vscode.TreeItem {
|
||||
return `${this._uri}`;
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
return this.book.type === BookTreeItemType.Book ? this.book.root : this.book.contentPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,18 +8,25 @@ import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as constants from '../common/constants';
|
||||
import * as fsw from 'fs';
|
||||
import { IPrompter, QuestionTypes, IQuestion } from '../prompts/question';
|
||||
import CodeAdapter from '../prompts/adapter';
|
||||
import { BookTreeItem } from './bookTreeItem';
|
||||
import { BookTreeItem, BookTreeItemType } from './bookTreeItem';
|
||||
import { BookModel } from './bookModel';
|
||||
import { Deferred } from '../common/promise';
|
||||
import { IBookTrustManager, BookTrustManager } from './bookTrustManager';
|
||||
import * as loc from '../common/localizedConstants';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
import * as glob from 'fast-glob';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { debounce } from '../common/utils';
|
||||
|
||||
const Content = 'content';
|
||||
|
||||
interface BookSearchResults {
|
||||
notebookPaths: string[];
|
||||
bookPaths: string[];
|
||||
}
|
||||
|
||||
export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeItem> {
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<BookTreeItem | undefined> = new vscode.EventEmitter<BookTreeItem | undefined>();
|
||||
readonly onDidChangeTreeData: vscode.Event<BookTreeItem | undefined> = this._onDidChangeTreeData.event;
|
||||
@@ -50,7 +57,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
await vscode.commands.executeCommand('setContext', 'unsavedBooks', this._openAsUntitled);
|
||||
await Promise.all(workspaceFolders.map(async (workspaceFolder) => {
|
||||
try {
|
||||
await this.createAndAddBookModel(workspaceFolder.uri.fsPath);
|
||||
await this.loadNotebooksInFolder(workspaceFolder.uri.fsPath);
|
||||
} catch {
|
||||
// no-op, not all workspace folders are going to be valid books
|
||||
}
|
||||
@@ -97,41 +104,56 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
}
|
||||
}
|
||||
|
||||
async openBook(bookPath: string, urlToOpen?: string): Promise<void> {
|
||||
async openBook(bookPath: string, urlToOpen?: string, showPreview?: boolean, isNotebook?: boolean): Promise<void> {
|
||||
try {
|
||||
let books: BookModel[] = this.books.filter(book => book.bookPath === bookPath) || [];
|
||||
// Convert path to posix style for easier comparisons
|
||||
bookPath = bookPath.replace(/\\/g, '/');
|
||||
|
||||
// Check if the book is already open in viewlet.
|
||||
if (books.length > 0 && books[0].bookItems.length > 0) {
|
||||
this.currentBook = books[0];
|
||||
await this.showPreviewFile(urlToOpen);
|
||||
}
|
||||
else {
|
||||
await this.createAndAddBookModel(bookPath);
|
||||
let existingBook = this.books.find(book => book.bookPath === bookPath);
|
||||
if (existingBook?.bookItems.length > 0) {
|
||||
this.currentBook = existingBook;
|
||||
} else {
|
||||
await this.createAndAddBookModel(bookPath, isNotebook);
|
||||
let bookViewer = vscode.window.createTreeView(this.viewId, { showCollapseAll: true, treeDataProvider: this });
|
||||
this.currentBook = this.books.filter(book => book.bookPath === bookPath)[0];
|
||||
this.currentBook = this.books.find(book => book.bookPath === bookPath);
|
||||
bookViewer.reveal(this.currentBook.bookItems[0], { expand: vscode.TreeItemCollapsibleState.Expanded, focus: true, select: true });
|
||||
}
|
||||
|
||||
if (showPreview) {
|
||||
await this.showPreviewFile(urlToOpen);
|
||||
}
|
||||
|
||||
// add file watcher on toc file.
|
||||
fsw.watch(path.join(bookPath, '_data', 'toc.yml'), async (event, filename) => {
|
||||
if (event === 'change') {
|
||||
let index = this.books.findIndex(book => book.bookPath === bookPath);
|
||||
await this.books[index].initializeContents().then(() => {
|
||||
this._onDidChangeTreeData.fire(this.books[index].bookItems[0]);
|
||||
});
|
||||
this._onDidChangeTreeData.fire();
|
||||
}
|
||||
});
|
||||
if (!isNotebook) {
|
||||
fs.watchFile(path.join(bookPath, '_data', 'toc.yml'), async (curr, prev) => {
|
||||
if (curr.mtime > prev.mtime) {
|
||||
let book = this.books.find(book => book.bookPath === bookPath);
|
||||
if (book) {
|
||||
this.fireBookRefresh(book);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
vscode.window.showErrorMessage(loc.openFileError(bookPath, e instanceof Error ? e.message : e));
|
||||
}
|
||||
}
|
||||
|
||||
@debounce(1500)
|
||||
async fireBookRefresh(book: BookModel): Promise<void> {
|
||||
await book.initializeContents().then(() => {
|
||||
this._onDidChangeTreeData.fire();
|
||||
});
|
||||
}
|
||||
|
||||
async closeBook(book: BookTreeItem): Promise<void> {
|
||||
// remove book from the saved books
|
||||
let deletedBook: BookModel;
|
||||
try {
|
||||
let index: number = this.books.indexOf(this.books.find(b => b.bookPath.replace(/\\/g, '/') === book.root));
|
||||
let targetPath = book.book.type === BookTreeItemType.Book ? book.root : book.book.contentPath;
|
||||
let targetBook = this.books.find(b => b.bookPath === targetPath);
|
||||
let index: number = this.books.indexOf(targetBook);
|
||||
if (index > -1) {
|
||||
deletedBook = this.books.splice(index, 1)[0];
|
||||
if (this.currentBook === deletedBook) {
|
||||
@@ -143,8 +165,8 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
vscode.window.showErrorMessage(loc.closeBookError(book.root, e instanceof Error ? e.message : e));
|
||||
} finally {
|
||||
// remove watch on toc file.
|
||||
if (deletedBook) {
|
||||
fsw.unwatchFile(path.join(deletedBook.bookPath, '_data', 'toc.yml'));
|
||||
if (deletedBook && !deletedBook.isNotebook) {
|
||||
fs.unwatchFile(path.join(deletedBook.bookPath, '_data', 'toc.yml'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,8 +176,8 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
* were able to successfully parse it.
|
||||
* @param bookPath The path to the book folder to create the model for
|
||||
*/
|
||||
private async createAndAddBookModel(bookPath: string): Promise<void> {
|
||||
const book: BookModel = new BookModel(bookPath, this._openAsUntitled, this._extensionContext);
|
||||
private async createAndAddBookModel(bookPath: string, isNotebook: boolean): Promise<void> {
|
||||
const book: BookModel = new BookModel(bookPath, this._openAsUntitled, isNotebook, this._extensionContext);
|
||||
await book.initializeContents();
|
||||
this.books.push(book);
|
||||
if (!this.currentBook) {
|
||||
@@ -271,7 +293,7 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
canSelectFiles: false,
|
||||
canSelectMany: false,
|
||||
canSelectFolders: true,
|
||||
openLabel: loc.labelPickFolder
|
||||
openLabel: loc.labelSelectFolder
|
||||
});
|
||||
if (uris && uris.length > 0) {
|
||||
let pickedFolder = uris[0];
|
||||
@@ -305,11 +327,20 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
}
|
||||
|
||||
public async searchJupyterBooks(treeItem?: BookTreeItem): Promise<void> {
|
||||
if (this.currentBook && this.currentBook.bookPath) {
|
||||
let folderToSearch = this.currentBook.bookPath;
|
||||
if (treeItem && treeItem.uri) {
|
||||
folderToSearch = path.join(folderToSearch, Content, path.dirname(treeItem.uri));
|
||||
let folderToSearch: string;
|
||||
if (treeItem && treeItem.book.type !== BookTreeItemType.Notebook) {
|
||||
if (treeItem.uri) {
|
||||
folderToSearch = path.join(treeItem.root, Content, path.dirname(treeItem.uri));
|
||||
} else {
|
||||
folderToSearch = path.join(treeItem.root, Content);
|
||||
}
|
||||
} else if (this.currentBook && !this.currentBook.isNotebook) {
|
||||
folderToSearch = path.join(this.currentBook.bookPath, Content);
|
||||
} else {
|
||||
vscode.window.showErrorMessage(loc.noBooksSelectedError);
|
||||
}
|
||||
|
||||
if (folderToSearch) {
|
||||
let filesToIncludeFiltered = path.join(folderToSearch, '**', '*.md') + ',' + path.join(folderToSearch, '**', '*.ipynb');
|
||||
vscode.commands.executeCommand('workbench.action.findInFiles', { filesToInclude: filesToIncludeFiltered, query: '' });
|
||||
}
|
||||
@@ -328,10 +359,58 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
});
|
||||
if (uris && uris.length > 0) {
|
||||
let bookPath = uris[0];
|
||||
await this.openBook(bookPath.fsPath);
|
||||
await this.openBook(bookPath.fsPath, undefined, true);
|
||||
}
|
||||
}
|
||||
|
||||
public async openNotebookFolder(): Promise<void> {
|
||||
const allFilesFilter = loc.allFiles;
|
||||
let filter: any = {};
|
||||
filter[allFilesFilter] = '*';
|
||||
let uris = await vscode.window.showOpenDialog({
|
||||
filters: filter,
|
||||
canSelectFiles: false,
|
||||
canSelectMany: false,
|
||||
canSelectFolders: true,
|
||||
openLabel: loc.labelSelectFolder
|
||||
});
|
||||
if (uris && uris.length > 0) {
|
||||
await this.loadNotebooksInFolder(uris[0]?.fsPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadNotebooksInFolder(folderPath: string) {
|
||||
let bookCollection = await this.getNotebooksInTree(folderPath);
|
||||
for (let i = 0; i < bookCollection.bookPaths.length; i++) {
|
||||
await this.openBook(bookCollection.bookPaths[i], undefined, false);
|
||||
}
|
||||
for (let i = 0; i < bookCollection.notebookPaths.length; i++) {
|
||||
await this.openBook(bookCollection.notebookPaths[i], undefined, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
private async getNotebooksInTree(folderPath: string): Promise<BookSearchResults> {
|
||||
let notebookConfig = vscode.workspace.getConfiguration(constants.notebookConfigKey);
|
||||
let maxDepth = notebookConfig[constants.maxBookSearchDepth];
|
||||
// Use default value if user enters an invalid value
|
||||
if (isNullOrUndefined(maxDepth) || maxDepth < 0) {
|
||||
maxDepth = 10;
|
||||
} else if (maxDepth === 0) { // No limit of search depth if user enters 0
|
||||
maxDepth = undefined;
|
||||
}
|
||||
|
||||
let escapedPath = glob.escapePath(folderPath.replace(/\\/g, '/'));
|
||||
let bookFilter = path.posix.join(escapedPath, '**', '_data', 'toc.yml');
|
||||
let bookPaths = await glob(bookFilter, { deep: maxDepth });
|
||||
let tocTrimLength = '/_data/toc.yml'.length * -1;
|
||||
bookPaths = bookPaths.map(path => path.slice(0, tocTrimLength));
|
||||
|
||||
let notebookFilter = path.posix.join(escapedPath, '**', '*.ipynb');
|
||||
let notebookPaths = await glob(notebookFilter, { ignore: bookPaths.map(path => glob.escapePath(path) + '/**/*.ipynb'), deep: maxDepth });
|
||||
|
||||
return { notebookPaths: notebookPaths, bookPaths: bookPaths };
|
||||
}
|
||||
|
||||
private runThrottledAction(resource: string, action: () => void) {
|
||||
const isResourceChange = resource !== this._resource;
|
||||
if (isResourceChange) {
|
||||
@@ -378,11 +457,11 @@ export class BookTreeViewProvider implements vscode.TreeDataProvider<BookTreeIte
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
} else {
|
||||
let booksitems: BookTreeItem[] = [];
|
||||
let bookItems: BookTreeItem[] = [];
|
||||
this.books.map(book => {
|
||||
booksitems = booksitems.concat(book.bookItems);
|
||||
bookItems = bookItems.concat(book.bookItems);
|
||||
});
|
||||
return Promise.resolve(booksitems);
|
||||
return Promise.resolve(bookItems);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export const msgSampleCodeDataFrame = localize('msgSampleCodeDataFrame', "This s
|
||||
|
||||
// Book view-let constants
|
||||
export const allFiles = localize('allFiles', "All Files");
|
||||
export const labelPickFolder = localize('labelPickFolder', "Pick Folder");
|
||||
export const labelSelectFolder = localize('labelSelectFolder', "Select Folder");
|
||||
export const labelBookFolder = localize('labelBookFolder', "Select Book");
|
||||
export const confirmReplace = localize('confirmReplace', "Folder already exists. Are you sure you want to delete and replace this folder?");
|
||||
export const openNotebookCommand = localize('openNotebookCommand', "Open Notebook");
|
||||
@@ -25,7 +25,8 @@ export const msgBookTrusted = localize('msgBookTrusted', "Book is now trusted in
|
||||
export const msgBookAlreadyTrusted = localize('msgBookAlreadyTrusted', "Book is already trusted in this workspace.");
|
||||
export const msgBookUntrusted = localize('msgBookUntrusted', "Book is no longer trusted in this workspace");
|
||||
export const msgBookAlreadyUntrusted = localize('msgBookAlreadyUntrusted', "Book is already untrusted in this workspace.");
|
||||
export const missingTocError = localize('bookInitializeFailed', "Failed to find a toc.yml.");
|
||||
export const missingTocError = localize('bookInitializeFailed', "Failed to find a Table of Contents file in the specified book.");
|
||||
export const noBooksSelectedError = localize('noBooksSelected', "No books are currently selected in the viewlet.");
|
||||
|
||||
export function missingFileError(title: string): string { return localize('missingFileError', "Missing file : {0}", title); }
|
||||
export function invalidTocFileError(): string { return localize('InvalidError.tocFile', "Invalid toc file"); }
|
||||
|
||||
@@ -262,3 +262,35 @@ export function getIgnoreSslVerificationConfigSetting(): boolean {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function debounce(delay: number): Function {
|
||||
return decorate((fn, key) => {
|
||||
const timerKey = `$debounce$${key}`;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
clearTimeout(this[timerKey]);
|
||||
this[timerKey] = setTimeout(() => fn.apply(this, args), delay);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function decorate(decorator: (fn: Function, key: string) => Function): Function {
|
||||
return (_target: any, key: string, descriptor: any) => {
|
||||
let fnKey: string | null = null;
|
||||
let fn: Function | null = null;
|
||||
|
||||
if (typeof descriptor.value === 'function') {
|
||||
fnKey = 'value';
|
||||
fn = descriptor.value;
|
||||
} else if (typeof descriptor.get === 'function') {
|
||||
fnKey = 'get';
|
||||
fn = descriptor.get;
|
||||
}
|
||||
|
||||
if (!fn || !fnKey) {
|
||||
throw new Error('not supported');
|
||||
}
|
||||
|
||||
descriptor[fnKey] = decorator(fn, key);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type ChooseCellType = { label: string, id: CellType };
|
||||
|
||||
export async function activate(extensionContext: vscode.ExtensionContext): Promise<IExtensionApi> {
|
||||
const createBookPath: string = path.posix.join(extensionContext.extensionPath, 'resources', 'notebooks', 'JupyterBooksCreate.ipynb');
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openBook', (bookPath: string, openAsUntitled: boolean, urlToOpen?: string) => openAsUntitled ? untitledBookTreeViewProvider.openBook(bookPath, urlToOpen) : bookTreeViewProvider.openBook(bookPath, urlToOpen)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openBook', (bookPath: string, openAsUntitled: boolean, urlToOpen?: string) => openAsUntitled ? untitledBookTreeViewProvider.openBook(bookPath, urlToOpen, true) : bookTreeViewProvider.openBook(bookPath, urlToOpen, true)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openNotebook', (resource) => bookTreeViewProvider.openNotebook(resource)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openUntitledNotebook', (resource) => untitledBookTreeViewProvider.openNotebookAsUntitled(resource)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('bookTreeView.openMarkdown', (resource) => bookTreeViewProvider.openMarkdown(resource)));
|
||||
@@ -41,6 +41,8 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.searchUntitledBook', () => untitledBookTreeViewProvider.searchJupyterBooks()));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.openBook', () => bookTreeViewProvider.openNewBook()));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.closeBook', (book: any) => bookTreeViewProvider.closeBook(book)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.closeNotebook', (book: any) => bookTreeViewProvider.closeBook(book)));
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.openNotebookFolder', () => bookTreeViewProvider.openNotebookFolder()));
|
||||
|
||||
extensionContext.subscriptions.push(vscode.commands.registerCommand('notebook.command.createBook', async () => {
|
||||
let untitledFileName: vscode.Uri = vscode.Uri.parse(`untitled:${createBookPath}`);
|
||||
|
||||
@@ -625,7 +625,7 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
|
||||
let versionSpecifier = useMinVersion ? '>=' : '==';
|
||||
let packagesStr = packages.map(pkg => `"${pkg.name}${versionSpecifier}${pkg.version}"`).join(' ');
|
||||
let condaExe = this.getCondaExePath();
|
||||
let cmd = `"${condaExe}" install -y ${packagesStr}`;
|
||||
let cmd = `"${condaExe}" install -c conda-forge -y ${packagesStr}`;
|
||||
return this.executeStreamedCommand(cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -235,10 +235,9 @@ describe('BookTreeViewProviderTests', function () {
|
||||
});
|
||||
|
||||
it('should ignore toc.yml files not in _data folder', async () => {
|
||||
await bookTreeViewProvider.currentBook.getTableOfContentFiles(rootFolderPath);
|
||||
for (let p of bookTreeViewProvider.currentBook.tableOfContentPaths) {
|
||||
should(p.toLocaleLowerCase()).equal(tableOfContentsFile.replace(/\\/g, '/').toLocaleLowerCase());
|
||||
}
|
||||
await bookTreeViewProvider.currentBook.loadTableOfContentFiles(rootFolderPath);
|
||||
let path = bookTreeViewProvider.currentBook.tableOfContentsPath;
|
||||
should(path.toLocaleLowerCase()).equal(tableOfContentsFile.replace(/\\/g, '/').toLocaleLowerCase());
|
||||
});
|
||||
|
||||
this.afterAll(async function (): Promise<void> {
|
||||
|
||||
@@ -53,6 +53,7 @@ describe('BookTrustManagerTests', function () {
|
||||
|
||||
// Mock Book Data
|
||||
let bookTreeItemFormat1: BookTreeItemFormat = {
|
||||
contentPath: undefined,
|
||||
root: '/temp/SubFolder/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
@@ -72,6 +73,7 @@ describe('BookTrustManagerTests', function () {
|
||||
};
|
||||
|
||||
let bookTreeItemFormat2: BookTreeItemFormat = {
|
||||
contentPath: undefined,
|
||||
root: '/temp/SubFolder2/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
@@ -88,6 +90,7 @@ describe('BookTrustManagerTests', function () {
|
||||
};
|
||||
|
||||
let bookTreeItemFormat3: BookTreeItemFormat = {
|
||||
contentPath: undefined,
|
||||
root: '/temp2/SubFolder3/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
@@ -206,6 +209,7 @@ describe('BookTrustManagerTests', function () {
|
||||
apiWrapperMock.setup(api => api.getWorkspaceFolders()).returns(() => []);
|
||||
apiWrapperMock.setup(api => api.getConfiguration(TypeMoq.It.isValue(constants.notebookConfigKey))).returns(() => workspaceConfigurtionMock.object);
|
||||
let bookTreeItemFormat1: BookTreeItemFormat = {
|
||||
contentPath: undefined,
|
||||
root: '/temp/SubFolder/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
@@ -225,6 +229,7 @@ describe('BookTrustManagerTests', function () {
|
||||
};
|
||||
|
||||
let bookTreeItemFormat2: BookTreeItemFormat = {
|
||||
contentPath: undefined,
|
||||
root: '/temp/SubFolder2/',
|
||||
tableOfContents: {
|
||||
sections: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"dom"
|
||||
],
|
||||
|
||||
@@ -24,7 +24,7 @@ panel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical>.title {
|
||||
.tabbedPanel.vertical > .title {
|
||||
flex: 0 0 auto;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
@@ -41,7 +41,6 @@ panel {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
justify-content: flex-start;
|
||||
line-height: 35px;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
@@ -50,17 +49,19 @@ panel {
|
||||
.tabbedPanel .tabList .tab {
|
||||
cursor: pointer;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
|
||||
.tabbedPanel.horizontal .tabList .tab .tabLabel {
|
||||
.tabbedPanel.horizontal > .title .tabList .tab .tabLabel {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical .tabList .tab .tabLabel {
|
||||
.tabbedPanel.vertical >.title .tabList .tab .tabLabel {
|
||||
font-size: 13px;
|
||||
padding-bottom: 0px;
|
||||
font-weight: normal;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .tab .tabLabel {
|
||||
@@ -69,6 +70,14 @@ panel {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tabbedPanel.horizontal > .title .tabList .tab .tabLabel,
|
||||
.tabbedPanel.vertical > .title .tabList .tab .tabLabel {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
border: 0px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tabbedPanel .tabList .tab-header {
|
||||
display: flex;
|
||||
padding-left: 5px;
|
||||
@@ -124,23 +133,29 @@ panel {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical>.title {
|
||||
.tabbedPanel.vertical > .title {
|
||||
flex: 0 0 auto;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tabbedPanel>.tab-content {
|
||||
.tabbedPanel > .tab-content {
|
||||
flex: 1 1 auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabbedPanel.vertical>.title > .tabContainer .tabList {
|
||||
.tabbedPanel.vertical > .title > .tabContainer .tabList {
|
||||
flex-flow: column;
|
||||
height: calc(100% - 35px);
|
||||
overflow: auto;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.tabbedPanel.horizontal > .title > .tabContainer .tabList {
|
||||
flex-flow: row;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.tabbedPanel > .title > .tabContainer > .monaco-scrollable-element {
|
||||
|
||||
@@ -58,7 +58,7 @@ let idPool = 0;
|
||||
<div *ngIf="options.layout === NavigationBarLayout.vertical" class="vertical-tab-action-container">
|
||||
<button [attr.aria-expanded]="_tabExpanded" [title]="toggleTabPanelButtonAriaLabel" [attr.aria-label]="toggleTabPanelButtonAriaLabel" [ngClass]="toggleTabPanelButtonCssClass" tabindex="0" (click)="toggleTabPanel()"></button>
|
||||
</div>
|
||||
<div [style.display]="_tabExpanded ? 'flex': 'none'" [attr.aria-hidden]="_tabExpanded ? 'false': 'true'" class="tabList" role="tablist" scrollable [horizontalScroll]="AutoScrollbarVisibility" [verticalScroll]="HiddenScrollbarVisibility" [scrollYToX]="true" (keydown)="onKey($event)">
|
||||
<div [style.display]="_tabExpanded ? 'flex': 'none'" [attr.aria-hidden]="_tabExpanded ? 'false': 'true'" class="tabList" role="tablist" (keydown)="onKey($event)">
|
||||
<div role="presentation" *ngFor="let tab of _tabs">
|
||||
<ng-container *ngIf="tab.type!=='group-header'">
|
||||
<tab-header role="presentation" [active]="_activeTab === tab" [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'></tab-header>
|
||||
|
||||
@@ -20,14 +20,11 @@ import { CloseTabAction } from 'sql/base/browser/ui/panel/tabActions';
|
||||
selector: 'tab-header',
|
||||
template: `
|
||||
<div #actionHeader role="tab" [attr.aria-selected]="tab.active" [attr.aria-label]="tab.title" class="tab-header" style="flex: 0 0; flex-direction: row;" [class.active]="tab.active" tabindex="0" (click)="selectTab(tab)" (keyup)="onKey($event)">
|
||||
<span class="tab" role="presentation">
|
||||
<div role="presentation">
|
||||
<a #tabIcon></a>
|
||||
<a class="tabLabel" [class.active]="tab.active" #tabLabel>
|
||||
</a>
|
||||
</div>
|
||||
</span>
|
||||
<span #actionbar style="flex: 0 0 auto; align-self: end; margin-top: auto; margin-bottom: auto;" ></span>
|
||||
<div class="tab" role="presentation">
|
||||
<a #tabIcon></a>
|
||||
<a class="tabLabel" [class.active]="tab.active" [title]="tab.title" #tabLabel></a>
|
||||
</div>
|
||||
<div #actionbar style="flex: 0 0 auto; align-self: end; margin-top: auto; margin-bottom: auto;" ></div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
|
||||
3
src/sql/media/icons/chevron_down.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.1484 3.64844L15.8516 4.35156L8 12.2031L0.148438 4.35156L0.851562 3.64844L8 10.7969L15.1484 3.64844Z" fill="#4F4F4F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 234 B |
3
src/sql/media/icons/chevron_down_inverse.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.1484 3.64844L15.8516 4.35156L8 12.2031L0.148438 4.35156L0.851562 3.64844L8 10.7969L15.1484 3.64844Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 232 B |
3
src/sql/media/icons/chevron_up.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.2734 11.9766L8 4.71094L0.726562 11.9766L0.0234375 11.2734L8 3.28906L15.9766 11.2734L15.2734 11.9766Z" fill="#4F4F4F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 235 B |
3
src/sql/media/icons/chevron_up_inverse.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.2734 11.9766L8 4.71094L0.726562 11.9766L0.0234375 11.2734L8 3.28906L15.9766 11.2734L15.2734 11.9766Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 233 B |
3
src/sql/media/icons/close-blue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.525 5.925L11.85 11.25L11.25 11.85L5.925 6.525L0.6 11.85L0 11.25L5.325 5.925L0 0.6L0.6 0L5.925 5.325L11.25 0L11.85 0.6L6.525 5.925Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 264 B |
@@ -278,6 +278,119 @@
|
||||
background-image: url('stop_inverse.svg')
|
||||
}
|
||||
|
||||
/* Notebook cells */
|
||||
.codicon.toolbarIconRunInactive {
|
||||
background-image: url('execute_cell_grey.svg');
|
||||
}
|
||||
.codicon.toolbarIconRun {
|
||||
background-image: url('execute_cell.svg');
|
||||
}
|
||||
.codicon.toolbarIconRunError {
|
||||
background-image: url('execute_cell_error.svg');
|
||||
}
|
||||
.codicon.toolbarIconStop {
|
||||
background-image: url('stop_cell_solidanimation.svg');
|
||||
}
|
||||
.vs-dark .codicon.toolbarIconRunInactive {
|
||||
background-image: url('execute_cell_dark.svg');
|
||||
}
|
||||
.vs-dark .codicon.toolbarIconRun {
|
||||
background-image: url('execute_cell_white.svg');
|
||||
}
|
||||
.hc-black .codicon.toolbarIconRunInactive {
|
||||
background-image: url('execute_cell_hc.svg');
|
||||
}
|
||||
.hc-black .codicon.toolbarIconRun {
|
||||
background-image: url('execute_cell_orange_hc.svg');
|
||||
}
|
||||
.vs-dark .codicon.toolbarIconStop,
|
||||
.hc-black .codicon.toolbarIconStop {
|
||||
background-image: url('stop_cell_solidanimation_inverse.svg');
|
||||
}
|
||||
|
||||
.codicon.arrow-up {
|
||||
background-image: url("chevron_up.svg");
|
||||
}
|
||||
.vs-dark .codicon.arrow-up,
|
||||
.hc-black .codicon.arrow-up {
|
||||
background-image: url("chevron_up_inverse.svg");
|
||||
}
|
||||
|
||||
.codicon.arrow-down {
|
||||
background-image: url("chevron_down.svg");
|
||||
}
|
||||
.vs-dark .codicon.arrow-down,
|
||||
.hc-black .codicon.arrow-down {
|
||||
background-image: url("chevron_down_inverse.svg");
|
||||
}
|
||||
|
||||
/* Icons as masked elements for easy theme switching */
|
||||
.codicon.bold {
|
||||
-webkit-mask-image: url('toolbar-bold.svg');
|
||||
mask-image: url('toolbar-bold.svg');
|
||||
}
|
||||
.codicon.italic {
|
||||
-webkit-mask-image: url('toolbar-italic.svg');
|
||||
mask-image: url('toolbar-italic.svg');
|
||||
}
|
||||
.codicon.highlight {
|
||||
-webkit-mask-image: url('toolbar-highlight.svg');
|
||||
mask-image: url('toolbar-highlight.svg');
|
||||
}
|
||||
.codicon.code {
|
||||
-webkit-mask-image: url('toolbar-code.svg');
|
||||
mask-image: url('toolbar-code.svg');
|
||||
}
|
||||
.codicon.insert-link {
|
||||
-webkit-mask-image: url('toolbar-link.svg');
|
||||
mask-image: url('toolbar-link.svg');
|
||||
}
|
||||
.codicon.list {
|
||||
-webkit-mask-image: url('toolbar-list.svg');
|
||||
mask-image: url('toolbar-list.svg');
|
||||
}
|
||||
.codicon.ordered-list {
|
||||
-webkit-mask-image: url('toolbar-ordered-list.svg');
|
||||
mask-image: url('toolbar-ordered-list.svg');
|
||||
}
|
||||
.codicon.insert-image {
|
||||
-webkit-mask-image: url('toolbar-image.svg');
|
||||
mask-image: url('toolbar-image.svg');
|
||||
}
|
||||
.codicon.split-toggle-on {
|
||||
-webkit-mask-image: url('toolbar-preview-toggle-on.svg');
|
||||
mask-image: url('toolbar-preview-toggle-on.svg');
|
||||
}
|
||||
.codicon.split-toggle-off {
|
||||
-webkit-mask-image: url('toolbar-preview-toggle-off.svg');
|
||||
mask-image: url('toolbar-preview-toggle-off.svg');
|
||||
}
|
||||
|
||||
/* Cell toolbar icons */
|
||||
.cell-tool-close {
|
||||
background-image: url('close-blue.svg');
|
||||
}
|
||||
.cell-tool-edit {
|
||||
background-image: url('edit.svg');
|
||||
}
|
||||
.cell-tool-add {
|
||||
background-image: url('new-blue.svg');
|
||||
}
|
||||
.cell-tool-move-up {
|
||||
background-image: url('down-arrow-blue.svg');
|
||||
transform: scale(-1);
|
||||
}
|
||||
.cell-tool-move-down {
|
||||
background-image: url('down-arrow-blue.svg');
|
||||
}
|
||||
.cell-tool-delete {
|
||||
background-image: url('garbage-can-blue.svg');
|
||||
}
|
||||
.cell-tool-more {
|
||||
background-image: url('ellipsis-blue.svg');
|
||||
}
|
||||
|
||||
|
||||
.small {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
3
src/sql/media/icons/down-arrow-blue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.3506 8.60156L7.99902 15.9531L0.647461 8.60156L1.35059 7.89844L7.49902 14.0469V0H8.49902V14.0469L14.6475 7.89844L15.3506 8.60156Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 263 B |
3
src/sql/media/icons/ellipsis-blue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="14" height="2" viewBox="0 0 14 2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 0C1.14062 0 1.27083 0.0260417 1.39062 0.078125C1.51042 0.130208 1.61458 0.203125 1.70312 0.296875C1.79688 0.385417 1.86979 0.489583 1.92188 0.609375C1.97396 0.729167 2 0.859375 2 1C2 1.14062 1.97396 1.27083 1.92188 1.39062C1.86979 1.51042 1.79688 1.61719 1.70312 1.71094C1.61458 1.79948 1.51042 1.86979 1.39062 1.92188C1.27083 1.97396 1.14062 2 1 2C0.859375 2 0.729167 1.97396 0.609375 1.92188C0.489583 1.86979 0.382812 1.79948 0.289062 1.71094C0.200521 1.61719 0.130208 1.51042 0.078125 1.39062C0.0260417 1.27083 0 1.14062 0 1C0 0.859375 0.0260417 0.729167 0.078125 0.609375C0.130208 0.489583 0.200521 0.385417 0.289062 0.296875C0.382812 0.203125 0.489583 0.130208 0.609375 0.078125C0.729167 0.0260417 0.859375 0 1 0ZM7 0C7.14062 0 7.27083 0.0260417 7.39062 0.078125C7.51042 0.130208 7.61458 0.203125 7.70312 0.296875C7.79688 0.385417 7.86979 0.489583 7.92188 0.609375C7.97396 0.729167 8 0.859375 8 1C8 1.14062 7.97396 1.27083 7.92188 1.39062C7.86979 1.51042 7.79688 1.61719 7.70312 1.71094C7.61458 1.79948 7.51042 1.86979 7.39062 1.92188C7.27083 1.97396 7.14062 2 7 2C6.85938 2 6.72917 1.97396 6.60938 1.92188C6.48958 1.86979 6.38281 1.79948 6.28906 1.71094C6.20052 1.61719 6.13021 1.51042 6.07812 1.39062C6.02604 1.27083 6 1.14062 6 1C6 0.859375 6.02604 0.729167 6.07812 0.609375C6.13021 0.489583 6.20052 0.385417 6.28906 0.296875C6.38281 0.203125 6.48958 0.130208 6.60938 0.078125C6.72917 0.0260417 6.85938 0 7 0ZM13 0C13.1406 0 13.2708 0.0260417 13.3906 0.078125C13.5104 0.130208 13.6146 0.203125 13.7031 0.296875C13.7969 0.385417 13.8698 0.489583 13.9219 0.609375C13.974 0.729167 14 0.859375 14 1C14 1.14062 13.974 1.27083 13.9219 1.39062C13.8698 1.51042 13.7969 1.61719 13.7031 1.71094C13.6146 1.79948 13.5104 1.86979 13.3906 1.92188C13.2708 1.97396 13.1406 2 13 2C12.8594 2 12.7292 1.97396 12.6094 1.92188C12.4896 1.86979 12.3828 1.79948 12.2891 1.71094C12.2005 1.61719 12.1302 1.51042 12.0781 1.39062C12.026 1.27083 12 1.14062 12 1C12 0.859375 12.026 0.729167 12.0781 0.609375C12.1302 0.489583 12.2005 0.385417 12.2891 0.296875C12.3828 0.203125 12.4896 0.130208 12.6094 0.078125C12.7292 0.0260417 12.8594 0 13 0Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
4
src/sql/media/icons/execute_cell.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#0078D4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 392 B |
4
src/sql/media/icons/execute_cell_dark.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#A19F9D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="#1B1A19"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 394 B |
1
src/sql/media/icons/execute_cell_error.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#d02e00;}.cls-2{fill:#fff;}</style></defs><title>execute_cell_error</title><circle class="cls-1" cx="8" cy="7.92" r="7.76"/><polygon class="cls-2" points="10.7 8 6.67 11 6.67 5 10.7 8 10.7 8"/></svg>
|
||||
|
After Width: | Height: | Size: 317 B |
4
src/sql/media/icons/execute_cell_grey.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#A19F9D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 392 B |
4
src/sql/media/icons/execute_cell_hc.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 21C16.5228 21 21 16.5228 21 11C21 5.47715 16.5228 1 11 1C5.47715 1 1 5.47715 1 11C1 16.5228 5.47715 21 11 21Z" stroke="#2B56F2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2972 10.9375L9 14.875V7L14.2972 10.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 396 B |
4
src/sql/media/icons/execute_cell_orange_hc.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 21C16.5228 21 21 16.5228 21 11C21 5.47715 16.5228 1 11 1C5.47715 1 1 5.47715 1 11C1 16.5228 5.47715 21 11 21Z" stroke="#E86E58"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2972 10.9375L9 14.875V7L14.2972 10.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 396 B |
4
src/sql/media/icons/execute_cell_white.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="#1B1A19"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 392 B |
3
src/sql/media/icons/garbage-can-blue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5 3.0001H12.5V14.5001C12.5146 14.7052 12.4803 14.9108 12.4 15.1001L12.1 15.6001L11.6 15.9001H2.4L1.9 15.6001L1.6 15.1001C1.51969 14.9108 1.48542 14.7052 1.5 14.5001V3.0001H0.5V2.0001H4.5V1.0001C4.48504 0.859138 4.52046 0.717432 4.6 0.600098L4.8 0.300098L5.1 0.100098H8.9L9.2 0.300098L9.4 0.600098C9.47954 0.717432 9.51496 0.859138 9.5 1.0001V2.0001H13.5V3.0001ZM11.5 3.0001H2.5V14.5001C2.48504 14.6411 2.52046 14.7828 2.6 14.9001H11.4C11.4795 14.7828 11.515 14.6411 11.5 14.5001V3.0001ZM5.5 13.0001H4.5V5.0001H5.5V13.0001ZM5.5 2.0001H8.5V1.0001H5.5V2.0001ZM7.5 13.0001H6.5V5.0001H7.5V13.0001ZM9.5 13.0001H8.5V5.0001H9.5V13.0001Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 763 B |
3
src/sql/media/icons/new-blue.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 6.53333V7.46667H7.46667V14H6.53333V7.46667H0V6.53333H6.53333V0H7.46667V6.53333H14Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 217 B |
16
src/sql/media/icons/stop_cell_solidanimation.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs><style>.cls-1{fill:#c1d6e6;}.cls-2{fill:#0078d4;}.cls-3{fill:#fff;}</style></defs>
|
||||
<title>stop_cell_solidanimation</title>
|
||||
<path class="cls-1" d="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM8,1a7,7,0,1,0,7,7A7,7,0,0,0,8,1Z"/>
|
||||
<path class="cls-2" d="M8.51,0v1A7,7,0,0,1,15,8a6.87,6.87,0,0,1-1.07,3.7l.81.64A7.92,7.92,0,0,0,16,8,8,8,0,0,0,8.51,0Z">
|
||||
<animateTransform attributeName="transform"
|
||||
type="rotate"
|
||||
from="0 8 8"
|
||||
to="360 8 8"
|
||||
begin="0s"
|
||||
dur="1.5s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</path>
|
||||
<circle cx="8" cy="8" r="6.32"/>
|
||||
<rect class="cls-3" x="4.91" y="4.91" width="6.18" height="6.18"/></svg>
|
||||
|
After Width: | Height: | Size: 766 B |
16
src/sql/media/icons/stop_cell_solidanimation_inverse.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<defs><style>.cls-1{fill:#c1d6e6;}.cls-2{fill:#0078d4;}.cls-3{fill:#fff;}</style></defs>
|
||||
<title>stop_cell_solidanimation_inverse</title>
|
||||
<path class="cls-1" d="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM8,1a7,7,0,1,0,7,7A7,7,0,0,0,8,1Z"/>
|
||||
<path class="cls-2" d="M8.51,0v1A7,7,0,0,1,15,8a6.87,6.87,0,0,1-1.07,3.7l.81.64A7.92,7.92,0,0,0,16,8,8,8,0,0,0,8.51,0Z">
|
||||
<animateTransform attributeName="transform"
|
||||
type="rotate"
|
||||
from="0 8 8"
|
||||
to="360 8 8"
|
||||
begin="0s"
|
||||
dur="1.5s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</path>
|
||||
<circle class="cls-3" cx="8" cy="8" r="6.32"/>
|
||||
<rect x="4.91" y="4.91" width="6.18" height="6.18"/></svg>
|
||||
|
After Width: | Height: | Size: 774 B |
4
src/sql/media/icons/toolbar-bold.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>bold</title>
|
||||
<path d="M5.80469 6.03906C6.28385 6.03906 6.73438 6.13021 7.15625 6.3125C7.58333 6.49479 7.95312 6.74479 8.26562 7.0625C8.58333 7.375 8.83333 7.74219 9.01562 8.16406C9.19792 8.58594 9.28906 9.03646 9.28906 9.51562C9.28906 9.99479 9.19792 10.4479 9.01562 10.875C8.83333 11.2969 8.58333 11.6667 8.26562 11.9844C7.95312 12.2969 7.58333 12.5443 7.15625 12.7266C6.73438 12.9089 6.28385 13 5.80469 13H0V0H5.80469C6.22135 0 6.61198 0.0807292 6.97656 0.242188C7.34115 0.398438 7.65885 0.614583 7.92969 0.890625C8.20573 1.16146 8.42188 1.47917 8.57812 1.84375C8.73958 2.20833 8.82031 2.59896 8.82031 3.01562C8.82031 3.43229 8.74219 3.82552 8.58594 4.19531C8.42969 4.5599 8.21354 4.88021 7.9375 5.15625C7.66667 5.42708 7.34635 5.64323 6.97656 5.80469C6.61198 5.96094 6.22135 6.03906 5.80469 6.03906ZM4.17969 1.85938H3V5.57031H4.17969C4.4349 5.57031 4.67448 5.52083 4.89844 5.42188C5.1276 5.32292 5.32552 5.1901 5.49219 5.02344C5.65885 4.85677 5.79167 4.66146 5.89062 4.4375C5.98958 4.20833 6.03906 3.96615 6.03906 3.71094C6.03906 3.45573 5.98958 3.21615 5.89062 2.99219C5.79167 2.76823 5.65885 2.57292 5.49219 2.40625C5.32552 2.23438 5.1276 2.10156 4.89844 2.00781C4.67448 1.90885 4.4349 1.85938 4.17969 1.85938ZM4.64062 11.1406C4.89583 11.1406 5.13542 11.0938 5.35938 11C5.58854 10.901 5.78646 10.7682 5.95312 10.6016C6.11979 10.4297 6.2526 10.2318 6.35156 10.0078C6.45052 9.78385 6.5 9.54427 6.5 9.28906C6.5 9.03385 6.45052 8.79427 6.35156 8.57031C6.25781 8.34115 6.125 8.14323 5.95312 7.97656C5.78646 7.80469 5.58854 7.67188 5.35938 7.57812C5.13542 7.47917 4.89583 7.42969 4.64062 7.42969H3V11.1406H4.64062Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
4
src/sql/media/icons/toolbar-code.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="9" viewBox="0 0 16 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>preformatted</title>
|
||||
<path d="M1.71094 5L3.3125 6.60156L3.02344 7.73438L0.289062 5L3.64844 1.64844L4.35156 2.35156L1.71094 5ZM15.7109 5L12.3516 8.35156L11.6484 7.64844L14.2891 5L13.125 3.83594C13.2604 3.70052 13.3828 3.57552 13.4922 3.46094C13.6016 3.34115 13.7005 3.21615 13.7891 3.08594L15.7109 5ZM11.4375 0C11.6562 0 11.8594 0.0390625 12.0469 0.117188C12.2396 0.195312 12.4062 0.304688 12.5469 0.445312C12.6875 0.585938 12.7969 0.75 12.875 0.9375C12.9583 1.125 13 1.32812 13 1.54688C13 1.75 12.9609 1.94792 12.8828 2.14062C12.8047 2.33333 12.6927 2.5026 12.5469 2.64844L6.94531 8.26562L4 9L4.73438 6.05469L10.3359 0.445312C10.4818 0.299479 10.651 0.190104 10.8438 0.117188C11.0365 0.0390625 11.2344 0 11.4375 0ZM11.8359 1.94531C11.9453 1.83594 12 1.70312 12 1.54688C12 1.38542 11.9453 1.25521 11.8359 1.15625C11.7318 1.05208 11.599 1 11.4375 1C11.3646 1 11.2943 1.01302 11.2266 1.03906C11.1589 1.0599 11.099 1.09635 11.0469 1.14844L5.64062 6.57031L5.375 7.625L6.42969 7.35938L11.8359 1.94531Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
4
src/sql/media/icons/toolbar-highlight.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>highlight</title>
|
||||
<path d="M13 0V3.25C12.6318 3.25 12.3166 3.2902 12.0542 3.37061C11.7918 3.45101 11.5697 3.56738 11.3877 3.71973C11.2057 3.87207 11.0576 4.04557 10.9434 4.24023C10.8291 4.4349 10.7424 4.65706 10.6831 4.90674C10.6239 5.15641 10.5837 5.41032 10.5625 5.66846C10.5413 5.9266 10.5308 6.19954 10.5308 6.4873C10.5308 6.7666 10.535 7.04378 10.5435 7.31885C10.5519 7.59391 10.5583 7.86263 10.5625 8.125H8.9375V10.5625L4.0625 13V8.125H2.4375C2.4375 7.86263 2.44173 7.59391 2.4502 7.31885C2.45866 7.04378 2.46501 6.7666 2.46924 6.4873C2.46924 6.20801 2.45866 5.93506 2.4375 5.66846C2.41634 5.40186 2.37614 5.14795 2.31689 4.90674C2.25765 4.66553 2.17301 4.44548 2.06299 4.24658C1.95296 4.04769 1.80485 3.87207 1.61865 3.71973C1.43245 3.56738 1.20817 3.45312 0.945801 3.37695C0.683431 3.30078 0.368164 3.25846 0 3.25V0H0.8125V2.4375H12.1875V0H13ZM8.125 8.125H4.875V11.686L8.125 10.061V8.125ZM9.75 7.3125C9.75 7.12207 9.74788 6.93587 9.74365 6.75391C9.73942 6.57194 9.7373 6.38997 9.7373 6.20801C9.7373 5.93717 9.74788 5.67057 9.76904 5.4082C9.7902 5.14583 9.83252 4.89193 9.896 4.64648C9.95947 4.40104 10.0568 4.15983 10.188 3.92285C10.3192 3.68587 10.4927 3.46159 10.7085 3.25H2.2915C2.50732 3.46582 2.67871 3.6901 2.80566 3.92285C2.93262 4.1556 3.02995 4.39681 3.09766 4.64648C3.16536 4.89616 3.2098 5.15006 3.23096 5.4082C3.25212 5.66634 3.2627 5.93294 3.2627 6.20801C3.2627 6.38997 3.26058 6.57194 3.25635 6.75391C3.25212 6.93587 3.25 7.12207 3.25 7.3125H9.75Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
4
src/sql/media/icons/toolbar-image.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>add inline image</title>
|
||||
<path d="M11 2.5C11 2.36458 11.0495 2.2474 11.1484 2.14844C11.2474 2.04948 11.3646 2 11.5 2C11.6354 2 11.7526 2.04948 11.8516 2.14844C11.9505 2.2474 12 2.36458 12 2.5C12 2.63542 11.9505 2.7526 11.8516 2.85156C11.7526 2.95052 11.6354 3 11.5 3C11.3646 3 11.2474 2.95052 11.1484 2.85156C11.0495 2.7526 11 2.63542 11 2.5ZM16 10V11H14V13H13V11H11V10H13V8H14V10H16ZM7.20312 7.5L10 10.2891V11H0V0H14V7H13V1H1V4.28906L2.5 2.79688L6.5 6.79688L8.5 4.79688L12 8.28906V9H11.2891L8.5 6.20312L7.20312 7.5ZM2.5 4.20312L1 5.71094V10H8.28906L2.5 4.20312Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 691 B |
4
src/sql/media/icons/toolbar-italic.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="11" height="13" viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>italics</title>
|
||||
<path d="M9.25 1H7.55469L3.89062 12H6.75L5.75 13H0.25L1.25 12H2.50781L6.17188 1H3.75L4.75 0H10.25L9.25 1Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 250 B |
4
src/sql/media/icons/toolbar-link.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>link</title>
|
||||
<path d="M7 7V6H8.1L9.1 5.5C9.38138 5.32024 9.62024 5.08138 9.8 4.8C9.93294 4.37949 10.0004 3.94103 10 3.5C9.98112 3.15886 9.91378 2.82215 9.8 2.5C9.6702 2.21199 9.50201 1.94288 9.3 1.7L8.5 1.2L7.5 1H3.5L2.5 1.2L1.7 1.7C1.49799 1.94288 1.3298 2.21199 1.2 2.5C1.08622 2.82215 1.01888 3.15886 1 3.5C1.00946 3.90746 1.0768 4.3115 1.2 4.7L1.9 5.4L2.9 5.9H4V7H3.5C3.01765 6.99754 2.54101 6.8954 2.1 6.7C1.69834 6.52684 1.32698 6.29051 1 6C0.709485 5.67302 0.473165 5.30166 0.3 4.9C0.104596 4.45899 0.00245968 3.98235 0 3.5C0.00245968 3.01765 0.104596 2.54101 0.3 2.1C0.473165 1.69834 0.709485 1.32698 1 1C1.32698 0.709485 1.69834 0.473165 2.1 0.3C2.54101 0.104596 3.01765 0.00245968 3.5 0L7.5 0C7.98235 0.00245968 8.45899 0.104596 8.9 0.3C9.30166 0.473165 9.67302 0.709485 10 1C10.2905 1.32698 10.5268 1.69834 10.7 2.1C10.8954 2.54101 10.9975 3.01765 11 3.5C10.9975 3.98235 10.8954 4.45899 10.7 4.9C10.5268 5.30166 10.2905 5.67302 10 6C9.67302 6.29051 9.30166 6.52684 8.9 6.7C8.45899 6.8954 7.98235 6.99754 7.5 7H7ZM12 3V4H13.1L14.1 4.5C14.3814 4.67976 14.6202 4.91862 14.8 5.2C14.9329 5.62051 15.0004 6.05897 15 6.5C14.9811 6.84114 14.9138 7.17785 14.8 7.5C14.6702 7.78801 14.502 8.05712 14.3 8.3L13.5 8.8L12.5 9H8.5L7.5 8.8L6.7 8.3C6.49799 8.05712 6.3298 7.78801 6.2 7.5C6.08622 7.17785 6.01888 6.84114 6 6.5C6.00946 6.09254 6.0768 5.6885 6.2 5.3C6.37976 5.01862 6.61862 4.77976 6.9 4.6L7.9 4.1H9V3H8.5C8.01765 3.00246 7.54101 3.1046 7.1 3.3C6.69834 3.47316 6.32698 3.70949 6 4C5.70949 4.32698 5.47316 4.69834 5.3 5.1C5.10121 5.53996 4.99839 6.01721 4.99839 6.5C4.99839 6.98279 5.10121 7.46004 5.3 7.9C5.47316 8.30166 5.70949 8.67302 6 9C6.32698 9.29051 6.69834 9.52684 7.1 9.7C7.54101 9.8954 8.01765 9.99754 8.5 10H12.5C12.9824 9.99754 13.459 9.8954 13.9 9.7C14.3017 9.52684 14.673 9.29051 15 9C15.2905 8.67302 15.5268 8.30166 15.7 7.9C15.8988 7.46004 16.0016 6.98279 16.0016 6.5C16.0016 6.01721 15.8988 5.53996 15.7 5.1C15.5268 4.69834 15.2905 4.32698 15 4C14.673 3.70949 14.3017 3.47316 13.9 3.3C13.459 3.1046 12.9824 3.00246 12.5 3H12Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
4
src/sql/media/icons/toolbar-list.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>unordered list</title>
|
||||
<path d="M0 7V6H1V7H0ZM0 4V3H1V4H0ZM3 4V3H16V4H3ZM0 1V0H1V1H0ZM3 0H16V1H3V0ZM3 7V6H16V7H3ZM0 10V9H1V10H0ZM3 10V9H16V10H3Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 273 B |
4
src/sql/media/icons/toolbar-ordered-list.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Ordered list</title>
|
||||
<path d="M16 2V3H4V2H16ZM4 6H16V7H4V6ZM4 10H16V11H4V10ZM1.05469 1.72656C0.981771 1.78385 0.882812 1.84115 0.757812 1.89844C0.638021 1.95052 0.528646 1.97656 0.429688 1.97656V1.4375C0.591146 1.38021 0.744792 1.31771 0.890625 1.25C1.03646 1.18229 1.17708 1.09635 1.3125 0.992188H1.69531V4H1.05469V1.72656ZM1.04688 5.00781C1.17708 5.00781 1.29948 5.02604 1.41406 5.0625C1.53385 5.09375 1.63542 5.14583 1.71875 5.21875C1.80729 5.28646 1.875 5.3724 1.92188 5.47656C1.97396 5.58073 2 5.70312 2 5.84375C2 6.00521 1.96875 6.14844 1.90625 6.27344C1.84375 6.39323 1.76562 6.5026 1.67188 6.60156C1.58333 6.69531 1.48438 6.78125 1.375 6.85938C1.26562 6.93229 1.16406 7.0026 1.07031 7.07031C0.981771 7.13281 0.90625 7.19792 0.84375 7.26562C0.78125 7.32812 0.75 7.39323 0.75 7.46094H2V8H0.0390625C0.0390625 7.88021 0.0390625 7.77344 0.0390625 7.67969C0.0442708 7.58594 0.0703125 7.48438 0.117188 7.375C0.195312 7.19792 0.302083 7.04948 0.4375 6.92969C0.572917 6.80469 0.705729 6.6901 0.835938 6.58594C0.971354 6.48177 1.08854 6.3776 1.1875 6.27344C1.28646 6.16927 1.33594 6.04688 1.33594 5.90625C1.33594 5.76562 1.29688 5.66667 1.21875 5.60938C1.14062 5.55208 1.03646 5.52344 0.90625 5.52344C0.770833 5.52344 0.640625 5.55208 0.515625 5.60938C0.395833 5.66667 0.283854 5.73958 0.179688 5.82812V5.25781C0.440104 5.09115 0.729167 5.00781 1.04688 5.00781ZM1.32812 10.4688C1.51562 10.4948 1.67448 10.5651 1.80469 10.6797C1.9349 10.7943 2 10.9531 2 11.1562C2 11.3177 1.96615 11.4557 1.89844 11.5703C1.83594 11.6849 1.7526 11.7786 1.64844 11.8516C1.54427 11.9193 1.42188 11.9714 1.28125 12.0078C1.14583 12.0391 1.00781 12.0547 0.867188 12.0547C0.742188 12.0547 0.614583 12.0443 0.484375 12.0234C0.359375 12.0026 0.239583 11.9635 0.125 11.9062V11.3359C0.223958 11.4089 0.330729 11.4635 0.445312 11.5C0.565104 11.5365 0.6875 11.5547 0.8125 11.5547C0.947917 11.5547 1.06771 11.526 1.17188 11.4688C1.28125 11.4115 1.33594 11.3047 1.33594 11.1484C1.33594 11.0339 1.30208 10.9505 1.23438 10.8984C1.16667 10.8411 1.08333 10.8021 0.984375 10.7812C0.890625 10.7552 0.791667 10.7422 0.6875 10.7422C0.583333 10.7422 0.494792 10.7422 0.421875 10.7422V10.2422C0.494792 10.2422 0.578125 10.2422 0.671875 10.2422C0.765625 10.2422 0.854167 10.2344 0.9375 10.2188C1.02604 10.1979 1.09896 10.1615 1.15625 10.1094C1.21875 10.0573 1.25 9.97656 1.25 9.86719C1.25 9.73177 1.20573 9.63802 1.11719 9.58594C1.03385 9.53385 0.932292 9.50781 0.8125 9.50781C0.609375 9.50781 0.416667 9.57031 0.234375 9.69531V9.16406C0.348958 9.10677 0.466146 9.06771 0.585938 9.04688C0.710938 9.02083 0.835938 9.00781 0.960938 9.00781C1.07552 9.00781 1.1901 9.02083 1.30469 9.04688C1.41927 9.07292 1.52083 9.11719 1.60938 9.17969C1.69792 9.23698 1.77083 9.3125 1.82812 9.40625C1.88542 9.5 1.91406 9.61198 1.91406 9.74219C1.91406 9.9401 1.86198 10.099 1.75781 10.2188C1.65885 10.3333 1.51562 10.4141 1.32812 10.4609V10.4688Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
4
src/sql/media/icons/toolbar-preview-toggle-off.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>markdown preview toggle - off</title>
|
||||
<path d="M15.5 0.5V13.5H0.5V0.5H15.5ZM1.5 1.5V3.5H14.5V1.5H1.5ZM14.5 12.5V4.5H1.5V12.5H14.5Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 259 B |
5
src/sql/media/icons/toolbar-preview-toggle-on.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>markdown preview toggle - on</title>
|
||||
<path d="M15 1V14H0V1H15ZM1 2V4H14V2H1ZM14 13V5H1V13H14Z" fill="black"/>
|
||||
<path d="M8 5H7V13H8V5Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 260 B |
@@ -60,15 +60,14 @@ export const DeleteAgentAlert = 'DeleteAgentAlert';
|
||||
export const DeleteAgentOperator = 'DeleteAgentOperator';
|
||||
export const DeleteAgentProxy = 'DeleteAgentProxy';
|
||||
|
||||
// Notebook Events:
|
||||
export const NotebookMarkdownRendered = 'NotebookMarkdownRendered';
|
||||
|
||||
export enum TelemetryView {
|
||||
Shell = 'Shell',
|
||||
ExtensionRecommendationDialog = 'ExtensionRecommendationDialog',
|
||||
ResultsPanel = 'ResultsPanel'
|
||||
ResultsPanel = 'ResultsPanel',
|
||||
Notebook = 'Notebook'
|
||||
}
|
||||
|
||||
export enum TelemetryAction {
|
||||
Click = 'Click'
|
||||
Click = 'Click',
|
||||
Open = 'Open'
|
||||
}
|
||||
|
||||
@@ -41,4 +41,20 @@ export const gradientOne = registerColor('gradientOne', { light: '#f0f0f0', dark
|
||||
export const gradientTwo = registerColor('gradientTwo', { light: gradientTwoColorOne, dark: gradientTwoColorTwo, hc: gradientTwoColorTwo }, nls.localize('gradientTwo', "The bottom color for the banner image gradient"));
|
||||
export const gradientBackground = registerColor('gradientBackground', { light: '#fff', dark: 'transparent', hc: 'transparent' }, nls.localize('gradientBackground', "The background color for the banner image gradient"));
|
||||
|
||||
// --- Notebook Colors
|
||||
export const toolbarBackground = registerColor('notebook.toolbarBackground', { light: '#F5F5F5', dark: '#252423', hc: '#000000' }, nls.localize('notebook.toolbarBackground', "Notebook: Markdown toolbar background"));
|
||||
export const toolbarIcon = registerColor('notebook.toolbarIcon', { light: '#323130', dark: '#FFFFFe', hc: '#FFFFFe' }, nls.localize('notebook.toolbarIcon', "Notebook: Markdown toolbar icons"));
|
||||
export const toolbarBottomBorder = registerColor('notebook.toolbarBottomBorder', { light: '#D4D4D4', dark: '#323130', hc: '#E86E58' }, nls.localize('notebook.toolbarBottomBorder', "Notebook: Markdown toolbar bottom border"));
|
||||
// Notebook: All cells
|
||||
export const cellBorder = registerColor('notebook.cellBorder', { light: '#0078D4', dark: '#0078D4', hc: '#E86E58' }, nls.localize('notebook.cellBorder', "Notebook: Active cell border"));
|
||||
// Notebook: Markdown cell
|
||||
export const markdownEditorBackground = registerColor('notebook.markdownEditorBackground', { light: '#FFFFFe', dark: '#1B1A19', hc: '#000000' }, nls.localize('notebook.markdownEditorBackground', "Notebook: Markdown editor background"));
|
||||
export const splitBorder = registerColor('notebook.splitBorder', { light: '#E6E6E6', dark: '#323130', hc: '#872412' }, nls.localize('notebook.splitBorder', "Notebook: Border between Markdown editor and preview"));
|
||||
|
||||
// Notebook: Code cell
|
||||
export const codeEditorBackground = registerColor('notebook.codeEditorBackground', { light: '#F5F5F5', dark: '#333333', hc: '#000000' }, nls.localize('notebook.codeEditorBackground', "Notebook: Code editor background"));
|
||||
export const codeEditorBackgroundActive = registerColor('notebook.codeEditorBackgroundActive', { light: '#FFFFFe', dark: null, hc: null }, nls.localize('notebook.codeEditorBackgroundActive', "Notebook: Code editor background of active cell"));
|
||||
export const codeEditorLineNumber = registerColor('notebook.codeEditorLineNumber', { light: '#A19F9D', dark: '#A19F9D', hc: '#FFFFFe' }, nls.localize('notebook.codeEditorLineNumber', "Notebook: Code editor line numbers"));
|
||||
export const codeEditorToolbarIcon = registerColor('notebook.codeEditorToolbarIcon', { light: '#999999', dark: '#A19F9D', hc: '#FFFFFe' }, nls.localize('notebook.codeEditorToolbarIcon', "Notebook: Code editor toolbar icons"));
|
||||
export const codeEditorToolbarBackground = registerColor('notebook.codeEditorToolbarBackground', { light: '#EEEEEE', dark: '#333333', hc: '#000000' }, nls.localize('notebook.codeEditorToolbarBackground', "Notebook: Code editor toolbar background"));
|
||||
export const codeEditorToolbarBorder = registerColor('notebook.codeEditorToolbarBorder', { light: '#C8C6C4', dark: '#333333', hc: '#000000' }, nls.localize('notebook.codeEditorToolbarBorder', "Notebook: Code editor toolbar right border"));
|
||||
|
||||
@@ -86,7 +86,7 @@ export class ChartView extends Disposable implements IPanelView {
|
||||
public readonly onOptionsChange: Event<IInsightOptions> = this._onOptionsChange.event;
|
||||
|
||||
constructor(
|
||||
private readonly _renderOptionsInline: boolean,
|
||||
private readonly _isQueryEditorChart: boolean,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@@ -102,15 +102,15 @@ export class ChartView extends Disposable implements IPanelView {
|
||||
this.typeControls = DOM.$('div.type-controls');
|
||||
this.optionsControl.appendChild(this.typeControls);
|
||||
|
||||
this._createInsightAction = this._instantiationService.createInstance(CreateInsightAction);
|
||||
this._copyAction = this._instantiationService.createInstance(CopyAction);
|
||||
this._saveAction = this._instantiationService.createInstance(SaveImageAction);
|
||||
|
||||
if (this._renderOptionsInline) {
|
||||
if (this._isQueryEditorChart) {
|
||||
this._createInsightAction = this._instantiationService.createInstance(CreateInsightAction);
|
||||
this.taskbar.setContent([{ action: this._createInsightAction }]);
|
||||
} else {
|
||||
this._configureChartAction = this._instantiationService.createInstance(ConfigureChartAction, this);
|
||||
this.taskbar.setContent([{ action: this._createInsightAction }, { action: this._configureChartAction }]);
|
||||
this.taskbar.setContent([{ action: this._configureChartAction }]);
|
||||
}
|
||||
|
||||
const self = this;
|
||||
@@ -177,7 +177,7 @@ export class ChartView extends Disposable implements IPanelView {
|
||||
this.container.appendChild(this.taskbarContainer);
|
||||
this.container.appendChild(this.chartingContainer);
|
||||
this.chartingContainer.appendChild(this.insightContainer);
|
||||
if (this._renderOptionsInline) {
|
||||
if (this._isQueryEditorChart) {
|
||||
this.chartingContainer.appendChild(this.optionsControl);
|
||||
}
|
||||
this.insight = new Insight(this.insightContainer, this._options, this._instantiationService);
|
||||
@@ -301,14 +301,15 @@ export class ChartView extends Disposable implements IPanelView {
|
||||
if (this.insight && this.insight.isCopyable) {
|
||||
this.taskbar.context = { insight: this.insight.insight, options: this._options };
|
||||
actions = [
|
||||
{ action: this._createInsightAction },
|
||||
{ action: this._copyAction },
|
||||
{ action: this._saveAction }
|
||||
];
|
||||
} else {
|
||||
actions = [{ action: this._createInsightAction }];
|
||||
actions = [];
|
||||
}
|
||||
if (!this._renderOptionsInline) {
|
||||
if (this._isQueryEditorChart) {
|
||||
actions.unshift({ action: this._createInsightAction });
|
||||
} else {
|
||||
actions.push({ action: this._configureChartAction });
|
||||
}
|
||||
this.taskbar.setContent(actions);
|
||||
|
||||
@@ -34,12 +34,12 @@ suite('Chart View', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function createChartView(renderOptions: boolean): ChartView {
|
||||
function createChartView(isQueryEditorChart: boolean): ChartView {
|
||||
const layoutService = new TestLayoutService();
|
||||
const contextViewService = new ContextViewService(layoutService);
|
||||
const themeService = new TestThemeService();
|
||||
const instantiationService = new TestInstantiationService();
|
||||
const notificationService = new TestNotificationService();
|
||||
instantiationService.stub(IThemeService, themeService);
|
||||
return new ChartView(renderOptions, contextViewService, themeService, instantiationService, notificationService);
|
||||
return new ChartView(isQueryEditorChart, contextViewService, themeService, instantiationService, notificationService);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./dashboardGridContainer';
|
||||
|
||||
import { Component, Inject, Input, forwardRef, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef, ContentChild } from '@angular/core';
|
||||
import { Component, Inject, Input, forwardRef, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef, ViewChild } from '@angular/core';
|
||||
|
||||
import { CommonServiceInterface } from 'sql/workbench/services/bootstrap/browser/commonServiceInterface.service';
|
||||
import { TabConfig, WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
||||
@@ -206,7 +206,7 @@ export class DashboardGridContainer extends DashboardTab implements OnDestroy {
|
||||
|
||||
@ViewChildren(DashboardWidgetWrapper) private _widgets: QueryList<DashboardWidgetWrapper>;
|
||||
@ViewChildren(WebviewContent) private _webViews: QueryList<WebviewContent>;
|
||||
@ContentChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
||||
@ViewChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) protected dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ElementRef)) protected _el: ElementRef,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import 'vs/css!./dashboardHomeContainer';
|
||||
|
||||
import { Component, forwardRef, Input, ChangeDetectorRef, Inject, ViewChild, ContentChild, ElementRef } from '@angular/core';
|
||||
import { Component, forwardRef, Input, ChangeDetectorRef, Inject, ViewChild, ElementRef } from '@angular/core';
|
||||
|
||||
import { DashboardWidgetContainer } from 'sql/workbench/contrib/dashboard/browser/containers/dashboardWidgetContainer.component';
|
||||
import { WidgetConfig } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
||||
@@ -44,7 +44,7 @@ export class DashboardHomeContainer extends DashboardWidgetContainer {
|
||||
@Input() private properties: WidgetConfig;
|
||||
@ViewChild('propertiesClass') private _propertiesClass: DashboardWidgetWrapper;
|
||||
@ViewChild('propertiesContainer') private _propertiesContainer: ElementRef;
|
||||
@ContentChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
||||
@ViewChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
||||
|
||||
@@ -50,3 +50,11 @@ dashboard-widget-wrapper .bottomActionbar {
|
||||
margin-top: -27px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
dashboard-widget-wrapper .bottomActionbar .actions-container .action-item a.action-label.codicon-chevron-up {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
dashboard-widget-wrapper .bottomActionbar .actions-container .action-item a.action-label.codicon-chevron-down {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
@@ -8,28 +8,30 @@
|
||||
[actions]="panelActions">
|
||||
<div #toolbar [style.display]="showToolbar ? 'block': 'none'" class="editor-toolbar">
|
||||
</div>
|
||||
<tab [visibilityType]="'visibility'" *ngFor="let tab of tabs" [title]="tab.title" class="fullsize"
|
||||
[identifier]="tab.id" [canClose]="tab.canClose" [actions]="tab.actions" [type]="tab.type" [iconClass]="tab.iconClass">
|
||||
<ng-template>
|
||||
<dashboard-home-container *ngIf="tab.id === 'homeTab'; else not_home" [properties]="propertiesWidget"
|
||||
[tab]="tab">
|
||||
</dashboard-home-container>
|
||||
<ng-template #not_home>
|
||||
<dashboard-webview-container *ngIf="getContentType(tab) === 'webview-container'" [tab]="tab">
|
||||
</dashboard-webview-container>
|
||||
<dashboard-widget-container *ngIf="getContentType(tab) === 'widgets-container'" [tab]="tab">
|
||||
</dashboard-widget-container>
|
||||
<dashboard-modelview-container *ngIf="getContentType(tab) === 'modelview-container'" [tab]="tab">
|
||||
</dashboard-modelview-container>
|
||||
<dashboard-controlhost-container *ngIf="getContentType(tab) === 'controlhost-container'" [tab]="tab">
|
||||
</dashboard-controlhost-container>
|
||||
<dashboard-nav-section *ngIf="getContentType(tab) === 'nav-section'" [tab]="tab">
|
||||
</dashboard-nav-section>
|
||||
<dashboard-grid-container *ngIf="getContentType(tab) === 'grid-container'" [tab]="tab">
|
||||
</dashboard-grid-container>
|
||||
<dashboard-error-container *ngIf="getContentType(tab) === 'error-container'" [tab]="tab">
|
||||
</dashboard-error-container>
|
||||
<div [style.height]="getContentAreaHeight()">
|
||||
<tab [visibilityType]="'visibility'" *ngFor="let tab of tabs" [title]="tab.title" class="fullsize"
|
||||
[identifier]="tab.id" [canClose]="tab.canClose" [actions]="tab.actions" [type]="tab.type"
|
||||
[iconClass]="tab.iconClass">
|
||||
<ng-template>
|
||||
<dashboard-home-container *ngIf="tab.id === 'homeTab'; else not_home" [properties]="propertiesWidget" [tab]="tab">
|
||||
</dashboard-home-container>
|
||||
<ng-template #not_home>
|
||||
<dashboard-webview-container *ngIf="getContentType(tab) === 'webview-container'" [tab]="tab">
|
||||
</dashboard-webview-container>
|
||||
<dashboard-widget-container *ngIf="getContentType(tab) === 'widgets-container'" [tab]="tab">
|
||||
</dashboard-widget-container>
|
||||
<dashboard-modelview-container *ngIf="getContentType(tab) === 'modelview-container'" [tab]="tab">
|
||||
</dashboard-modelview-container>
|
||||
<dashboard-controlhost-container *ngIf="getContentType(tab) === 'controlhost-container'" [tab]="tab">
|
||||
</dashboard-controlhost-container>
|
||||
<dashboard-nav-section *ngIf="getContentType(tab) === 'nav-section'" [tab]="tab">
|
||||
</dashboard-nav-section>
|
||||
<dashboard-grid-container *ngIf="getContentType(tab) === 'grid-container'" [tab]="tab">
|
||||
</dashboard-grid-container>
|
||||
<dashboard-error-container *ngIf="getContentType(tab) === 'error-container'" [tab]="tab">
|
||||
</dashboard-error-container>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</tab>
|
||||
</tab>
|
||||
</div>
|
||||
</panel>
|
||||
|
||||
@@ -553,4 +553,8 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
|
||||
const border = theme.getColor(DASHBOARD_BORDER);
|
||||
this.toolbarContainer.nativeElement.style.borderBottomColor = border.toString();
|
||||
}
|
||||
|
||||
public getContentAreaHeight() {
|
||||
return this.showToolbar ? `calc(100% - ${(<HTMLElement>this.toolbarContainer.nativeElement).clientHeight}px)` : '100%';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,16 @@ const defaultVal = [
|
||||
widget: {
|
||||
'all-database-size-server-insight': null
|
||||
}
|
||||
}, {
|
||||
name: nls.localize('explorerWidgetsTitle', "Search"),
|
||||
gridItemConfig: {
|
||||
sizex: 2,
|
||||
sizey: 2
|
||||
},
|
||||
when: 'mssql:engineedition == 11 || mssql:iscloud',
|
||||
widget: {
|
||||
'explorer-widget': {}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -292,11 +292,6 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isNullRow(row)) {
|
||||
self.addRow(row);
|
||||
self.refreshGrid();
|
||||
}
|
||||
|
||||
let cellSelectTasks: Promise<void> = this.submitCurrentCellChange(
|
||||
(result: EditUpdateCellResult) => {
|
||||
// Cell update was successful, update the flags
|
||||
@@ -549,7 +544,15 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
private submitCurrentCellChange(resultHandler, errorHandler): Promise<void> {
|
||||
let self = this;
|
||||
let updateCellPromise: Promise<void> = Promise.resolve();
|
||||
let refreshGrid = false;
|
||||
if (this.currentCell && this.currentCell.isEditable && this.currentEditCellValue !== undefined && !this.removingNewRow) {
|
||||
if (this.isNullRow(this.currentCell.row)) {
|
||||
refreshGrid = true;
|
||||
// We've entered the "new row", so we need to add a row and jump to it
|
||||
updateCellPromise = updateCellPromise.then(() => {
|
||||
return self.addRow(this.currentCell.row);
|
||||
});
|
||||
}
|
||||
// We're exiting a read/write cell after having changed the value, update the cell value in the service
|
||||
updateCellPromise = updateCellPromise.then(() => {
|
||||
// Use the mapped row ID if we're on that row
|
||||
@@ -562,6 +565,9 @@ export class EditDataGridPanel extends GridParentComponent {
|
||||
result => {
|
||||
self.currentEditCellValue = undefined;
|
||||
let refreshPromise: Thenable<void> = Promise.resolve();
|
||||
if (refreshGrid) {
|
||||
refreshPromise = self.refreshGrid();
|
||||
}
|
||||
return refreshPromise.then(() => {
|
||||
return resultHandler(result);
|
||||
});
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.editDataGridPanel.slickgridContainer {
|
||||
height: 447px;
|
||||
width: 632px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<ul class="cell-toolbar">
|
||||
<li><a class="cell-tool-edit" role="button" href="#" (click)="toolbarToggleEditMode()"><span class="offscreen">{{buttonEdit}}</span></a></li>
|
||||
<li><a class="cell-tool-close" role="button" href="#" (click)="toolbarUnselectActiveCell()"><span class="offscreen">{{buttonClose}}</span></a></li>
|
||||
<li><a class="cell-tool-add" role="button" href="#"><span class="offscreen">{{buttonAdd}}</span></a></li>
|
||||
<li><a class="cell-tool-move-down" role="button" href="#"><span class="offscreen">{{buttonMoveDown}}</span></a></li>
|
||||
<li><a class="cell-tool-move-up" role="button" href="#"><span class="offscreen">{{buttonMoveUp}}</span></a></li>
|
||||
<li><a class="cell-tool-delete" role="button" href="#"><span class="offscreen">{{buttonDelete}}</span></a></li>
|
||||
<li><div #moreactions class="cell-tool-more"></div></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./cellToolbar';
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export const CELL_TOOLBAR_SELECTOR: string = 'cell-toolbar-component';
|
||||
|
||||
@Component({
|
||||
selector: CELL_TOOLBAR_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./cellToolbar.component.html'))
|
||||
})
|
||||
export class CellToolbarComponent {
|
||||
public buttonEdit = localize('buttonEdit', "Edit");
|
||||
public buttonClose = localize('buttonClose', "Close");
|
||||
public buttonAdd = localize('buttonAdd', "Add new cell");
|
||||
public buttonMoveDown = localize('buttonMoveDown', "Move cell down");
|
||||
public buttonMoveUp = localize('buttonMoveUp', "Move cell up");
|
||||
public buttonDelete = localize('buttonDelete', "Delete cell");
|
||||
|
||||
constructor() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
cell-toolbar-component {
|
||||
position: absolute;
|
||||
left: 25px;
|
||||
top: -21px;
|
||||
}
|
||||
|
||||
cell-toolbar-component ul {
|
||||
display: inline-block;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 5px 10px 0 10px;
|
||||
}
|
||||
|
||||
cell-toolbar-component li {
|
||||
display: inline-block;
|
||||
margin-right: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
cell-toolbar-component li:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
cell-toolbar-component li a {
|
||||
background: 50% 50% no-repeat;
|
||||
display: block;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
cell-toolbar-component li div {
|
||||
background: 50% 50% no-repeat;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
cell-toolbar-component .offscreen {
|
||||
height: 1px;
|
||||
text-indent: -999999px;
|
||||
margin-top: -1px;
|
||||
position: absolute;
|
||||
}
|
||||
@@ -9,14 +9,20 @@ code-component {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.notebook-cell:not(.active) code-component .toolbar {
|
||||
border-right-color: transparent!important;
|
||||
}
|
||||
|
||||
code-component .toolbar {
|
||||
border-right-style: solid;
|
||||
border-right-width: 1px;
|
||||
flex: 0 0 auto;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
flex-flow:column;
|
||||
width: 40px;
|
||||
min-height: 40px;
|
||||
orientation: portrait
|
||||
orientation: portrait;
|
||||
width: 52px;
|
||||
}
|
||||
|
||||
code-component .toolbar.markdown {
|
||||
@@ -29,36 +35,37 @@ code-component .toolbar .carbon-taskbar {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
code-component .toolbarIconRun {
|
||||
code-component .toolbar .codicon {
|
||||
height: 20px;
|
||||
background-image: url('./media/light/execute_cell.svg');
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.vs-dark code-component .toolbarIconRun,
|
||||
.hc-black code-component .toolbarIconRun {
|
||||
background-image: url('./media/dark/execute_cell_inverse.svg');
|
||||
.notebook-cell:not(.active):hover code-component .toolbarIconRun {
|
||||
background-image: url('./media/execute_cell_grey.svg');
|
||||
}
|
||||
|
||||
code-component .toolbarIconRunError {
|
||||
height: 20px;
|
||||
background-image: url('./media/light/execute_cell_error.svg');
|
||||
padding-bottom: 10px;
|
||||
.vs-dark .notebook-cell:not(.active):hover code-component .toolbarIconRun {
|
||||
background-image: url('./media/execute_cell_dark.svg');
|
||||
}
|
||||
|
||||
code-component .toolbarIconStop {
|
||||
height: 20px;
|
||||
background-image: url('./media/light/stop_cell_solidanimation.svg');
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.vs-dark code-component .toolbarIconStop,
|
||||
.hc-black code-component .toolbarIconStop {
|
||||
background-image: url('./media/dark/stop_cell_solidanimation_inverse.svg');
|
||||
.hc-black .notebook-cell:not(.active):hover code-component .toolbarIconRun {
|
||||
background-image: url('./media/execute_cell_hc.svg');
|
||||
}
|
||||
|
||||
code-component .editor {
|
||||
padding: 5px 0px 5px 0px
|
||||
margin: 14px 0px 5px 0px
|
||||
}
|
||||
|
||||
code-cell-component code-component .monaco-editor .margin-view-overlays .line-numbers {
|
||||
left: 0!important;
|
||||
}
|
||||
code-cell-component code-component .monaco-scrollable-element.editor-scrollable.vs {
|
||||
left: 40px!important;
|
||||
}
|
||||
|
||||
code-cell-component .monaco-editor .margin,
|
||||
code-cell-component code-component .monaco-editor,
|
||||
code-cell-component code-component .monaco-editor-background,
|
||||
code-cell-component code-component .monaco-editor .inputarea.ime-input {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* overview ruler */
|
||||
@@ -84,7 +91,7 @@ code-component .carbon-taskbar .codicon.hideIcon {
|
||||
padding-left: 0px;
|
||||
padding-top: 6px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
code-component .carbon-taskbar .codicon.hideIcon.execCountTen {
|
||||
@@ -95,10 +102,6 @@ code-component .carbon-taskbar .codicon.hideIcon.execCountHundred {
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
code-component .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container {
|
||||
padding-left: 10px
|
||||
}
|
||||
|
||||
code-component .hide-component-button {
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
@@ -106,23 +109,5 @@ code-component .hide-component-button {
|
||||
border-width: 0px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
code-component .hide-component-button.icon-hide-cell {
|
||||
background-image: url("./media/light/chevron_up.svg");
|
||||
}
|
||||
|
||||
code-component .hide-component-button.icon-show-cell {
|
||||
background-image: url("./media/light/chevron_down.svg");
|
||||
}
|
||||
|
||||
.vs-dark code-component .hide-component-button.icon-hide-cell,
|
||||
.hc-black code-component .hide-component-button.icon-hide-cell {
|
||||
background-image: url("./media/dark/chevron_up_inverse.svg");
|
||||
}
|
||||
|
||||
.vs-dark code-component .hide-component-button.icon-show-cell,
|
||||
.hc-black code-component .hide-component-button.icon-show-cell {
|
||||
background-image: url("./media/dark/chevron_down_inverse.svg");
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div style="width: 100%; height: fit-content; display: flex; flex-flow: column">
|
||||
<button #collapseCellButton (click)="toggleCollapsed($event)" class="hide-component-button"></button>
|
||||
<button #collapseCellButton (click)="toggleCollapsed($event)" class="hide-component-button codicon"></button>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,10 @@ export class CollapseComponent extends CellView implements OnInit, OnChanges {
|
||||
@ViewChild('collapseCellButton', { read: ElementRef }) private collapseCellButtonElement: ElementRef;
|
||||
|
||||
private readonly expandButtonTitle = localize('expandCellContents', "Expand code cell contents");
|
||||
private readonly expandButtonClass = 'icon-show-cell';
|
||||
private readonly expandButtonClass = 'arrow-down';
|
||||
|
||||
private readonly collapseButtonTitle = localize('collapseCellContents', "Collapse code cell contents");
|
||||
private readonly collapseButtonClass = 'icon-hide-cell';
|
||||
private readonly collapseButtonClass = 'arrow-up';
|
||||
|
||||
@Input() cellModel: ICellModel;
|
||||
@Input() activeCellId: string;
|
||||
|
||||
@@ -9,8 +9,10 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { relative, resolve } from 'vs/base/common/path';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
const knownSchemes = new Set(['http', 'https', 'file', 'mailto', 'data', 'azuredatastudio', 'azuredatastudio-insiders', 'vscode', 'vscode-insiders', 'vscode-resource']);
|
||||
const knownSchemes = new Set(['http', 'https', 'file', 'mailto', 'data', 'azuredatastudio', 'azuredatastudio-insiders', 'vscode', 'vscode-insiders', 'vscode-resource', 'onenote']);
|
||||
@Directive({
|
||||
selector: '[link-handler]',
|
||||
})
|
||||
@@ -21,16 +23,16 @@ export class LinkHandlerDirective {
|
||||
|
||||
constructor(
|
||||
@Inject(IOpenerService) private readonly openerService: IOpenerService,
|
||||
@Inject(INotebookService) private readonly notebookService: INotebookService
|
||||
@Inject(INotebookService) private readonly notebookService: INotebookService,
|
||||
@Inject(IFileService) private readonly fileService: IFileService
|
||||
) {
|
||||
this.workbenchFilePath = URI.parse(require.toUrl('vs/code/electron-browser/workbench/workbench.html'));
|
||||
}
|
||||
|
||||
@HostListener('click', ['$event'])
|
||||
onclick(event: MouseEvent): void {
|
||||
async onclick(event: MouseEvent): Promise<void> {
|
||||
// Note: this logic is taken from the VSCode handling of links in markdown
|
||||
// Untrusted cells will not support commands or raw HTML tags
|
||||
// Finally, we should consider supporting relative paths - created #5238 to track
|
||||
let target: HTMLElement = event.target as HTMLElement;
|
||||
if (target.tagName !== 'A') {
|
||||
target = target.parentElement;
|
||||
@@ -41,16 +43,18 @@ export class LinkHandlerDirective {
|
||||
try {
|
||||
const href = target['href'];
|
||||
if (href) {
|
||||
this.handleLink(href);
|
||||
await this.handleLink(href);
|
||||
}
|
||||
} catch (err) {
|
||||
onUnexpectedError(err);
|
||||
} finally {
|
||||
}
|
||||
catch (e) {
|
||||
onUnexpectedError(e);
|
||||
}
|
||||
finally {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private handleLink(content: string): void {
|
||||
private async handleLink(content: string): Promise<void> {
|
||||
let uri: URI | undefined;
|
||||
try {
|
||||
uri = URI.parse(content);
|
||||
@@ -61,7 +65,24 @@ export class LinkHandlerDirective {
|
||||
if (uri.fragment && uri.fragment.length > 0 && uri.fsPath === this.workbenchFilePath.fsPath) {
|
||||
this.notebookService.navigateTo(this.notebookUri, uri.fragment);
|
||||
} else {
|
||||
this.openerService.open(uri).catch(onUnexpectedError);
|
||||
if (uri.scheme === 'file') {
|
||||
let exists = await this.fileService.exists(uri);
|
||||
if (!exists) {
|
||||
let relPath = relative(this.workbenchFilePath.fsPath, uri.fsPath);
|
||||
let path = resolve(this.notebookUri.fsPath, relPath);
|
||||
try {
|
||||
uri = URI.file(path);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.forceOpenExternal(uri)) {
|
||||
this.openerService.open(uri, { openExternal: true }).catch(onUnexpectedError);
|
||||
}
|
||||
else {
|
||||
this.openerService.open(uri).catch(onUnexpectedError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,4 +93,11 @@ export class LinkHandlerDirective {
|
||||
}
|
||||
return !!this.isTrusted && link.scheme === 'command';
|
||||
}
|
||||
|
||||
private forceOpenExternal(link: URI): boolean {
|
||||
if (link.scheme.toLowerCase() === 'onenote') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<ul #mdtoolbar class="markdown-toolbar"></ul>
|
||||
@@ -0,0 +1,67 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./markdownToolbar';
|
||||
import { Component, Input, Inject, ViewChild, ElementRef } from '@angular/core';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { TransformMarkdownAction, MarkdownButtonType } from 'sql/workbench/contrib/notebook/browser/markdownToolbarActions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const MARKDOWN_TOOLBAR_SELECTOR: string = 'markdown-toolbar-component';
|
||||
|
||||
@Component({
|
||||
selector: MARKDOWN_TOOLBAR_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./markdownToolbar.component.html'))
|
||||
})
|
||||
export class MarkdownToolbarComponent {
|
||||
@ViewChild('mdtoolbar', { read: ElementRef }) private mdtoolbar: ElementRef;
|
||||
|
||||
public buttonBold = localize('buttonBold', "Bold");
|
||||
public buttonItalic = localize('buttonItalic', "Italic");
|
||||
public buttonHighlight = localize('buttonHighlight', "Highlight");
|
||||
public buttonCode = localize('buttonCode', "Code");
|
||||
public buttonLink = localize('buttonLink', "Link");
|
||||
public buttonList = localize('buttonList', "List");
|
||||
public buttonOrderedList = localize('buttonOrderedList', "Ordered list");
|
||||
public buttonImage = localize('buttonImage', "Image");
|
||||
public buttonPreview = localize('buttonPreview', "Markdown preview toggle - off");
|
||||
|
||||
@Input() public cellModel: ICellModel;
|
||||
private _actionBar: Taskbar;
|
||||
|
||||
constructor(
|
||||
@Inject(IInstantiationService) private _instantiationService: IInstantiationService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.initActionBar();
|
||||
}
|
||||
|
||||
private initActionBar() {
|
||||
let boldButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.boldText', '', 'bold', this.buttonBold, this.cellModel, MarkdownButtonType.BOLD);
|
||||
let italicButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.italicText', '', 'italic', this.buttonItalic, this.cellModel, MarkdownButtonType.ITALIC);
|
||||
let highlightButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.highlightText', '', 'highlight', this.buttonHighlight, this.cellModel, MarkdownButtonType.HIGHLIGHT);
|
||||
let codeButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.codeText', '', 'code', this.buttonCode, this.cellModel, MarkdownButtonType.CODE);
|
||||
let linkButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.linkText', '', 'insert-link', this.buttonLink, this.cellModel, MarkdownButtonType.LINK);
|
||||
let listButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.listText', '', 'list', this.buttonList, this.cellModel, MarkdownButtonType.UNORDERED_LIST);
|
||||
let orderedListButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.orderedText', '', 'ordered-list', this.buttonOrderedList, this.cellModel, MarkdownButtonType.ORDERED_LIST);
|
||||
let imageButton = this._instantiationService.createInstance(TransformMarkdownAction, 'notebook.imageText', '', 'insert-image', this.buttonImage, this.cellModel, MarkdownButtonType.IMAGE);
|
||||
|
||||
let taskbar = <HTMLElement>this.mdtoolbar.nativeElement;
|
||||
this._actionBar = new Taskbar(taskbar);
|
||||
this._actionBar.context = this;
|
||||
this._actionBar.setContent([
|
||||
{ action: boldButton },
|
||||
{ action: italicButton },
|
||||
{ action: highlightButton },
|
||||
{ action: codeButton },
|
||||
{ action: linkButton },
|
||||
{ action: listButton },
|
||||
{ action: orderedListButton },
|
||||
{ action: imageButton }
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
/* Resets */
|
||||
.markdown-toolbar .carbon-taskbar li a.action-label {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.markdown-toolbar .carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.markdown-toolbar {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
display: block;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 4px 16px;
|
||||
}
|
||||
.markdown-toolbar .carbon-taskbar li.action-item {
|
||||
display: inline-block;
|
||||
margin-right: 14px;
|
||||
}
|
||||
.markdown-toolbar .carbon-taskbar li:nth-child(1) {
|
||||
margin-right: 9px;
|
||||
}
|
||||
.markdown-toolbar .carbon-taskbar li:nth-child(2) {
|
||||
margin-right: 9px;
|
||||
}
|
||||
.markdown-toolbar .carbon-taskbar li a {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
-webkit-mask-position: center;
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.markdown-toolbar li a.codicon.bold {
|
||||
-webkit-mask-size: 50% 100%;
|
||||
mask-size: 50% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.italic {
|
||||
-webkit-mask-size: 60% 100%;
|
||||
mask-size: 60% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.highlight {
|
||||
-webkit-mask-size: 65% 100%;
|
||||
mask-size: 65% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.code {
|
||||
-webkit-mask-size: 88% 100%;
|
||||
mask-size: 88% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.insert-link {
|
||||
-webkit-mask-size: 80% 100%;
|
||||
mask-size: 80% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.list {
|
||||
-webkit-mask-size: 80% 100%;
|
||||
mask-size: 80% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.ordered-list {
|
||||
-webkit-mask-size: 86% 100%;
|
||||
mask-size: 86% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.insertimage {
|
||||
-webkit-mask-size: 86% 100%;
|
||||
mask-size: 86% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.split-toggle-on {
|
||||
-webkit-mask-size: 75% 100%;
|
||||
mask-size: 75% 100%;
|
||||
}
|
||||
.markdown-toolbar li a.codicon.split-toggle-off {
|
||||
-webkit-mask-size: 75% 100%;
|
||||
mask-size: 75% 100%;
|
||||
}
|
||||
|
||||
text-cell-component .offscreen {
|
||||
height: 1px;
|
||||
margin-top: -1px;
|
||||
position: absolute;
|
||||
text-indent: -999999px;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#A19F9D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="#1B1A19"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 394 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 20C15.5228 20 20 15.5228 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20Z" fill="#A19F9D"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.2972 9.9375L8 13.875V6L13.2972 9.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 392 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 21C16.5228 21 21 16.5228 21 11C21 5.47715 16.5228 1 11 1C5.47715 1 1 5.47715 1 11C1 16.5228 5.47715 21 11 21Z" stroke="#2B56F2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.2972 10.9375L9 14.875V7L14.2972 10.9375Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 396 B |
@@ -1 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>execute_cell</title><circle cx="8" cy="7.92" r="7.76"/><polygon class="cls-1" points="10.7 8 6.67 11 6.67 5 10.7 8 10.7 8"/></svg>
|
||||
<svg id="executeCell" data-name="Execute Cell" xmlns="http://www.w3.org/2000/svg" fill="#0078D4" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>execute_cell</title><circle cx="8" cy="7.92" r="7.76"/><polygon class="cls-1" points="10.7 8 6.67 11 6.67 5 10.7 8 10.7 8"/></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 301 B |
@@ -0,0 +1 @@
|
||||
<svg id="executeCell" data-name="Execute Cell" xmlns="http://www.w3.org/2000/svg" fill="#A19F9D" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>execute_cell</title><circle cx="8" cy="7.92" r="7.76"/><polygon class="cls-1" points="10.7 8 6.67 11 6.67 5 10.7 8 10.7 8"/></svg>
|
||||
|
After Width: | Height: | Size: 301 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="10" height="13" viewBox="0 0 10 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>bold</title>
|
||||
<path d="M5.80469 6.03906C6.28385 6.03906 6.73438 6.13021 7.15625 6.3125C7.58333 6.49479 7.95312 6.74479 8.26562 7.0625C8.58333 7.375 8.83333 7.74219 9.01562 8.16406C9.19792 8.58594 9.28906 9.03646 9.28906 9.51562C9.28906 9.99479 9.19792 10.4479 9.01562 10.875C8.83333 11.2969 8.58333 11.6667 8.26562 11.9844C7.95312 12.2969 7.58333 12.5443 7.15625 12.7266C6.73438 12.9089 6.28385 13 5.80469 13H0V0H5.80469C6.22135 0 6.61198 0.0807292 6.97656 0.242188C7.34115 0.398438 7.65885 0.614583 7.92969 0.890625C8.20573 1.16146 8.42188 1.47917 8.57812 1.84375C8.73958 2.20833 8.82031 2.59896 8.82031 3.01562C8.82031 3.43229 8.74219 3.82552 8.58594 4.19531C8.42969 4.5599 8.21354 4.88021 7.9375 5.15625C7.66667 5.42708 7.34635 5.64323 6.97656 5.80469C6.61198 5.96094 6.22135 6.03906 5.80469 6.03906ZM4.17969 1.85938H3V5.57031H4.17969C4.4349 5.57031 4.67448 5.52083 4.89844 5.42188C5.1276 5.32292 5.32552 5.1901 5.49219 5.02344C5.65885 4.85677 5.79167 4.66146 5.89062 4.4375C5.98958 4.20833 6.03906 3.96615 6.03906 3.71094C6.03906 3.45573 5.98958 3.21615 5.89062 2.99219C5.79167 2.76823 5.65885 2.57292 5.49219 2.40625C5.32552 2.23438 5.1276 2.10156 4.89844 2.00781C4.67448 1.90885 4.4349 1.85938 4.17969 1.85938ZM4.64062 11.1406C4.89583 11.1406 5.13542 11.0938 5.35938 11C5.58854 10.901 5.78646 10.7682 5.95312 10.6016C6.11979 10.4297 6.2526 10.2318 6.35156 10.0078C6.45052 9.78385 6.5 9.54427 6.5 9.28906C6.5 9.03385 6.45052 8.79427 6.35156 8.57031C6.25781 8.34115 6.125 8.14323 5.95312 7.97656C5.78646 7.80469 5.58854 7.67188 5.35938 7.57812C5.13542 7.47917 4.89583 7.42969 4.64062 7.42969H3V11.1406H4.64062Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="9" viewBox="0 0 16 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>preformatted</title>
|
||||
<path d="M1.71094 5L3.3125 6.60156L3.02344 7.73438L0.289062 5L3.64844 1.64844L4.35156 2.35156L1.71094 5ZM15.7109 5L12.3516 8.35156L11.6484 7.64844L14.2891 5L13.125 3.83594C13.2604 3.70052 13.3828 3.57552 13.4922 3.46094C13.6016 3.34115 13.7005 3.21615 13.7891 3.08594L15.7109 5ZM11.4375 0C11.6562 0 11.8594 0.0390625 12.0469 0.117188C12.2396 0.195312 12.4062 0.304688 12.5469 0.445312C12.6875 0.585938 12.7969 0.75 12.875 0.9375C12.9583 1.125 13 1.32812 13 1.54688C13 1.75 12.9609 1.94792 12.8828 2.14062C12.8047 2.33333 12.6927 2.5026 12.5469 2.64844L6.94531 8.26562L4 9L4.73438 6.05469L10.3359 0.445312C10.4818 0.299479 10.651 0.190104 10.8438 0.117188C11.0365 0.0390625 11.2344 0 11.4375 0ZM11.8359 1.94531C11.9453 1.83594 12 1.70312 12 1.54688C12 1.38542 11.9453 1.25521 11.8359 1.15625C11.7318 1.05208 11.599 1 11.4375 1C11.3646 1 11.2943 1.01302 11.2266 1.03906C11.1589 1.0599 11.099 1.09635 11.0469 1.14844L5.64062 6.57031L5.375 7.625L6.42969 7.35938L11.8359 1.94531Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>highlight</title>
|
||||
<path d="M13 0V3.25C12.6318 3.25 12.3166 3.2902 12.0542 3.37061C11.7918 3.45101 11.5697 3.56738 11.3877 3.71973C11.2057 3.87207 11.0576 4.04557 10.9434 4.24023C10.8291 4.4349 10.7424 4.65706 10.6831 4.90674C10.6239 5.15641 10.5837 5.41032 10.5625 5.66846C10.5413 5.9266 10.5308 6.19954 10.5308 6.4873C10.5308 6.7666 10.535 7.04378 10.5435 7.31885C10.5519 7.59391 10.5583 7.86263 10.5625 8.125H8.9375V10.5625L4.0625 13V8.125H2.4375C2.4375 7.86263 2.44173 7.59391 2.4502 7.31885C2.45866 7.04378 2.46501 6.7666 2.46924 6.4873C2.46924 6.20801 2.45866 5.93506 2.4375 5.66846C2.41634 5.40186 2.37614 5.14795 2.31689 4.90674C2.25765 4.66553 2.17301 4.44548 2.06299 4.24658C1.95296 4.04769 1.80485 3.87207 1.61865 3.71973C1.43245 3.56738 1.20817 3.45312 0.945801 3.37695C0.683431 3.30078 0.368164 3.25846 0 3.25V0H0.8125V2.4375H12.1875V0H13ZM8.125 8.125H4.875V11.686L8.125 10.061V8.125ZM9.75 7.3125C9.75 7.12207 9.74788 6.93587 9.74365 6.75391C9.73942 6.57194 9.7373 6.38997 9.7373 6.20801C9.7373 5.93717 9.74788 5.67057 9.76904 5.4082C9.7902 5.14583 9.83252 4.89193 9.896 4.64648C9.95947 4.40104 10.0568 4.15983 10.188 3.92285C10.3192 3.68587 10.4927 3.46159 10.7085 3.25H2.2915C2.50732 3.46582 2.67871 3.6901 2.80566 3.92285C2.93262 4.1556 3.02995 4.39681 3.09766 4.64648C3.16536 4.89616 3.2098 5.15006 3.23096 5.4082C3.25212 5.66634 3.2627 5.93294 3.2627 6.20801C3.2627 6.38997 3.26058 6.57194 3.25635 6.75391C3.25212 6.93587 3.25 7.12207 3.25 7.3125H9.75Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>add inline image</title>
|
||||
<path d="M11 2.5C11 2.36458 11.0495 2.2474 11.1484 2.14844C11.2474 2.04948 11.3646 2 11.5 2C11.6354 2 11.7526 2.04948 11.8516 2.14844C11.9505 2.2474 12 2.36458 12 2.5C12 2.63542 11.9505 2.7526 11.8516 2.85156C11.7526 2.95052 11.6354 3 11.5 3C11.3646 3 11.2474 2.95052 11.1484 2.85156C11.0495 2.7526 11 2.63542 11 2.5ZM16 10V11H14V13H13V11H11V10H13V8H14V10H16ZM7.20312 7.5L10 10.2891V11H0V0H14V7H13V1H1V4.28906L2.5 2.79688L6.5 6.79688L8.5 4.79688L12 8.28906V9H11.2891L8.5 6.20312L7.20312 7.5ZM2.5 4.20312L1 5.71094V10H8.28906L2.5 4.20312Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 691 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="11" height="13" viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>italics</title>
|
||||
<path d="M9.25 1H7.55469L3.89062 12H6.75L5.75 13H0.25L1.25 12H2.50781L6.17188 1H3.75L4.75 0H10.25L9.25 1Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 250 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>link</title>
|
||||
<path d="M7 7V6H8.1L9.1 5.5C9.38138 5.32024 9.62024 5.08138 9.8 4.8C9.93294 4.37949 10.0004 3.94103 10 3.5C9.98112 3.15886 9.91378 2.82215 9.8 2.5C9.6702 2.21199 9.50201 1.94288 9.3 1.7L8.5 1.2L7.5 1H3.5L2.5 1.2L1.7 1.7C1.49799 1.94288 1.3298 2.21199 1.2 2.5C1.08622 2.82215 1.01888 3.15886 1 3.5C1.00946 3.90746 1.0768 4.3115 1.2 4.7L1.9 5.4L2.9 5.9H4V7H3.5C3.01765 6.99754 2.54101 6.8954 2.1 6.7C1.69834 6.52684 1.32698 6.29051 1 6C0.709485 5.67302 0.473165 5.30166 0.3 4.9C0.104596 4.45899 0.00245968 3.98235 0 3.5C0.00245968 3.01765 0.104596 2.54101 0.3 2.1C0.473165 1.69834 0.709485 1.32698 1 1C1.32698 0.709485 1.69834 0.473165 2.1 0.3C2.54101 0.104596 3.01765 0.00245968 3.5 0L7.5 0C7.98235 0.00245968 8.45899 0.104596 8.9 0.3C9.30166 0.473165 9.67302 0.709485 10 1C10.2905 1.32698 10.5268 1.69834 10.7 2.1C10.8954 2.54101 10.9975 3.01765 11 3.5C10.9975 3.98235 10.8954 4.45899 10.7 4.9C10.5268 5.30166 10.2905 5.67302 10 6C9.67302 6.29051 9.30166 6.52684 8.9 6.7C8.45899 6.8954 7.98235 6.99754 7.5 7H7ZM12 3V4H13.1L14.1 4.5C14.3814 4.67976 14.6202 4.91862 14.8 5.2C14.9329 5.62051 15.0004 6.05897 15 6.5C14.9811 6.84114 14.9138 7.17785 14.8 7.5C14.6702 7.78801 14.502 8.05712 14.3 8.3L13.5 8.8L12.5 9H8.5L7.5 8.8L6.7 8.3C6.49799 8.05712 6.3298 7.78801 6.2 7.5C6.08622 7.17785 6.01888 6.84114 6 6.5C6.00946 6.09254 6.0768 5.6885 6.2 5.3C6.37976 5.01862 6.61862 4.77976 6.9 4.6L7.9 4.1H9V3H8.5C8.01765 3.00246 7.54101 3.1046 7.1 3.3C6.69834 3.47316 6.32698 3.70949 6 4C5.70949 4.32698 5.47316 4.69834 5.3 5.1C5.10121 5.53996 4.99839 6.01721 4.99839 6.5C4.99839 6.98279 5.10121 7.46004 5.3 7.9C5.47316 8.30166 5.70949 8.67302 6 9C6.32698 9.29051 6.69834 9.52684 7.1 9.7C7.54101 9.8954 8.01765 9.99754 8.5 10H12.5C12.9824 9.99754 13.459 9.8954 13.9 9.7C14.3017 9.52684 14.673 9.29051 15 9C15.2905 8.67302 15.5268 8.30166 15.7 7.9C15.8988 7.46004 16.0016 6.98279 16.0016 6.5C16.0016 6.01721 15.8988 5.53996 15.7 5.1C15.5268 4.69834 15.2905 4.32698 15 4C14.673 3.70949 14.3017 3.47316 13.9 3.3C13.459 3.1046 12.9824 3.00246 12.5 3H12Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>unordered list</title>
|
||||
<path d="M0 7V6H1V7H0ZM0 4V3H1V4H0ZM3 4V3H16V4H3ZM0 1V0H1V1H0ZM3 0H16V1H3V0ZM3 7V6H16V7H3ZM0 10V9H1V10H0ZM3 10V9H16V10H3Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 273 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Ordered list</title>
|
||||
<path d="M16 2V3H4V2H16ZM4 6H16V7H4V6ZM4 10H16V11H4V10ZM1.05469 1.72656C0.981771 1.78385 0.882812 1.84115 0.757812 1.89844C0.638021 1.95052 0.528646 1.97656 0.429688 1.97656V1.4375C0.591146 1.38021 0.744792 1.31771 0.890625 1.25C1.03646 1.18229 1.17708 1.09635 1.3125 0.992188H1.69531V4H1.05469V1.72656ZM1.04688 5.00781C1.17708 5.00781 1.29948 5.02604 1.41406 5.0625C1.53385 5.09375 1.63542 5.14583 1.71875 5.21875C1.80729 5.28646 1.875 5.3724 1.92188 5.47656C1.97396 5.58073 2 5.70312 2 5.84375C2 6.00521 1.96875 6.14844 1.90625 6.27344C1.84375 6.39323 1.76562 6.5026 1.67188 6.60156C1.58333 6.69531 1.48438 6.78125 1.375 6.85938C1.26562 6.93229 1.16406 7.0026 1.07031 7.07031C0.981771 7.13281 0.90625 7.19792 0.84375 7.26562C0.78125 7.32812 0.75 7.39323 0.75 7.46094H2V8H0.0390625C0.0390625 7.88021 0.0390625 7.77344 0.0390625 7.67969C0.0442708 7.58594 0.0703125 7.48438 0.117188 7.375C0.195312 7.19792 0.302083 7.04948 0.4375 6.92969C0.572917 6.80469 0.705729 6.6901 0.835938 6.58594C0.971354 6.48177 1.08854 6.3776 1.1875 6.27344C1.28646 6.16927 1.33594 6.04688 1.33594 5.90625C1.33594 5.76562 1.29688 5.66667 1.21875 5.60938C1.14062 5.55208 1.03646 5.52344 0.90625 5.52344C0.770833 5.52344 0.640625 5.55208 0.515625 5.60938C0.395833 5.66667 0.283854 5.73958 0.179688 5.82812V5.25781C0.440104 5.09115 0.729167 5.00781 1.04688 5.00781ZM1.32812 10.4688C1.51562 10.4948 1.67448 10.5651 1.80469 10.6797C1.9349 10.7943 2 10.9531 2 11.1562C2 11.3177 1.96615 11.4557 1.89844 11.5703C1.83594 11.6849 1.7526 11.7786 1.64844 11.8516C1.54427 11.9193 1.42188 11.9714 1.28125 12.0078C1.14583 12.0391 1.00781 12.0547 0.867188 12.0547C0.742188 12.0547 0.614583 12.0443 0.484375 12.0234C0.359375 12.0026 0.239583 11.9635 0.125 11.9062V11.3359C0.223958 11.4089 0.330729 11.4635 0.445312 11.5C0.565104 11.5365 0.6875 11.5547 0.8125 11.5547C0.947917 11.5547 1.06771 11.526 1.17188 11.4688C1.28125 11.4115 1.33594 11.3047 1.33594 11.1484C1.33594 11.0339 1.30208 10.9505 1.23438 10.8984C1.16667 10.8411 1.08333 10.8021 0.984375 10.7812C0.890625 10.7552 0.791667 10.7422 0.6875 10.7422C0.583333 10.7422 0.494792 10.7422 0.421875 10.7422V10.2422C0.494792 10.2422 0.578125 10.2422 0.671875 10.2422C0.765625 10.2422 0.854167 10.2344 0.9375 10.2188C1.02604 10.1979 1.09896 10.1615 1.15625 10.1094C1.21875 10.0573 1.25 9.97656 1.25 9.86719C1.25 9.73177 1.20573 9.63802 1.11719 9.58594C1.03385 9.53385 0.932292 9.50781 0.8125 9.50781C0.609375 9.50781 0.416667 9.57031 0.234375 9.69531V9.16406C0.348958 9.10677 0.466146 9.06771 0.585938 9.04688C0.710938 9.02083 0.835938 9.00781 0.960938 9.00781C1.07552 9.00781 1.1901 9.02083 1.30469 9.04688C1.41927 9.07292 1.52083 9.11719 1.60938 9.17969C1.69792 9.23698 1.77083 9.3125 1.82812 9.40625C1.88542 9.5 1.91406 9.61198 1.91406 9.74219C1.91406 9.9401 1.86198 10.099 1.75781 10.2188C1.65885 10.3333 1.51562 10.4141 1.32812 10.4609V10.4688Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>markdown preview toggle - off</title>
|
||||
<path d="M15.5 0.5V13.5H0.5V0.5H15.5ZM1.5 1.5V3.5H14.5V1.5H1.5ZM14.5 12.5V4.5H1.5V12.5H14.5Z" fill="#323130"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 259 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>markdown preview toggle - on</title>
|
||||
<path d="M15 1V14H0V1H15ZM1 2V4H14V2H1ZM14 13V5H1V13H14Z" fill="black"/>
|
||||
<path d="M8 5H7V13H8V5Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 260 B |
@@ -5,6 +5,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column" (mouseover)="hover=true" (mouseleave)="hover=false">
|
||||
<markdown-toolbar-component #markdownToolbar *ngIf="previewFeaturesEnabled === true && isEditMode" [cellModel]="cellModel"></markdown-toolbar-component>
|
||||
<div class="notebook-text" style="flex: 0 0 auto;">
|
||||
<code-component *ngIf="isEditMode" [cellModel]="cellModel" (onContentChanged)="handleContentChanged()" [model]="model" [activeCellId]="activeCellId">
|
||||
</code-component>
|
||||
|
||||
@@ -27,11 +27,11 @@ import { CellToggleMoreActions } from 'sql/workbench/contrib/notebook/browser/ce
|
||||
import { CodeComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/code.component';
|
||||
import { NotebookRange, ICellEditorProvider } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
export const TEXT_SELECTOR: string = 'text-cell-component';
|
||||
const USER_SELECT_CLASS = 'actionselect';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: TEXT_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./textCell.component.html'))
|
||||
@@ -88,11 +88,13 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
private _hover: boolean;
|
||||
private markdownRenderer: NotebookMarkdownRenderer;
|
||||
private markdownResult: IMarkdownRenderResult;
|
||||
public previewFeaturesEnabled: boolean = false;
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IConfigurationService) private _configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
this.isEditMode = true;
|
||||
@@ -103,6 +105,9 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
this.markdownResult.dispose();
|
||||
}
|
||||
}));
|
||||
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||
this.previewFeaturesEnabled = this._configurationService.getValue('workbench.enablePreviewFeatures');
|
||||
}));
|
||||
}
|
||||
|
||||
public get cellEditors(): ICellEditorProvider[] {
|
||||
@@ -135,6 +140,7 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.previewFeaturesEnabled = this._configurationService.getValue('workbench.enablePreviewFeatures');
|
||||
this._register(this.themeService.onDidColorThemeChange(this.updateTheme, this));
|
||||
this.updateTheme(this.themeService.getColorTheme());
|
||||
this._cellToggleMoreActions.onInit(this.moreActionsElementRef, this.model, this.cellModel);
|
||||
@@ -308,9 +314,13 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
|
||||
for (let element of hostElem.children) {
|
||||
if (element.nodeName.toLowerCase() === 'table') {
|
||||
// add table header and table rows.
|
||||
children.push(element.children[0]);
|
||||
for (let trow of element.children[1].children) {
|
||||
children.push(trow);
|
||||
if (element.children.length > 0) {
|
||||
children.push(element.children[0]);
|
||||
if (element.children.length > 1) {
|
||||
for (let trow of element.children[1].children) {
|
||||
children.push(trow);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element.children.length > 1) {
|
||||
children = children.concat(this.getChildren(element));
|
||||
|
||||
@@ -7,6 +7,12 @@ text-cell-component {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.notebookEditor .notebook-cell.active text-cell-component code-component {
|
||||
border-color: transparent;
|
||||
border-bottom-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
text-cell-component .notebook-preview {
|
||||
user-select: none;
|
||||
padding-left: 8px;
|
||||
@@ -17,6 +23,16 @@ text-cell-component .notebook-preview {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
text-cell-component code-component .monaco-scrollable-element.editor-scrollable.vs {
|
||||
left: 16px!important;
|
||||
}
|
||||
text-cell-component .monaco-editor .margin,
|
||||
text-cell-component code-component .monaco-editor,
|
||||
text-cell-component code-component .monaco-editor-background,
|
||||
text-cell-component code-component .monaco-editor .inputarea.ime-input {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.vs .notebook-preview .rangeHighlight {
|
||||
background-color: rgba(255, 255, 0, 0.2)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
|
||||
import { INotebookEditor, INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
|
||||
|
||||
|
||||
// Action to decorate markdown
|
||||
export class TransformMarkdownAction extends Action {
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
cssClass: string,
|
||||
tooltip: string,
|
||||
private _cellModel: ICellModel,
|
||||
private _type: MarkdownButtonType,
|
||||
@INotebookService private _notebookService: INotebookService
|
||||
) {
|
||||
super(id, label, cssClass);
|
||||
this._tooltip = tooltip;
|
||||
}
|
||||
public run(context: any): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
try {
|
||||
let markdownTextTransformer = new MarkdownTextTransformer(this._notebookService, this._cellModel);
|
||||
markdownTextTransformer.transformText(this._type);
|
||||
resolve(true);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class MarkdownTextTransformer {
|
||||
|
||||
private _notebookEditor: INotebookEditor;
|
||||
constructor(private _notebookService: INotebookService, private _cellModel: ICellModel) { }
|
||||
|
||||
public transformText(type: MarkdownButtonType): void {
|
||||
let editorControl = this.getEditorControl();
|
||||
if (editorControl) {
|
||||
let selections = editorControl.getSelections();
|
||||
// TODO: Support replacement for multiple selections
|
||||
let selection = selections[0];
|
||||
let nothingSelected = this.editorHasNoSelection(selection);
|
||||
let startRange: IRange = {
|
||||
startColumn: selection.startColumn,
|
||||
endColumn: selection.startColumn,
|
||||
startLineNumber: selection.startLineNumber,
|
||||
endLineNumber: selection.startLineNumber
|
||||
};
|
||||
|
||||
// Get text to insert before selection
|
||||
let beginInsertedCode = this.getStartTextToInsert(type);
|
||||
// Get text to insert after selection
|
||||
let endInsertedCode = this.getEndTextToInsert(type);
|
||||
|
||||
// endInsertedCode can be an empty string (e.g. for unordered list), so no need to check for that as well
|
||||
if (beginInsertedCode) {
|
||||
let endRange: IRange = {
|
||||
startColumn: selection.endColumn,
|
||||
endColumn: selection.endColumn,
|
||||
startLineNumber: selection.endLineNumber,
|
||||
endLineNumber: selection.endLineNumber
|
||||
};
|
||||
let editorModel = editorControl.getModel() as TextModel;
|
||||
let isUndo = false;
|
||||
if (editorModel) {
|
||||
let markdownLineType = this.getMarkdownLineType(type);
|
||||
isUndo = this.isUndoOperation(selection, type, markdownLineType, editorModel);
|
||||
if (isUndo) {
|
||||
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
|
||||
startRange = this.getIRangeWithOffsets(startRange, -1 * beginInsertedCode.length, 0, 0, 0);
|
||||
endRange = this.getIRangeWithOffsets(endRange, 0, 0, endInsertedCode.length, 0);
|
||||
editorModel.pushEditOperations(selections, [{ range: endRange, text: '' }, { range: startRange, text: '' }], null);
|
||||
} else {
|
||||
let operations: IIdentifiedSingleEditOperation[] = [];
|
||||
startRange = this.getIRangeWithOffsets(startRange, 0, 0, beginInsertedCode.length, 0);
|
||||
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
|
||||
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: '' });
|
||||
}
|
||||
editorModel.pushEditOperations(selections, operations, null);
|
||||
}
|
||||
} else {
|
||||
// If the markdown we're inserting only needs to be added to the begin and end lines, add those edit operations directly
|
||||
if (markdownLineType === MarkdownLineType.BEGIN_AND_END_LINES) {
|
||||
editorModel.pushEditOperations(selections, [{ range: startRange, text: beginInsertedCode }, { range: endRange, text: endInsertedCode }], null);
|
||||
} else { // Otherwise, add an operation per line (plus the operation at the last column + line)
|
||||
let operations: IIdentifiedSingleEditOperation[] = [];
|
||||
for (let i = 0; i < selection.endLineNumber - selection.startLineNumber + 1; i++) {
|
||||
operations.push({ range: this.transformRangeByLineOffset(startRange, i), text: beginInsertedCode });
|
||||
}
|
||||
operations.push({ range: endRange, text: endInsertedCode });
|
||||
editorModel.pushEditOperations(selections, operations, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If selection end is on same line as beginning, need to add offset for number of characters inserted
|
||||
// Otherwise, the selection will not be correct after the transformation
|
||||
let offset = selection.startLineNumber === selection.endLineNumber ? beginInsertedCode.length : 0;
|
||||
endRange = this.getIRangeWithOffsets(endRange, offset, 0, offset, 0);
|
||||
this.setEndSelection(endRange, type, editorControl, nothingSelected, isUndo);
|
||||
}
|
||||
// Always give focus back to the editor after pressing the button
|
||||
editorControl.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// For items like lists (where we need to insert a character at the beginning of each line), create
|
||||
// range object for that range
|
||||
private transformRangeByLineOffset(range: IRange, lineOffset: number): IRange {
|
||||
return {
|
||||
startColumn: lineOffset === 0 ? range.startColumn : 1,
|
||||
endColumn: range.endColumn,
|
||||
startLineNumber: range.endLineNumber + lineOffset,
|
||||
endLineNumber: range.endLineNumber + lineOffset
|
||||
};
|
||||
}
|
||||
|
||||
private getStartTextToInsert(type: MarkdownButtonType): string {
|
||||
switch (type) {
|
||||
case MarkdownButtonType.BOLD:
|
||||
return '**';
|
||||
case MarkdownButtonType.ITALIC:
|
||||
return '_';
|
||||
case MarkdownButtonType.CODE:
|
||||
return '```\n';
|
||||
case MarkdownButtonType.LINK:
|
||||
return '[';
|
||||
case MarkdownButtonType.UNORDERED_LIST:
|
||||
return '- ';
|
||||
case MarkdownButtonType.ORDERED_LIST:
|
||||
return '1. ';
|
||||
case MarkdownButtonType.IMAGE:
|
||||
return '![';
|
||||
case MarkdownButtonType.HIGHLIGHT:
|
||||
return '<mark>';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private getEndTextToInsert(type: MarkdownButtonType): string {
|
||||
switch (type) {
|
||||
case MarkdownButtonType.BOLD:
|
||||
return '**';
|
||||
case MarkdownButtonType.ITALIC:
|
||||
return '_';
|
||||
case MarkdownButtonType.CODE:
|
||||
return '\n```';
|
||||
case MarkdownButtonType.LINK:
|
||||
case MarkdownButtonType.IMAGE:
|
||||
return ']()';
|
||||
case MarkdownButtonType.HIGHLIGHT:
|
||||
return '</mark>';
|
||||
case MarkdownButtonType.UNORDERED_LIST:
|
||||
case MarkdownButtonType.ORDERED_LIST:
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private getMarkdownLineType(type: MarkdownButtonType): MarkdownLineType {
|
||||
switch (type) {
|
||||
case MarkdownButtonType.UNORDERED_LIST:
|
||||
case MarkdownButtonType.ORDERED_LIST:
|
||||
return MarkdownLineType.EVERY_LINE;
|
||||
default:
|
||||
return MarkdownLineType.BEGIN_AND_END_LINES;
|
||||
}
|
||||
}
|
||||
|
||||
// Get offset from the end column for editor selection
|
||||
// For example, when inserting a link, we want to have the cursor be present in between the brackets
|
||||
private getColumnOffsetForSelection(type: MarkdownButtonType, nothingSelected: boolean): number {
|
||||
if (nothingSelected) {
|
||||
return 0;
|
||||
}
|
||||
switch (type) {
|
||||
case MarkdownButtonType.LINK:
|
||||
return 2;
|
||||
case MarkdownButtonType.IMAGE:
|
||||
return 2;
|
||||
// -1 is considered as having no explicit offset, so do not do anything with selection
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private getEditorControl(): CodeEditorWidget | undefined {
|
||||
if (!this._notebookEditor) {
|
||||
this._notebookEditor = this._notebookService.findNotebookEditor(this._cellModel.notebookModel.notebookUri);
|
||||
}
|
||||
if (this._notebookEditor?.cellEditors?.length > 0) {
|
||||
// Find cell editor provider via cell guid
|
||||
let cellEditorProvider = this._notebookEditor.cellEditors.find(e => e.cellGuid() === this._cellModel.cellGuid);
|
||||
if (cellEditorProvider) {
|
||||
let editor = cellEditorProvider.getEditor() as QueryTextEditor;
|
||||
if (editor) {
|
||||
let editorControl = editor.getControl() as CodeEditorWidget;
|
||||
return editorControl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private editorHasNoSelection(selection: Selection): boolean {
|
||||
return !selection || (selection.startLineNumber === selection.endLineNumber && selection.startColumn === selection.endColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end selection state after the transform has occurred
|
||||
* @param endRange range for end text that was inserted
|
||||
* @param type MarkdownButtonType
|
||||
* @param editorControl code editor widget
|
||||
* @param noSelection controls whether there was no previous selection in the editor
|
||||
*/
|
||||
private setEndSelection(endRange: IRange, type: MarkdownButtonType, editorControl: CodeEditorWidget, noSelection: boolean, isUndo: boolean): void {
|
||||
if (!endRange || !editorControl || isUndo) {
|
||||
return;
|
||||
}
|
||||
let offset = this.getColumnOffsetForSelection(type, noSelection);
|
||||
if (offset > -1) {
|
||||
let newRange: IRange = {
|
||||
startColumn: endRange.startColumn + offset,
|
||||
startLineNumber: endRange.startLineNumber,
|
||||
endColumn: endRange.startColumn + offset,
|
||||
endLineNumber: endRange.endLineNumber
|
||||
};
|
||||
editorControl.setSelection(newRange);
|
||||
} else {
|
||||
if (this.getMarkdownLineType(type) === MarkdownLineType.BEGIN_AND_END_LINES) {
|
||||
let currentSelection = editorControl.getSelection();
|
||||
editorControl.setSelection({
|
||||
startColumn: currentSelection.startColumn + this.getStartTextToInsert(type).length,
|
||||
startLineNumber: currentSelection.startLineNumber,
|
||||
endColumn: currentSelection.endColumn - this.getEndTextToInsert(type).length,
|
||||
endLineNumber: currentSelection.endLineNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if user wants to perform an undo operation
|
||||
* @param selection current user selection
|
||||
* @param type markdown button type
|
||||
* @param lineType markdown line type
|
||||
* @param editorModel text model for the cell
|
||||
*/
|
||||
private isUndoOperation(selection: Selection, type: MarkdownButtonType, lineType: MarkdownLineType, editorModel: TextModel): boolean {
|
||||
if (lineType === MarkdownLineType.BEGIN_AND_END_LINES) {
|
||||
let selectedText = this.getExtendedSelectedText(selection, type, lineType, editorModel);
|
||||
return selectedText && selectedText.startsWith(this.getStartTextToInsert(type)) && selectedText.endsWith(this.getEndTextToInsert(type));
|
||||
} else {
|
||||
return this.everyLineMatchesBeginString(selection, type, editorModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extended selected text (current selection + potential beginning + ending transformed text)
|
||||
* @param selection Current selection in editor
|
||||
* @param type Markdown Button Type
|
||||
* @param lineType Markdown Line Type
|
||||
* @param editorModel TextModel
|
||||
*/
|
||||
private getExtendedSelectedText(selection: Selection, type: MarkdownButtonType, lineType: MarkdownLineType, editorModel: TextModel): string {
|
||||
if (lineType === MarkdownLineType.BEGIN_AND_END_LINES) {
|
||||
return editorModel.getValueInRange({
|
||||
startColumn: selection.startColumn - this.getStartTextToInsert(type).length,
|
||||
startLineNumber: selection.startLineNumber,
|
||||
endColumn: selection.endColumn + this.getEndTextToInsert(type).length,
|
||||
endLineNumber: selection.endLineNumber
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether all lines start with the expected transformed text for actions that match the EVERY_LINE line type
|
||||
* @param selection Current selection in editor
|
||||
* @param type Markdown Button Type
|
||||
* @param editorModel TextModel
|
||||
*/
|
||||
private everyLineMatchesBeginString(selection: Selection, type: MarkdownButtonType, editorModel: TextModel): boolean {
|
||||
if (this.getMarkdownLineType(type) !== MarkdownLineType.EVERY_LINE) {
|
||||
return false;
|
||||
}
|
||||
for (let selectionLine = selection.startLineNumber; selectionLine <= selection.endLineNumber; selectionLine++) {
|
||||
if (!editorModel.getLineContent(selectionLine).startsWith(this.getStartTextToInsert(type))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new IRange object with arbitrary offsets
|
||||
* @param initialRange range object
|
||||
* @param startColumnOffset
|
||||
* @param startLineNumberOffset
|
||||
* @param endColumnOffset
|
||||
* @param endLineNumberOffset
|
||||
*/
|
||||
private getIRangeWithOffsets(initialRange: IRange, startColumnOffset = 0, startLineNumberOffset = 0, endColumnOffset = 0, endLineNumberOffset = 0): IRange {
|
||||
return {
|
||||
startColumn: initialRange.startColumn + startColumnOffset,
|
||||
startLineNumber: initialRange.startLineNumber + startLineNumberOffset,
|
||||
endColumn: initialRange.endColumn + endColumnOffset,
|
||||
endLineNumber: initialRange.endLineNumber + endLineNumberOffset
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export enum MarkdownButtonType {
|
||||
BOLD,
|
||||
ITALIC,
|
||||
CODE,
|
||||
HIGHLIGHT,
|
||||
LINK,
|
||||
UNORDERED_LIST,
|
||||
ORDERED_LIST,
|
||||
IMAGE
|
||||
}
|
||||
|
||||
// If ALL_LINES, we need to insert markdown at each line (e.g. lists)
|
||||
export enum MarkdownLineType {
|
||||
BEGIN_AND_END_LINES,
|
||||
EVERY_LINE
|
||||
}
|
||||
@@ -300,7 +300,7 @@ export abstract class NotebookInput extends EditorInput {
|
||||
|
||||
private async setTrustForNewEditor(newInput: IEditorInput | undefined): Promise<void> {
|
||||
let model = this._model.getNotebookModel();
|
||||
if (model?.trustedMode && newInput?.resource !== this.resource) {
|
||||
if (model?.trustedMode && newInput && newInput.resource !== this.resource) {
|
||||
await this.notebookService.serializeNotebookStateChange(newInput.resource, NotebookChangeType.Saved, undefined, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ 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 { LabeledMenuItemActionItem, fillInActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
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';
|
||||
@@ -56,11 +55,10 @@ import { TextCellComponent } from 'sql/workbench/contrib/notebook/browser/cellVi
|
||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
import { IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
|
||||
export const NOTEBOOK_SELECTOR: string = 'notebook-component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: NOTEBOOK_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./notebook.component.html'))
|
||||
@@ -104,8 +102,8 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
@Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService,
|
||||
@Inject(ITextFileService) private textFileService: ITextFileService,
|
||||
@Inject(ILogService) private readonly logService: ILogService,
|
||||
@Inject(ITelemetryService) private telemetryService: ITelemetryService,
|
||||
@Inject(ICommandService) private commandService: ICommandService
|
||||
@Inject(ICommandService) private commandService: ICommandService,
|
||||
@Inject(IAdsTelemetryService) private adstelemetryService: IAdsTelemetryService
|
||||
) {
|
||||
super();
|
||||
this.updateProfile();
|
||||
@@ -310,7 +308,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
layoutChanged: this._notebookParams.input.layoutChanged,
|
||||
capabilitiesService: this.capabilitiesService,
|
||||
editorLoadedTimestamp: this._notebookParams.input.editorOpenedTimestamp
|
||||
}, this.profile, this.logService, this.notificationService, this.telemetryService);
|
||||
}, this.profile, this.logService, this.notificationService, this.adstelemetryService);
|
||||
let trusted = await this.notebookService.isNotebookTrustCached(this._notebookParams.notebookUri, this.isDirty());
|
||||
this._register(model.onError((errInfo: INotification) => this.handleModelError(errInfo)));
|
||||
this._register(model.contentChanged((change) => this.handleContentChanged(change)));
|
||||
@@ -538,7 +536,7 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.editorService.activeEditor.matches(this.notebookParams.input);
|
||||
return this.editorService.activeEditor ? this.editorService.activeEditor.matches(this.notebookParams.input) : false;
|
||||
}
|
||||
|
||||
isVisible(): boolean {
|
||||
@@ -666,10 +664,17 @@ export class NotebookComponent extends AngularDisposable implements OnInit, OnDe
|
||||
|
||||
navigateToSection(id: string): void {
|
||||
id = id.toLowerCase();
|
||||
let chromeHeight: number = 0;
|
||||
let elBody: HTMLElement = document.body;
|
||||
let tabBar = elBody.querySelector('.title.tabs') as HTMLElement;
|
||||
let actionBar = elBody.querySelector('.editor-toolbar.actionbar-container') as HTMLElement;
|
||||
let section = find(this.getSectionElements(), s => s.relativeUri && s.relativeUri.toLowerCase() === id);
|
||||
if (section) {
|
||||
// Scroll this section to the top of the header instead of just bringing header into view.
|
||||
let scrollTop = section.headerEl.offsetTop;
|
||||
if (tabBar && actionBar) {
|
||||
chromeHeight = tabBar.scrollHeight + actionBar.scrollHeight;
|
||||
}
|
||||
let scrollTop: number = section.headerEl.getBoundingClientRect().top - (chromeHeight + 10);
|
||||
(<HTMLElement>this.container.nativeElement).scrollTo({
|
||||
top: scrollTop,
|
||||
behavior: 'smooth'
|
||||
|
||||