Compare commits

...

41 Commits

Author SHA1 Message Date
Anthony Dresser
6c2a0f3d40 import correct welcome page (#10117) 2020-04-21 21:24:13 -07:00
Amir Omidi
283c851494 Clear all saved accounts regardless of failure (#10107) 2020-04-21 13:56:04 -07:00
Karl Burtram
8e63ca8d0a Put new welcome page behind preview features flag (#10099) 2020-04-21 13:55:45 -07:00
Chris LaFreniere
fbce1719c9 Check for file scheme in linkhandler (#10090) (#10096) 2020-04-20 22:04:07 -07:00
v-bbrady
81ae52f75f Bbrady/release port/fixes video and admin pack images (#10053)
* merge cherry picked changes

* merges cherry picked commit
2020-04-20 20:48:28 -07:00
Amir Omidi
38ca77c8c5 Enable file based storage by default (#10061) (#10077) 2020-04-20 20:48:05 -07:00
Amir Omidi
5275bb9e56 Revert "Create new row upon focus on last row (#9046)" (#10039) (#10087)
This reverts commit 6b9184aa15.
2020-04-20 20:47:42 -07:00
Cory Rivera
a6816a5de8 Check treeItem first when building search path in searchJupyterBooks. (#10083) (#10092) 2020-04-20 16:11:49 -07:00
Hale Rankin
728bc76b4b Notebook UI - Fixes navigation offset (#10067) (#10074)
* Addresses bug: 10062. Replaced scrollTop with getBoundingClientRect.top minus the combined height of the top tabs and action bar.

* Setting initial value of chrome offset, and checking for existence of both tool bars before getting their heights.
2020-04-20 10:28:24 -07:00
Barbara Valdez
21dd79ab03 Fix relative paths on anchor links (#9958) (#10070)
* Fix relative links in notebooks
2020-04-17 17:07:41 -07:00
Alan Ren
ee60400e3b fix clipping issue (#10020) (#10040)
* fix clipping issue

* remove hardcoded height
2020-04-17 14:03:18 -07:00
Alan Ren
99f37006a5 more dashboard fixes (#9937) (#9953)
* unify the panel styles

* min-width

* min-width

* fix issues

* fix css selector
2020-04-17 13:58:15 -07:00
Hale Rankin
00b08bd677 UI - Markdown toolbar now behind preview flag (#10024) (#10050)
* Adding enablePreviewFeatures check before showing the new toolbar.

* Removed unused code.

* Added hook to trigger onDidChangeConfiguration -- this makes the UI change after user has checked or unchecked, without having to restart the app.

* Initializing the component with the current config value of enablePreviewFeatures.
2020-04-17 13:23:27 -07:00
Maddy
1503e3846f added proper check (#10032) (#10054) 2020-04-17 11:57:34 -07:00
Maddy
370e521910 Rename/books viewlet sections (#10044) (#10048)
* renamed viewlet sections

* template to provided
2020-04-17 10:13:04 -07:00
Cory Rivera
2ef0b7adb8 Check conda-forge channel first when installing conda packages. (#10035) (#10047) 2020-04-17 10:10:44 -07:00
Maddy
ebd307d78e Fix/find context correction (#9949) (#10045)
* trigger input change on new notebooks

* return to avoid further executions

* remove unnecessary check
2020-04-16 17:18:55 -07:00
Maddy
d1251ce57e replaced watch with watchFile (#9873) (#10046)
* replaced watch with watchFile

* testing debounce

* changed the beounce delay to 1500
2020-04-16 17:15:45 -07:00
Chris LaFreniere
5e91e86360 Notebooks: Fix Issue Around Load Error when Tables Have No Rows (#9980) (#10013)
* Table element children length check

* Add another check
2020-04-16 15:19:54 -07:00
Chris LaFreniere
c81f5580d1 Bring back hover buttons for adding cells (#10012) (#10031) 2020-04-16 15:18:35 -07:00
v-bbrady
27e3b4995a Welcome responsive container (#9946) (#9870) (#10033)
* adds responsiveness to the left navigation pane

* fixes style

* removes color from css

* updates style
2020-04-16 15:15:59 -07:00
v-bbrady
551536e666 Fix duplicating list on extension pack (#9992) (#10003) (#10010)
* makes the preview button hover state stay active when hovering over tooltip

* fixes the duplicating list on the extension pack when a 2nd welcome page tab is opened
2020-04-16 15:13:22 -07:00
Anthony Dresser
f3d4a55bb1 Merge from vscode ff915844119ce9485abfe8aa9076ec76b5300ddd (#10030) 2020-04-16 15:12:30 -07:00
Alex Ma
4fc9057025 Fix for edit data sizing of table (#9972) (#10007)
* Fix for style

* removed inline-block as its unnecessary
2020-04-16 15:11:58 -07:00
Amir Omidi
c30b8cde42 Listen on localhost only (#9997) (#10000) 2020-04-16 15:10:40 -07:00
Amir Omidi
f4464f352f Put cloud shell behind preview flag (#9995) (#9999) 2020-04-16 15:08:02 -07:00
Amir Omidi
2e127582bd Allow users to use file based key storage if they have to (#9993)
* Don't enforce the password limit for file keytar (#9974)

* Allow users to use file based keychain if they have to

* Don't enforce this limit for FS keytar

* Spacing

* Allow users to use file based keychain if they have to (#9952)
2020-04-16 15:07:19 -07:00
Anthony Dresser
ae13131370 Add innoupdater for windows fast update (#10028)
* add innoupdater for fast update (#10015)

* set default back to true
2020-04-16 14:52:20 -07:00
Shafiq Ur Rahman
64ccb21d26 Fixes #9397 Launch onenote links (#9931) (#10006)
* Fixes #9397 Launch onenote links

* Limit the change to linkhandler directive
2020-04-15 16:53:08 -07:00
Anthony Dresser
5b7224fa5e enablewindowsbackgroundupdate false 2020-04-15 16:15:19 -07:00
rajeshka
f364a60eca Added Notebook telemetry for livesite notebooks (#9948) (#9990)
* Added Notebook telemetry for livesite

* added back the metadata retension code

* Unified Telemetry services

* fixed names

* Fixed texts to use new NullAdsTelemetryService

* Validate GUID before sending it

* made GUID check a bit more robust

Co-authored-by: Rajesh Kamath <rajkashop@hotmail.com>

Co-authored-by: Rajesh Kamath <rajkashop@hotmail.com>
2020-04-15 15:34:44 -07:00
Hale Rankin
fc5cf99f02 UI feature - Notebook markdown toolbar (#9853) (#9991)
* Markdown editor toolbar - initial commit

* Moved icons. Refactored new toolbar component to include markup.

* Edited markdown toolbar component and referencing in textCell component markup.

* Completed UI updates for selected cell toolbar and markdown toolbar. 

* Modified import path to Event class. Changed EventEmitter to Emitter.

* Cleaned up newly added toolbar components

* Works sometimes sometimes editor is null

* Removed commented out code and styles. CellToolbar and MarkdownToolbar: moved component markup into html file.

* Added icon for highlight. Removed more commented code. Re-scoped two styles to their parent components. Corrected templateUrl reference for the new toolbars.

* Adjusted paths to SVG icons from toolbar stylesheet.

* Add lists and links

* Refactor out of component, add actionbar

* Support for nothing selected, quick bug fix

* Updated split view icons. Added markdown tool backgrounds and cell border colors to color registry and parent components. Updated toolbar icons to use mask as this allows the SVG icon colors to be adjusted on theme change.

* Added colorRegistry entries for code cell. Removed colors from styles. Running registerThemingParticipant from code.component.

* Revised code component style rules and corrected syntax.

* Merged in Chris' working branch and removed unused markup.

* Corrected styles and moved another color into colorRegistry for use in new markdown toolbar.

* Corrected style error. Overrode left position of content inside textCell and codeCell. Added more entries to colorRegistry.

* Moved toolbar and editor icons to common-icons location. Updated related stylesheet. Revised color theming rules for markdown and code cells.

* Added themed border between markdown and preview. Moved all notebook themes into notebookStyles.ts

* Merged in latest from origin/master and included a small but significant style tweak to light theme code cell toolbar.

* Add Undo Support for Markdown Toolbar (#9915)

* Remove comment

* Renamed registered notebook colors and prefixed with notebook. Moved markdown component theme colors into notebookStyles.ts. Removed colors from cellToolbar styles. Revised icon class names to generic names for better re-use. Removed commented markup.

Co-authored-by: chlafreniere <hichise@gmail.com>
Co-authored-by: Chris LaFreniere <40371649+chlafreniere@users.noreply.github.com>

Co-authored-by: chlafreniere <hichise@gmail.com>
Co-authored-by: Chris LaFreniere <40371649+chlafreniere@users.noreply.github.com>
2020-04-15 13:01:35 -07:00
Cory Rivera
14fdd6f529 Only show Create Insight button in Query Editor charts. (#9973) (#9988) 2020-04-15 12:03:45 -07:00
Cory Rivera
377a327cac Add Open Notebook Folder functionality to Books viewlet. (#9939) (#9978) 2020-04-15 10:29:07 -07:00
Kim Santiago
139609a7c3 center collapse icon (#9966) (#9969)
center collapse icon. port request for PR (#9966) (#9969)
2020-04-14 14:56:59 -07:00
Anthony Dresser
b80bc686b2 Release rc (#9971)
* release rc builds

* allow ref heads
2020-04-14 13:16:32 -07:00
Anthony Dresser
dc7fd013a6 enable cross partition queryies (#9961) 2020-04-14 13:16:20 -07:00
Alan Ren
5375629585 show databases for azure server (#9951) (#9954) 2020-04-14 09:59:55 -07:00
AzureDataStudio
339a3bcbf6 add cross partition query 2020-04-13 02:33:51 -07:00
AzureDataStudio
e627619c7a Merge branch 'master' into release/1.17 2020-04-12 22:54:12 -07:00
Anthony Dresser
26870655b6 try cross partition queries 2020-04-09 15:58:17 -07:00
133 changed files with 2739 additions and 992 deletions

View File

@@ -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,

View File

@@ -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)

View File

@@ -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'
]);

View File

@@ -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]

View File

@@ -84,7 +84,7 @@
},
"azure.noSystemKeychain": {
"type": "boolean",
"default": false,
"default": true,
"description": "%config.noSystemKeychain%",
"when": "isLinux || isWeb"
}

View File

@@ -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}`);

View File

@@ -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 = () => {

View File

@@ -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;
}

View File

@@ -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/"
},
{

View File

@@ -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 { }

View File

@@ -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": {

View File

@@ -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"
}
]

View File

@@ -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"
}

View 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="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View 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

View File

@@ -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> {

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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"); }

View 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);
};
}

View File

@@ -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}`);

View File

@@ -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);
}

View File

@@ -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> {

View File

@@ -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: [

View File

@@ -1,6 +1,7 @@
{
"extends": "../shared.tsconfig.json",
"compilerOptions": {
"experimentalDecorators": true,
"lib": [
"dom"
],

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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>
`
})

View 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

View 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

View 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

View 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

View 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

View File

@@ -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;

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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'
}

View File

@@ -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"));

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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%';
}
}

View File

@@ -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': {}
}
}
];

View File

@@ -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);
});

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
.editDataGridPanel.slickgridContainer {
height: 447px;
width: 632px;
height: 100%;
width: 100%;
}

View File

@@ -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>

View File

@@ -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() {
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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 }
]);
}
}

View File

@@ -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;
}

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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>

View File

@@ -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));

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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'

Some files were not shown because too many files have changed in this diff Show More