diff options
author | Sandeep Somavarapu <sasomava@microsoft.com> | 2022-05-20 11:15:27 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-20 11:15:27 +0300 |
commit | 078c77cf4976b07f334b76112779a020515777cf (patch) | |
tree | 69e3ca46ce2ab78fa23336ab808a2c3822cfd7e0 | |
parent | 04e34f25549ca272802d8532a5616b48ef262b4e (diff) | |
parent | fc9732a6833ad9b1ed9e4886dae1fc1e5f8db45e (diff) |
Merge branch 'main' into sandy081/policysandy081/policy
135 files changed, 4070 insertions, 2632 deletions
diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml new file mode 100644 index 00000000000..270e9523938 --- /dev/null +++ b/.github/workflows/basic.yml @@ -0,0 +1,142 @@ +name: Basic checks + +on: + # push: + # branches: + # - main + # - release/* + pull_request: + branches: + - main + - release/* + +jobs: + main: + name: Compilation, Unit and Integration Tests + runs-on: ubuntu-latest + timeout-minutes: 40 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + + # TODO: rename azure-pipelines/linux/xvfb.init to github-actions + - name: Setup Build Environment + run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 + sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb + sudo chmod +x /etc/init.d/xvfb + sudo update-rc.d xvfb defaults + sudo service xvfb start + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Compute node modules cache key + id: nodeModulesCacheKey + run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" + - name: Cache node modules + id: cacheNodeModules + uses: actions/cache@v3 + with: + path: "**/node_modules" + key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} + restore-keys: ${{ runner.os }}-cacheNodeModules21- + - name: Get yarn cache directory path + id: yarnCacheDirPath + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + run: echo "::set-output name=dir::$(yarn cache dir)" + - name: Cache yarn directory + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + uses: actions/cache@v3 + with: + path: ${{ steps.yarnCacheDirPath.outputs.dir }} + key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} + restore-keys: ${{ runner.os }}-yarnCacheDir- + - name: Execute yarn + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + run: yarn --frozen-lockfile --network-timeout 180000 + + - name: Compile and Download + run: yarn npm-run-all --max_old_space_size=4095 -lp compile "electron x64" playwright-install download-builtin-extensions + + - name: Compile Integration Tests + run: yarn --cwd test/integration/browser compile + + - name: Run Unit Tests + id: electron-unit-tests + run: DISPLAY=:10 ./scripts/test.sh + + - name: Run Integration Tests (Electron) + id: electron-integration-tests + run: DISPLAY=:10 ./scripts/test-integration.sh + + hygiene: + name: Hygiene and Layering + runs-on: ubuntu-latest + timeout-minutes: 40 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Compute node modules cache key + id: nodeModulesCacheKey + run: echo "::set-output name=value::$(node build/azure-pipelines/common/computeNodeModulesCacheKey.js)" + - name: Cache node modules + id: cacheNodeModules + uses: actions/cache@v3 + with: + path: "**/node_modules" + key: ${{ runner.os }}-cacheNodeModules21-${{ steps.nodeModulesCacheKey.outputs.value }} + restore-keys: ${{ runner.os }}-cacheNodeModules21- + - name: Get yarn cache directory path + id: yarnCacheDirPath + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + run: echo "::set-output name=dir::$(yarn cache dir)" + - name: Cache yarn directory + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + uses: actions/cache@v3 + with: + path: ${{ steps.yarnCacheDirPath.outputs.dir }} + key: ${{ runner.os }}-yarnCacheDir-${{ steps.nodeModulesCacheKey.outputs.value }} + restore-keys: ${{ runner.os }}-yarnCacheDir- + - name: Execute yarn + if: ${{ steps.cacheNodeModules.outputs.cache-hit != 'true' }} + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 + run: yarn --frozen-lockfile --network-timeout 180000 + + - name: Download Playwright + run: yarn playwright-install + + - name: Run Hygiene Checks + run: yarn gulp hygiene + + - name: Run Valid Layers Checks + run: yarn valid-layers-check + + - name: Compile /build/ + run: yarn --cwd build compile + + - name: Check clean git state + run: ./.github/workflows/check-clean-git-state.sh + + - name: Run eslint + run: yarn eslint + + - name: Run vscode-dts Compile Checks + run: yarn vscode-dts-compile-check + + - name: Run Trusted Types Checks + run: yarn tsec-compile-check @@ -1,4 +1,4 @@ disturl "https://electronjs.org/headers" -target "17.4.3" +target "17.4.4" runtime "electron" build_from_source "true" diff --git a/build/azure-pipelines/linux/product-build-linux-client.yml b/build/azure-pipelines/linux/product-build-linux-client.yml index 4e6f8f13d0e..7dba0eef378 100644 --- a/build/azure-pipelines/linux/product-build-linux-client.yml +++ b/build/azure-pipelines/linux/product-build-linux-client.yml @@ -122,16 +122,6 @@ steps: - script: | set -e export npm_config_arch=$(NPM_ARCH) - # node-gyp@9.0.0 shipped with node@16.15.0 starts using config.gypi - # from the custom headers path if dist-url option was set instead of - # using the config value from the process. Electron builds with pointer compression - # enabled for x64 and arm64, but incorrectly ships a single copy of config.gypi - # with v8_enable_pointer_compression option always set for all target architectures. - # We use the force_process_config option to use the config.gypi from the - # nodejs process executing npm for 32-bit architectures. - if [ "$NPM_ARCH" = "armv7l" ]; then - export npm_config_force_process_config="true" - fi if [ -z "$CC" ] || [ -z "$CXX" ]; then # Download clang based on chromium revision used by vscode diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 286283a31dc..4b746afc2a1 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -103,14 +103,6 @@ steps: . build/azure-pipelines/win32/retry.ps1 $ErrorActionPreference = "Stop" $env:npm_config_arch="$(VSCODE_ARCH)" - # node-gyp@9.0.0 shipped with node@16.15.0 starts using config.gypi - # from the custom headers path if dist-url option was set instead of - # using the config value from the process. Electron builds with pointer compression - # enabled for x64 and arm64, but incorrectly ships a single copy of config.gypi - # with v8_enable_pointer_compression option always set for all target architectures. - # We use the force_process_config option to use the config.gypi from the - # nodejs process executing npm for 32-bit architectures. - if ('$(VSCODE_ARCH)' -eq 'ia32') { $env:npm_config_force_process_config="true" } $env:CHILD_CONCURRENCY="1" retry { exec { yarn --frozen-lockfile --check-files } } env: diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 7b3a5043154..94b22026a07 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -65,7 +65,6 @@ const vscodeResources = [ 'out-build/vs/base/browser/ui/codicons/codicon/**', 'out-build/vs/base/parts/sandbox/electron-browser/preload.js', 'out-build/vs/platform/environment/node/userDataPath.js', - 'out-build/vs/platform/extensions/node/extensionHostStarterWorkerMain.js', 'out-build/vs/workbench/browser/media/*-theme.css', 'out-build/vs/workbench/contrib/debug/**/*.json', 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', diff --git a/build/hygiene.js b/build/hygiene.js index a5d2b080172..1668e508ec9 100644 --- a/build/hygiene.js +++ b/build/hygiene.js @@ -54,7 +54,7 @@ function hygiene(some, linting = true) { const m = /([^\t\n\r\x20-\x7E⊃⊇✔︎✓🎯⚠️🛑🔴🚗🚙🚕🎉✨❗⇧⌥⌘×÷¦⋯…↑↓→→←↔⟷·•●◆▼⟪⟫┌└├⏎↩√φ]+)/g.exec(line); if (m) { console.error( - file.relative + `(${i + 1},${m.index + 1}): Unexpected unicode character: "${m[0]}". To suppress, use // allow-any-unicode-next-line` + file.relative + `(${i + 1},${m.index + 1}): Unexpected unicode character: "${m[0]}" (charCode: ${m[0].charCodeAt(0)}). To suppress, use // allow-any-unicode-next-line` ); errorCount++; } diff --git a/cgmanifest.json b/cgmanifest.json index a4a8dc1be73..d153e97eb0f 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "322f1c3f8907f2592eef5b5e03a97045e30df9e3" + "commitHash": "085a15fd95969f3c61a52b39d64a7048d306dabe" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "17.4.3" + "version": "17.4.4" }, { "component": { diff --git a/extensions/css-language-features/client/src/browser/cssClientMain.ts b/extensions/css-language-features/client/src/browser/cssClientMain.ts index 0cfde9025f3..8fa2d81bd03 100644 --- a/extensions/css-language-features/client/src/browser/cssClientMain.ts +++ b/extensions/css-language-features/client/src/browser/cssClientMain.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ExtensionContext, Uri } from 'vscode'; -import { LanguageClientOptions } from 'vscode-languageclient'; +import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor } from '../cssClient'; import { LanguageClient } from 'vscode-languageclient/browser'; @@ -15,8 +15,10 @@ declare const TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string }; }; +let client: BaseLanguageClient | undefined; + // this method is called when vs code is activated -export function activate(context: ExtensionContext) { +export async function activate(context: ExtensionContext) { const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/cssServerMain.js'); try { const worker = new Worker(serverMain.toString()); @@ -24,9 +26,17 @@ export function activate(context: ExtensionContext) { return new LanguageClient(id, name, clientOptions, worker); }; - startClient(context, newLanguageClient, { TextDecoder }); + client = await startClient(context, newLanguageClient, { TextDecoder }); } catch (e) { console.log(e); } } + +export async function deactivate(): Promise<void> { + if (client) { + await client.stop(); + client = undefined; + } +} + diff --git a/extensions/css-language-features/client/src/cssClient.ts b/extensions/css-language-features/client/src/cssClient.ts index 282c347bdd8..6f6238465d8 100644 --- a/extensions/css-language-features/client/src/cssClient.ts +++ b/extensions/css-language-features/client/src/cssClient.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { commands, CompletionItem, CompletionItemKind, ExtensionContext, languages, Position, Range, SnippetString, TextEdit, window, TextDocument, CompletionContext, CancellationToken, ProviderResult, CompletionList, FormattingOptions, workspace } from 'vscode'; -import { Disposable, LanguageClientOptions, ProvideCompletionItemsSignature, NotificationType, CommonLanguageClient, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient'; +import { Disposable, LanguageClientOptions, ProvideCompletionItemsSignature, NotificationType, BaseLanguageClient, DocumentRangeFormattingParams, DocumentRangeFormattingRequest } from 'vscode-languageclient'; import * as nls from 'vscode-nls'; import { getCustomDataSource } from './customData'; import { RequestService, serveFileSystemRequests } from './requests'; @@ -15,7 +15,7 @@ namespace CustomDataChangedNotification { const localize = nls.loadMessageBundle(); -export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => CommonLanguageClient; +export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; export interface Runtime { TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string } }; @@ -39,7 +39,7 @@ interface CSSFormatSettings { const cssFormatSettingKeys: (keyof CSSFormatSettings)[] = ['newlineBetweenSelectors', 'newlineBetweenRules', 'spaceAroundSelectorSeparator', 'braceStyle', 'preserveNewLines', 'maxPreserveNewLines']; -export function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime) { +export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<BaseLanguageClient> { const customDataSource = getCustomDataSource(context.subscriptions); @@ -100,31 +100,25 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua // Create the language client and start the client. let client = newLanguageClient('css', localize('cssserver.name', 'CSS Language Server'), clientOptions); client.registerProposedFeatures(); - client.onReady().then(() => { + await client.start(); + + client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); + customDataSource.onDidChange(() => { client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); - customDataSource.onDidChange(() => { - client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); - }); + }); - // manually register / deregister format provider based on the `css/less/scss.format.enable` setting avoiding issues with late registration. See #71652. - for (const registration of formatterRegistrations) { - updateFormatterRegistration(registration); - context.subscriptions.push({ dispose: () => registration.provider?.dispose() }); - context.subscriptions.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(registration.settingId) && updateFormatterRegistration(registration))); - } + // manually register / deregister format provider based on the `css/less/scss.format.enable` setting avoiding issues with late registration. See #71652. + for (const registration of formatterRegistrations) { + updateFormatterRegistration(registration); + context.subscriptions.push({ dispose: () => registration.provider?.dispose() }); + context.subscriptions.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(registration.settingId) && updateFormatterRegistration(registration))); + } - serveFileSystemRequests(client, runtime); - }); + serveFileSystemRequests(client, runtime); - let disposable = client.start(); - // Push the disposable to the context's subscriptions so that the - // client can be deactivated on extension deactivation - context.subscriptions.push(disposable); - client.onReady().then(() => { - context.subscriptions.push(initCompletionProvider()); - }); + context.subscriptions.push(initCompletionProvider()); function initCompletionProvider(): Disposable { const regionCompletionRegExpr = /^(\s*)(\/(\*\s*(#\w*)?)?)?$/; @@ -204,11 +198,10 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua } } } - console.log(JSON.stringify(params.options)); return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( client.protocol2CodeConverter.asTextEdits, (error) => { - client.handleFailedRequest(DocumentRangeFormattingRequest.type, error, []); + client.handleFailedRequest(DocumentRangeFormattingRequest.type, undefined, error, []); return Promise.resolve([]); } ); @@ -216,4 +209,6 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua }); } } + + return client; } diff --git a/extensions/css-language-features/client/src/node/cssClientMain.ts b/extensions/css-language-features/client/src/node/cssClientMain.ts index b88838d8912..dfbe121f822 100644 --- a/extensions/css-language-features/client/src/node/cssClientMain.ts +++ b/extensions/css-language-features/client/src/node/cssClientMain.ts @@ -6,11 +6,14 @@ import { getNodeFSRequestService } from './nodeFs'; import { ExtensionContext, extensions } from 'vscode'; import { startClient, LanguageClientConstructor } from '../cssClient'; -import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node'; +import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient, BaseLanguageClient } from 'vscode-languageclient/node'; import { TextDecoder } from 'util'; + +let client: BaseLanguageClient | undefined; + // this method is called when vs code is activated -export function activate(context: ExtensionContext) { +export async function activate(context: ExtensionContext) { const clientMain = extensions.getExtension('vscode.css-language-features')?.packageJSON?.main || ''; const serverMain = `./server/${clientMain.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/cssServerMain`; @@ -30,5 +33,12 @@ export function activate(context: ExtensionContext) { return new LanguageClient(id, name, serverOptions, clientOptions); }; - startClient(context, newLanguageClient, { fs: getNodeFSRequestService(), TextDecoder }); + client = await startClient(context, newLanguageClient, { fs: getNodeFSRequestService(), TextDecoder }); +} + +export async function deactivate(): Promise<void> { + if (client) { + await client.stop(); + client = undefined; + } } diff --git a/extensions/css-language-features/client/src/requests.ts b/extensions/css-language-features/client/src/requests.ts index 6aea3ab8fad..f19918e57ef 100644 --- a/extensions/css-language-features/client/src/requests.ts +++ b/extensions/css-language-features/client/src/requests.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Uri, workspace } from 'vscode'; -import { RequestType, CommonLanguageClient } from 'vscode-languageclient'; +import { RequestType, BaseLanguageClient } from 'vscode-languageclient'; import { Runtime } from './cssClient'; export namespace FsContentRequest { @@ -18,7 +18,7 @@ export namespace FsReadDirRequest { export const type: RequestType<string, [string, FileType][], any> = new RequestType('fs/readDir'); } -export function serveFileSystemRequests(client: CommonLanguageClient, runtime: Runtime) { +export function serveFileSystemRequests(client: BaseLanguageClient, runtime: Runtime) { client.onRequest(FsContentRequest.type, (param: { uri: string; encoding?: string }) => { const uri = Uri.parse(param.uri); if (uri.scheme === 'file' && runtime.fs) { diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index e9ea587d4db..c4955243c8f 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -336,7 +336,10 @@ "type": "string", "scope": "resource", "default": "collapse", - "enum": ["collapse", "expand"], + "enum": [ + "collapse", + "expand" + ], "markdownDescription": "%css.format.braceStyle.desc%" }, "css.format.preserveNewLines": { @@ -638,7 +641,10 @@ "type": "string", "scope": "resource", "default": "collapse", - "enum": ["collapse", "expand"], + "enum": [ + "collapse", + "expand" + ], "markdownDescription": "%scss.format.braceStyle.desc%" }, "scss.format.preserveNewLines": { @@ -941,7 +947,10 @@ "type": "string", "scope": "resource", "default": "collapse", - "enum": ["collapse", "expand"], + "enum": [ + "collapse", + "expand" + ], "markdownDescription": "%less.format.braceStyle.desc%" }, "less.format.preserveNewLines": { @@ -985,7 +994,7 @@ ] }, "dependencies": { - "vscode-languageclient": "^7.0.0", + "vscode-languageclient": "^8.0.1", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.3" }, diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index 18c39540516..d2f0443e65b 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -10,8 +10,8 @@ "main": "./out/node/cssServerMain", "browser": "./dist/browser/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^5.4.2", - "vscode-languageserver": "^7.0.0", + "vscode-css-languageservice": "^6.0.1", + "vscode-languageserver": "^8.0.1", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/css-language-features/server/src/cssServer.ts b/extensions/css-language-features/server/src/cssServer.ts index 40e05b13ab1..3eed3962879 100644 --- a/extensions/css-language-features/server/src/cssServer.ts +++ b/extensions/css-language-features/server/src/cssServer.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { - Connection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder, TextDocumentSyncKind, NotificationType, Disposable, TextDocumentIdentifier, Range, FormattingOptions, TextEdit + Connection, TextDocuments, InitializeParams, InitializeResult, ServerCapabilities, ConfigurationRequest, WorkspaceFolder, TextDocumentSyncKind, NotificationType, Disposable, TextDocumentIdentifier, Range, FormattingOptions, TextEdit, Diagnostic } from 'vscode-languageserver'; import { URI } from 'vscode-uri'; import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, TextDocument, Position, CSSFormatConfiguration } from 'vscode-css-languageservice'; @@ -64,6 +64,9 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // After the server has started the client sends an initialize request. The server receives // in the passed params the rootPath of the workspace plus the client capabilities. connection.onInitialize((params: InitializeParams): InitializeResult => { + + const initializationOptions = params.initializationOptions as any || {}; + workspaceFolders = (<any>params).workspaceFolders; if (!Array.isArray(workspaceFolders)) { workspaceFolders = []; @@ -72,7 +75,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) } } - requestService = getRequestService(params.initializationOptions?.handledSchemas || ['file'], connection, runtime); + requestService = getRequestService(initializationOptions?.handledSchemas || ['file'], connection, runtime); function getClientCapability<T>(name: string, def: T) { const keys = name.split('.'); @@ -88,7 +91,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) const snippetSupport = !!getClientCapability('textDocument.completion.completionItem.snippetSupport', false); scopedSettingsSupport = !!getClientCapability('workspace.configuration', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); - formatterMaxNumberOfEdits = params.initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; + formatterMaxNumberOfEdits = initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; languageServices.css = getCSSLanguageService({ fileSystemProvider: requestService, clientCapabilities: params.capabilities }); languageServices.scss = getSCSSLanguageService({ fileSystemProvider: requestService, clientCapabilities: params.capabilities }); @@ -110,8 +113,8 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) colorProvider: {}, foldingRangeProvider: true, selectionRangeProvider: true, - documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true, - documentFormattingProvider: params.initializationOptions?.provideFormatter === true, + documentRangeFormattingProvider: initializationOptions?.provideFormatter === true, + documentFormattingProvider: initializationOptions?.provideFormatter === true, }; return { capabilities }; }); @@ -135,7 +138,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) let promise = documentSettings[textDocument.uri]; if (!promise) { const configRequestParam = { items: [{ scopeUri: textDocument.uri, section: textDocument.languageId }] }; - promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => s[0]); + promise = connection.sendRequest(ConfigurationRequest.type, configRequestParam).then(s => s[0] as LanguageSettings | undefined); documentSettings[textDocument.uri] = promise; } return promise; @@ -145,12 +148,12 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration(change => { - updateConfiguration(<Settings>change.settings); + updateConfiguration(change.settings as any); }); - function updateConfiguration(settings: Settings) { + function updateConfiguration(settings: any) { for (const languageId in languageServices) { - languageServices[languageId].configure((settings as any)[languageId]); + languageServices[languageId].configure(settings[languageId]); } // reset all document settings documentSettings = {}; @@ -193,7 +196,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) const settingsPromise = getDocumentSettings(textDocument); Promise.all([settingsPromise, dataProvidersReady]).then(async ([settings]) => { const stylesheet = stylesheets.get(textDocument); - const diagnostics = getLanguageService(textDocument).doValidation(textDocument, stylesheet, settings); + const diagnostics = getLanguageService(textDocument).doValidation(textDocument, stylesheet, settings) as Diagnostic[]; // Send the computed diagnostics to VSCode. connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }); }, e => { diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index b7a44bc52c4..8749dcdebad 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -12,50 +12,50 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-css-languageservice@^5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.4.2.tgz#69ea74c000bd653dfc8e458a1720d28b9ffa5cfb" - integrity sha512-DT7+7vfdT2HDNjDoXWtYJ0lVDdeDEdbMNdK4PKqUl2MS8g7PWt7J5G9B6k9lYox8nOfhCEjLnoNC3UKHHCR1lg== +vscode-css-languageservice@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.0.1.tgz#ccf94944e094dcc5833d1b4ac276994b698e9283" + integrity sha512-81n/eeYuJwQdvpoy6IK1258PtPbO720fl13FcJ5YQECPyHMFkmld1qKHwPJkyLbLPfboqJPM53ys4xW8v+iBVw== dependencies: vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.16.0" - vscode-nls "^5.0.0" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-languageserver-types@3.16.0, vscode-languageserver-types@^3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== +vscode-languageserver-types@3.17.1, vscode-languageserver-types@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== +vscode-languageserver@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.1.tgz#56bd7a01f5c88af075a77f1d220edcb30fc4bdc7" + integrity sha512-sn7SjBwWm3OlmLtgg7jbM0wBULppyL60rj8K5HF0ny/MzN+GzPBX1kCvYdybhl7UW63V5V5tRVnyB8iwC73lSQ== dependencies: - vscode-languageserver-protocol "3.16.0" + vscode-languageserver-protocol "3.17.1" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 60ba7c2dcc3..76af92973f2 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -39,39 +39,39 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageclient@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz#b505c22c21ffcf96e167799757fca07a6bad0fb2" - integrity sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg== +vscode-languageclient@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" + integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== dependencies: minimatch "^3.0.4" - semver "^7.3.4" - vscode-languageserver-protocol "3.16.0" + semver "^7.3.5" + vscode-languageserver-protocol "3.17.1" -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== +vscode-languageserver-types@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== vscode-nls@^5.0.0: version "5.0.0" diff --git a/extensions/github/src/pushErrorHandler.ts b/extensions/github/src/pushErrorHandler.ts index 37f138caffb..5569d4fb480 100644 --- a/extensions/github/src/pushErrorHandler.ts +++ b/extensions/github/src/pushErrorHandler.ts @@ -102,13 +102,14 @@ async function handlePushError(repository: Repository, remote: Remote, refspec: let title = `Update ${remoteName}`; const head = repository.state.HEAD?.name; + let body: string | undefined; + if (head) { const commit = await repository.getCommit(head); - title = commit.message.replace(/\n.*$/m, ''); + title = commit.message.split('\n')[0]; + body = commit.message.slice(title.length + 1).trim(); } - let body: string | undefined; - const templates = await findPullRequestTemplates(repository.rootUri); if (templates.length > 0) { templates.sort((a, b) => a.path.localeCompare(b.path)); diff --git a/extensions/html-language-features/client/src/browser/htmlClientMain.ts b/extensions/html-language-features/client/src/browser/htmlClientMain.ts index b69cca75854..ab23520fe79 100644 --- a/extensions/html-language-features/client/src/browser/htmlClientMain.ts +++ b/extensions/html-language-features/client/src/browser/htmlClientMain.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, ExtensionContext, Uri } from 'vscode'; -import { LanguageClientOptions } from 'vscode-languageclient'; +import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor } from '../htmlClient'; import { LanguageClient } from 'vscode-languageclient/browser'; @@ -15,8 +15,10 @@ declare const TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string }; }; +let client: BaseLanguageClient | undefined; + // this method is called when vs code is activated -export function activate(context: ExtensionContext) { +export async function activate(context: ExtensionContext) { const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/htmlServerMain.js'); try { const worker = new Worker(serverMain.toString()); @@ -31,9 +33,17 @@ export function activate(context: ExtensionContext) { } }; - startClient(context, newLanguageClient, { TextDecoder, timer }); + client = await startClient(context, newLanguageClient, { TextDecoder, timer }); } catch (e) { console.log(e); } } + +export async function deactivate(): Promise<void> { + if (client) { + await client.stop(); + client = undefined; + } +} + diff --git a/extensions/html-language-features/client/src/htmlClient.ts b/extensions/html-language-features/client/src/htmlClient.ts index 7baceece6fb..6c44ceb72a8 100644 --- a/extensions/html-language-features/client/src/htmlClient.ts +++ b/extensions/html-language-features/client/src/htmlClient.ts @@ -13,7 +13,7 @@ import { } from 'vscode'; import { LanguageClientOptions, RequestType, DocumentRangeFormattingParams, - DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, TextDocumentIdentifier, RequestType0, Range as LspRange, Position as LspPosition, NotificationType, CommonLanguageClient + DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, TextDocumentIdentifier, RequestType0, Range as LspRange, Position as LspPosition, NotificationType, BaseLanguageClient } from 'vscode-languageclient'; import { FileSystemProvider, serveFileSystemRequests } from './requests'; import { getCustomDataSource } from './customData'; @@ -72,7 +72,7 @@ export interface TelemetryReporter { }): void; } -export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => CommonLanguageClient; +export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; export interface Runtime { TextDecoder: { new(encoding?: string): { decode(buffer: ArrayBuffer): string } }; @@ -83,18 +83,17 @@ export interface Runtime { }; } -export function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime) { +export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<BaseLanguageClient> { - let toDispose = context.subscriptions; + const toDispose = context.subscriptions; - - let documentSelector = ['html', 'handlebars']; - let embeddedLanguages = { css: true, javascript: true }; + const documentSelector = ['html', 'handlebars']; + const embeddedLanguages = { css: true, javascript: true }; let rangeFormatting: Disposable | undefined = undefined; // Options to control the language client - let clientOptions: LanguageClientOptions = { + const clientOptions: LanguageClientOptions = { documentSelector, synchronize: { configurationSection: ['html', 'css', 'javascript'], // the settings to synchronize @@ -135,68 +134,66 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua let client = newLanguageClient('html', localize('htmlserver.name', 'HTML Language Server'), clientOptions); client.registerProposedFeatures(); - let disposable = client.start(); - toDispose.push(disposable); - client.onReady().then(() => { + await client.start(); - toDispose.push(serveFileSystemRequests(client, runtime)); + toDispose.push(serveFileSystemRequests(client, runtime)); - const customDataSource = getCustomDataSource(runtime, context.subscriptions); + const customDataSource = getCustomDataSource(runtime, context.subscriptions); + client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); + customDataSource.onDidChange(() => { client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); - customDataSource.onDidChange(() => { - client.sendNotification(CustomDataChangedNotification.type, customDataSource.uris); - }); - client.onRequest(CustomDataContent.type, customDataSource.getContent); + }); + client.onRequest(CustomDataContent.type, customDataSource.getContent); - const insertRequestor = (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position): Promise<string> => { - let param: AutoInsertParams = { - kind, - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - position: client.code2ProtocolConverter.asPosition(position) - }; - return client.sendRequest(AutoInsertRequest.type, param); + const insertRequestor = (kind: 'autoQuote' | 'autoClose', document: TextDocument, position: Position): Promise<string> => { + const param: AutoInsertParams = { + kind, + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + position: client.code2ProtocolConverter.asPosition(position) }; - let disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime); - toDispose.push(disposable); - - disposable = client.onTelemetry(e => { - runtime.telemetry?.sendTelemetryEvent(e.key, e.data); - }); - toDispose.push(disposable); - - // manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652. - updateFormatterRegistration(); - toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); - toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(SettingIds.formatEnable) && updateFormatterRegistration())); - - client.sendRequest(SemanticTokenLegendRequest.type).then(legend => { - if (legend) { - const provider: DocumentSemanticTokensProvider & DocumentRangeSemanticTokensProvider = { - provideDocumentSemanticTokens(doc) { - const params: SemanticTokenParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc), - }; - return client.sendRequest(SemanticTokenRequest.type, params).then(data => { - return data && new SemanticTokens(new Uint32Array(data)); - }); - }, - provideDocumentRangeSemanticTokens(doc, range) { - const params: SemanticTokenParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc), - ranges: [client.code2ProtocolConverter.asRange(range)] - }; - return client.sendRequest(SemanticTokenRequest.type, params).then(data => { - return data && new SemanticTokens(new Uint32Array(data)); - }); - } - }; - toDispose.push(languages.registerDocumentSemanticTokensProvider(documentSelector, provider, new SemanticTokensLegend(legend.types, legend.modifiers))); - } - }); + return client.sendRequest(AutoInsertRequest.type, param); + }; + const disposable = activateAutoInsertion(insertRequestor, { html: true, handlebars: true }, runtime); + toDispose.push(disposable); + + const disposable2 = client.onTelemetry(e => { + runtime.telemetry?.sendTelemetryEvent(e.key, e.data); + }); + toDispose.push(disposable2); + + // manually register / deregister format provider based on the `html.format.enable` setting avoiding issues with late registration. See #71652. + updateFormatterRegistration(); + toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); + toDispose.push(workspace.onDidChangeConfiguration(e => e.affectsConfiguration(SettingIds.formatEnable) && updateFormatterRegistration())); + + client.sendRequest(SemanticTokenLegendRequest.type).then(legend => { + if (legend) { + const provider: DocumentSemanticTokensProvider & DocumentRangeSemanticTokensProvider = { + provideDocumentSemanticTokens(doc) { + const params: SemanticTokenParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc), + }; + return client.sendRequest(SemanticTokenRequest.type, params).then(data => { + return data && new SemanticTokens(new Uint32Array(data)); + }); + }, + provideDocumentRangeSemanticTokens(doc, range) { + const params: SemanticTokenParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(doc), + ranges: [client.code2ProtocolConverter.asRange(range)] + }; + return client.sendRequest(SemanticTokenRequest.type, params).then(data => { + return data && new SemanticTokens(new Uint32Array(data)); + }); + } + }; + toDispose.push(languages.registerDocumentSemanticTokensProvider(documentSelector, provider, new SemanticTokensLegend(legend.types, legend.modifiers))); + } }); + function updateFormatterRegistration() { const formatEnabled = workspace.getConfiguration().get(SettingIds.formatEnable); if (!formatEnabled && rangeFormatting) { @@ -219,7 +216,7 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( client.protocol2CodeConverter.asTextEdits, (error) => { - client.handleFailedRequest(DocumentRangeFormattingRequest.type, error, []); + client.handleFailedRequest(DocumentRangeFormattingRequest.type, undefined, error, []); return Promise.resolve([]); } ); @@ -300,4 +297,6 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua } } + return client; + } diff --git a/extensions/html-language-features/client/src/node/htmlClientMain.ts b/extensions/html-language-features/client/src/node/htmlClientMain.ts index 4c7d24e397c..f460d0c1524 100644 --- a/extensions/html-language-features/client/src/node/htmlClientMain.ts +++ b/extensions/html-language-features/client/src/node/htmlClientMain.ts @@ -6,16 +6,17 @@ import { getNodeFileFS } from './nodeFs'; import { Disposable, ExtensionContext } from 'vscode'; import { startClient, LanguageClientConstructor } from '../htmlClient'; -import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node'; +import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient, BaseLanguageClient } from 'vscode-languageclient/node'; import { TextDecoder } from 'util'; import * as fs from 'fs'; import TelemetryReporter from '@vscode/extension-telemetry'; let telemetry: TelemetryReporter | undefined; +let client: BaseLanguageClient | undefined; // this method is called when vs code is activated -export function activate(context: ExtensionContext) { +export async function activate(context: ExtensionContext) { let clientPackageJSON = getPackageInfo(context); telemetry = new TelemetryReporter(clientPackageJSON.name, clientPackageJSON.version, clientPackageJSON.aiKey); @@ -44,7 +45,14 @@ export function activate(context: ExtensionContext) { } }; - startClient(context, newLanguageClient, { fileFs: getNodeFileFS(), TextDecoder, telemetry, timer }); + client = await startClient(context, newLanguageClient, { fileFs: getNodeFileFS(), TextDecoder, telemetry, timer }); +} + +export async function deactivate(): Promise<void> { + if (client) { + await client.stop(); + client = undefined; + } } interface IPackageInfo { diff --git a/extensions/html-language-features/client/src/requests.ts b/extensions/html-language-features/client/src/requests.ts index ba124e28cd7..8106f044228 100644 --- a/extensions/html-language-features/client/src/requests.ts +++ b/extensions/html-language-features/client/src/requests.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Uri, workspace, Disposable } from 'vscode'; -import { RequestType, CommonLanguageClient } from 'vscode-languageclient'; +import { RequestType, BaseLanguageClient } from 'vscode-languageclient'; import { Runtime } from './htmlClient'; export namespace FsStatRequest { @@ -15,7 +15,7 @@ export namespace FsReadDirRequest { export const type: RequestType<string, [string, FileType][], any> = new RequestType('fs/readDir'); } -export function serveFileSystemRequests(client: CommonLanguageClient, runtime: Runtime): Disposable { +export function serveFileSystemRequests(client: BaseLanguageClient, runtime: Runtime): Disposable { const disposables = []; disposables.push(client.onRequest(FsReadDirRequest.type, (uriString: string) => { const uri = Uri.parse(uriString); diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index e7244d251c0..2f2dc4d1067 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -261,9 +261,9 @@ ] }, "dependencies": { - "@vscode/extension-telemetry": "0.4.10", - "vscode-languageclient": "^7.0.0", - "vscode-nls": "^5.0.0", + "@vscode/extension-telemetry": "0.5.1", + "vscode-languageclient": "^8.0.1", + "vscode-nls": "^5.0.1", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 423a395ba96..affcf98e566 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,11 +9,11 @@ }, "main": "./out/node/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^5.4.2", - "vscode-html-languageservice": "^4.2.5", - "vscode-languageserver": "^7.0.0", - "vscode-languageserver-textdocument": "^1.0.3", - "vscode-nls": "^5.0.0", + "vscode-css-languageservice": "^6.0.1", + "vscode-html-languageservice": "^5.0.0", + "vscode-languageserver": "^8.0.1", + "vscode-languageserver-textdocument": "^1.0.4", + "vscode-nls": "^5.0.1", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/html-language-features/server/src/htmlServer.ts b/extensions/html-language-features/server/src/htmlServer.ts index b3df5fc8e51..319399a038c 100644 --- a/extensions/html-language-features/server/src/htmlServer.ts +++ b/extensions/html-language-features/server/src/htmlServer.ts @@ -11,7 +11,7 @@ import { } from 'vscode-languageserver'; import { getLanguageModes, LanguageModes, Settings, TextDocument, Position, Diagnostic, WorkspaceFolder, ColorInformation, - Range, DocumentLink, SymbolInformation, TextDocumentIdentifier + Range, DocumentLink, SymbolInformation, TextDocumentIdentifier, isCompletionItemData } from './modes/languageModes'; import { format } from './modes/formatting'; @@ -129,7 +129,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // After the server has started the client sends an initialize request. The server receives // in the passed params the rootPath of the workspace plus the client capabilities connection.onInitialize((params: InitializeParams): InitializeResult => { - const initializationOptions = params.initializationOptions; + const initializationOptions = params.initializationOptions as any || {}; workspaceFolders = (<any>params).workspaceFolders; if (!Array.isArray(workspaceFolders)) { @@ -179,14 +179,14 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) scopedSettingsSupport = getClientCapability('workspace.configuration', false); workspaceFoldersSupport = getClientCapability('workspace.workspaceFolders', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); - formatterMaxNumberOfEdits = params.initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; + formatterMaxNumberOfEdits = initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; const capabilities: ServerCapabilities = { textDocumentSync: TextDocumentSyncKind.Incremental, completionProvider: clientSnippetSupport ? { resolveProvider: true, triggerCharacters: ['.', ':', '<', '"', '=', '/'] } : undefined, hoverProvider: true, documentHighlightProvider: true, - documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true, - documentFormattingProvider: params.initializationOptions?.provideFormatter === true, + documentRangeFormattingProvider: initializationOptions?.provideFormatter === true, + documentFormattingProvider: initializationOptions?.provideFormatter === true, documentLinkProvider: { resolveProvider: false }, documentSymbolProvider: true, definitionProvider: true, @@ -226,7 +226,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // The settings have changed. Is send on server activation as well. connection.onDidChangeConfiguration((change) => { - globalSettings = change.settings; + globalSettings = change.settings as Settings; documentSettings = {}; // reset all document settings documents.all().forEach(triggerValidation); @@ -331,7 +331,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) connection.onCompletionResolve((item, token) => { return runSafe(runtime, async () => { const data = item.data; - if (data && data.languageId && data.uri) { + if (isCompletionItemData(data)) { const mode = languageModes.getMode(data.languageId); const document = documents.get(data.uri); if (mode && mode.doResolve && document) { diff --git a/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts index 9757d99cd88..6bc02acb510 100644 --- a/extensions/html-language-features/server/src/modes/cssMode.ts +++ b/extensions/html-language-features/server/src/modes/cssMode.ts @@ -5,7 +5,7 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { Stylesheet, LanguageService as CSSLanguageService } from 'vscode-css-languageservice'; -import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext } from './languageModes'; +import { LanguageMode, Workspace, Color, TextDocument, Position, Range, CompletionList, DocumentContext, Diagnostic } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache<HTMLDocumentRegions>, workspace: Workspace): LanguageMode { @@ -18,7 +18,7 @@ export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegio }, async doValidation(document: TextDocument, settings = workspace.settings) { let embedded = embeddedCSSDocuments.get(document); - return cssLanguageService.doValidation(embedded, cssStylesheets.get(embedded), settings && settings.css); + return (cssLanguageService.doValidation(embedded, cssStylesheets.get(embedded), settings && settings.css) as Diagnostic[]); }, async doComplete(document: TextDocument, position: Position, documentContext: DocumentContext, _settings = workspace.settings) { let embedded = embeddedCSSDocuments.get(document); diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index bbcba5e0f86..7f9e3f1d85a 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -8,7 +8,7 @@ import { SymbolInformation, SymbolKind, CompletionItem, Location, SignatureHelp, SignatureInformation, ParameterInformation, Definition, TextEdit, TextDocument, Diagnostic, DiagnosticSeverity, Range, CompletionItemKind, Hover, DocumentHighlight, DocumentHighlightKind, CompletionList, Position, FormattingOptions, FoldingRange, FoldingRangeKind, SelectionRange, - LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext + LanguageMode, Settings, SemanticTokenData, Workspace, DocumentContext, CompletionItemData, isCompletionItemData } from './languageModes'; import { getWordAtText, isWhitespaceOnly, repeat } from '../utils/strings'; import { HTMLDocumentRegions } from './embeddedSupport'; @@ -122,6 +122,11 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume return { isIncomplete: false, items: completions.entries.map(entry => { + const data: CompletionItemData = { // data used for resolving item details (see 'doResolve') + languageId, + uri: document.uri, + offset: offset + }; return { uri: document.uri, position: position, @@ -129,23 +134,21 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache<HTMLDocume sortText: entry.sortText, kind: convertKind(entry.kind), textEdit: TextEdit.replace(replaceRange, entry.name), - data: { // data used for resolving item details (see 'doResolve') - languageId, - uri: document.uri, - offset: offset - } + data }; }) }; }, async doResolve(document: TextDocument, item: CompletionItem): Promise<CompletionItem> { - const jsDocument = jsDocuments.get(document); - const jsLanguageService = await host.getLanguageService(jsDocument); - let details = jsLanguageService.getCompletionEntryDetails(jsDocument.uri, item.data.offset, item.label, undefined, undefined, undefined, undefined); - if (details) { - item.detail = ts.displayPartsToString(details.displayParts); - item.documentation = ts.displayPartsToString(details.documentation); - delete item.data; + if (isCompletionItemData(item.data)) { + const jsDocument = jsDocuments.get(document); + const jsLanguageService = await host.getLanguageService(jsDocument); + let details = jsLanguageService.getCompletionEntryDetails(jsDocument.uri, item.data.offset, item.label, undefined, undefined, undefined, undefined); + if (details) { + item.detail = ts.displayPartsToString(details.displayParts); + item.documentation = ts.displayPartsToString(details.documentation); + delete item.data; + } } return item; }, diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index 3a8b9b797cc..59cc742b2b8 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -54,6 +54,16 @@ export interface SemanticTokenData { modifierSet: number; } +export type CompletionItemData = { + languageId: string; + uri: string; + offset: number; +}; + +export function isCompletionItemData(value: any): value is CompletionItemData { + return value && typeof value.languageId === 'string' && typeof value.uri === 'string' && typeof value.offset === 'number'; +} + export interface LanguageMode { getId(): string; getSelectionRange?: (document: TextDocument, position: Position) => Promise<SelectionRange>; diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index a5bfebda600..f086cbf6898 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -12,65 +12,60 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -vscode-css-languageservice@^5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-5.4.2.tgz#69ea74c000bd653dfc8e458a1720d28b9ffa5cfb" - integrity sha512-DT7+7vfdT2HDNjDoXWtYJ0lVDdeDEdbMNdK4PKqUl2MS8g7PWt7J5G9B6k9lYox8nOfhCEjLnoNC3UKHHCR1lg== +vscode-css-languageservice@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.0.1.tgz#ccf94944e094dcc5833d1b4ac276994b698e9283" + integrity sha512-81n/eeYuJwQdvpoy6IK1258PtPbO720fl13FcJ5YQECPyHMFkmld1qKHwPJkyLbLPfboqJPM53ys4xW8v+iBVw== dependencies: vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.16.0" - vscode-nls "^5.0.0" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-html-languageservice@^4.2.5: - version "4.2.5" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-4.2.5.tgz#c0cc8ff3d824d16388bbac187e1828749eccf006" - integrity sha512-dbr10KHabB9EaK8lI0XZW7SqOsTfrNyT3Nuj0GoPi4LjGKUmMiLtsqzfedIzRTzqY+w0FiLdh0/kQrnQ0tLxrw== +vscode-html-languageservice@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-5.0.0.tgz#c68613f836d7fcff125183d78e6f1f0ff326fa55" + integrity sha512-KJG13z54aLszskp3ETf8b1EKDypr2Sf5RUsfR6OXmKqEl2ZUfyIxsWz4gbJWjPzoJZx/bGH0ZXVwxJ1rg8OKRQ== dependencies: vscode-languageserver-textdocument "^1.0.4" - vscode-languageserver-types "^3.16.0" - vscode-nls "^5.0.0" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-textdocument@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.3.tgz#879f2649bfa5a6e07bc8b392c23ede2dfbf43eff" - integrity sha512-ynEGytvgTb6HVSUwPJIAZgiHQmPCx8bZ8w5um5Lz+q5DjP0Zj8wTFhQpyg8xaMvefDytw2+HH5yzqS+FhsR28A== + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-languageserver-types@3.16.0, vscode-languageserver-types@^3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== +vscode-languageserver-types@3.17.1, vscode-languageserver-types@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== +vscode-languageserver@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.1.tgz#56bd7a01f5c88af075a77f1d220edcb30fc4bdc7" + integrity sha512-sn7SjBwWm3OlmLtgg7jbM0wBULppyL60rj8K5HF0ny/MzN+GzPBX1kCvYdybhl7UW63V5V5tRVnyB8iwC73lSQ== dependencies: - vscode-languageserver-protocol "3.16.0" + vscode-languageserver-protocol "3.17.1" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index d77421b701c..5157b15d877 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@vscode/extension-telemetry@0.4.10": - version "0.4.10" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.4.10.tgz#be960c05bdcbea0933866346cf244acad6cac910" - integrity sha512-XgyUoWWRQExTmd9DynIIUQo1NPex/zIeetdUAXeBjVuW9ioojM1TcDaSqOa/5QLC7lx+oEXwSU1r0XSBgzyz6w== +"@vscode/extension-telemetry@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.5.1.tgz#20150976629663b3d33799a4ad25944a1535f7db" + integrity sha512-cvFq8drxdLRF8KN72WcV4lTEa9GqDiRwy9EbnYuoSCD9Jdk8zHFF49MmACC1qs4R9Ko/C1uMOmeLJmVi8EA0rQ== balanced-match@^1.0.0: version "1.0.0" @@ -44,44 +44,44 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageclient@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz#b505c22c21ffcf96e167799757fca07a6bad0fb2" - integrity sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg== +vscode-languageclient@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" + integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== dependencies: minimatch "^3.0.4" - semver "^7.3.4" - vscode-languageserver-protocol "3.16.0" + semver "^7.3.5" + vscode-languageserver-protocol "3.17.1" -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== - -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" + +vscode-languageserver-types@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== + +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/ipynb/package.json b/extensions/ipynb/package.json index 32802630b84..901f65e56e1 100644 --- a/extensions/ipynb/package.json +++ b/extensions/ipynb/package.json @@ -9,7 +9,8 @@ "vscode": "^1.57.0" }, "enabledApiProposals": [ - "notebookEditor" + "notebookEditor", + "notebookWorkspaceEdit" ], "activationEvents": [ "*" diff --git a/extensions/json-language-features/client/src/browser/jsonClientMain.ts b/extensions/json-language-features/client/src/browser/jsonClientMain.ts index 9eb390b545c..e1fae6ffeb4 100644 --- a/extensions/json-language-features/client/src/browser/jsonClientMain.ts +++ b/extensions/json-language-features/client/src/browser/jsonClientMain.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ExtensionContext, Uri } from 'vscode'; -import { LanguageClientOptions } from 'vscode-languageclient'; +import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient'; import { startClient, LanguageClientConstructor, SchemaRequestService } from '../jsonClient'; import { LanguageClient } from 'vscode-languageclient/browser'; @@ -14,8 +14,10 @@ declare const Worker: { declare function fetch(uri: string, options: any): any; +let client: BaseLanguageClient | undefined; + // this method is called when vs code is activated -export function activate(context: ExtensionContext) { +export async function activate(context: ExtensionContext) { const serverMain = Uri.joinPath(context.extensionUri, 'server/dist/browser/jsonServerMain.js'); try { const worker = new Worker(serverMain.toString()); @@ -32,9 +34,16 @@ export function activate(context: ExtensionContext) { } }; - startClient(context, newLanguageClient, { schemaRequests }); + client = await startClient(context, newLanguageClient, { schemaRequests }); } catch (e) { console.log(e); } } + +export async function deactivate(): Promise<void> { + if (client) { + await client.stop(); + client = undefined; + } +} diff --git a/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts index 5246257adc8..60225af8cef 100644 --- a/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -16,9 +16,10 @@ import { import { LanguageClientOptions, RequestType, NotificationType, DidChangeConfigurationNotification, HandleDiagnosticsSignature, ResponseError, DocumentRangeFormattingParams, - DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, ProvideHoverSignature, CommonLanguageClient + DocumentRangeFormattingRequest, ProvideCompletionItemsSignature, ProvideHoverSignature, BaseLanguageClient } from 'vscode-languageclient'; + import { hash } from './utils/hash'; import { createLanguageStatusItem } from './languageStatus'; @@ -56,7 +57,7 @@ namespace ResultLimitReachedNotification { export const type: NotificationType<string> = new NotificationType('json/resultLimitReached'); } -interface Settings { +type Settings = { json?: { schemas?: JSONSchemaSettings[]; format?: { enable?: boolean }; @@ -67,13 +68,13 @@ interface Settings { proxy?: string; proxyStrictSSL?: boolean; }; -} +}; -export interface JSONSchemaSettings { +export type JSONSchemaSettings = { fileMatch?: string[]; url?: string; schema?: any; -} +}; namespace SettingIds { export const enableFormatter = 'json.format.enable'; @@ -94,7 +95,7 @@ export interface TelemetryReporter { }): void; } -export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => CommonLanguageClient; +export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; export interface Runtime { schemaRequests: SchemaRequestService; @@ -108,7 +109,7 @@ export interface SchemaRequestService { export const languageServerDescription = localize('jsonserver.name', 'JSON Language Server'); -export function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime) { +export async function startClient(context: ExtensionContext, newLanguageClient: LanguageClientConstructor, runtime: Runtime): Promise<BaseLanguageClient> { const toDispose = context.subscriptions; @@ -218,178 +219,177 @@ export function startClient(context: ExtensionContext, newLanguageClient: Langua const client = newLanguageClient('json', languageServerDescription, clientOptions); client.registerProposedFeatures(); - const disposable = client.start(); - toDispose.push(disposable); - client.onReady().then(() => { - isClientReady = true; - - const schemaDocuments: { [uri: string]: boolean } = {}; + const schemaDocuments: { [uri: string]: boolean } = {}; - // handle content request - client.onRequest(VSCodeContentRequest.type, (uriPath: string) => { - const uri = Uri.parse(uriPath); - if (uri.scheme === 'untitled') { - return Promise.reject(new ResponseError(3, localize('untitled.schema', 'Unable to load {0}', uri.toString()))); - } - if (uri.scheme !== 'http' && uri.scheme !== 'https') { - return workspace.openTextDocument(uri).then(doc => { - schemaDocuments[uri.toString()] = true; - return doc.getText(); - }, error => { - return Promise.reject(new ResponseError(2, error.toString())); - }); - } else if (schemaDownloadEnabled) { - if (runtime.telemetry && uri.authority === 'schema.management.azure.com') { - /* __GDPR__ - "json.schema" : { - "owner": "aeschli", - "comment": "Measure the use of the Azure resource manager schemas", - "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The azure schema URL that was requested." } - } - */ - runtime.telemetry.sendTelemetryEvent('json.schema', { schemaURL: uriPath }); - } - return runtime.schemaRequests.getContent(uriPath).catch(e => { - return Promise.reject(new ResponseError(4, e.toString())); - }); - } else { - return Promise.reject(new ResponseError(1, localize('schemaDownloadDisabled', 'Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload))); + // handle content request + client.onRequest(VSCodeContentRequest.type, (uriPath: string) => { + const uri = Uri.parse(uriPath); + if (uri.scheme === 'untitled') { + return Promise.reject(new ResponseError(3, localize('untitled.schema', 'Unable to load {0}', uri.toString()))); + } + if (uri.scheme !== 'http' && uri.scheme !== 'https') { + return workspace.openTextDocument(uri).then(doc => { + schemaDocuments[uri.toString()] = true; + return doc.getText(); + }, error => { + return Promise.reject(new ResponseError(2, error.toString())); + }); + } else if (schemaDownloadEnabled) { + if (runtime.telemetry && uri.authority === 'schema.management.azure.com') { + /* __GDPR__ + "json.schema" : { + "owner": "aeschli", + "comment": "Measure the use of the Azure resource manager schemas", + "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "comment": "The azure schema URL that was requested." } + } + */ + runtime.telemetry.sendTelemetryEvent('json.schema', { schemaURL: uriPath }); } - }); + return runtime.schemaRequests.getContent(uriPath).catch(e => { + return Promise.reject(new ResponseError(4, e.toString())); + }); + } else { + return Promise.reject(new ResponseError(1, localize('schemaDownloadDisabled', 'Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload))); + } + }); - const handleContentChange = (uriString: string) => { - if (schemaDocuments[uriString]) { - client.sendNotification(SchemaContentChangeNotification.type, uriString); - return true; - } - return false; - }; - const handleActiveEditorChange = (activeEditor?: TextEditor) => { - if (!activeEditor) { - return; - } + await client.start(); - const activeDocUri = activeEditor.document.uri.toString(); + isClientReady = true; - if (activeDocUri && fileSchemaErrors.has(activeDocUri)) { - schemaResolutionErrorStatusBarItem.show(); - } else { - schemaResolutionErrorStatusBarItem.hide(); - } - }; + const handleContentChange = (uriString: string) => { + if (schemaDocuments[uriString]) { + client.sendNotification(SchemaContentChangeNotification.type, uriString); + return true; + } + return false; + }; + const handleActiveEditorChange = (activeEditor?: TextEditor) => { + if (!activeEditor) { + return; + } - toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri.toString()))); - toDispose.push(workspace.onDidCloseTextDocument(d => { - const uriString = d.uri.toString(); - if (handleContentChange(uriString)) { - delete schemaDocuments[uriString]; - } - fileSchemaErrors.delete(uriString); - })); - toDispose.push(window.onDidChangeActiveTextEditor(handleActiveEditorChange)); - - const handleRetryResolveSchemaCommand = () => { - if (window.activeTextEditor) { - schemaResolutionErrorStatusBarItem.text = '$(watch)'; - const activeDocUri = window.activeTextEditor.document.uri.toString(); - client.sendRequest(ForceValidateRequest.type, activeDocUri).then((diagnostics) => { - const schemaErrorIndex = diagnostics.findIndex(isSchemaResolveError); - if (schemaErrorIndex !== -1) { - // Show schema resolution errors in status bar only; ref: #51032 - const schemaResolveDiagnostic = diagnostics[schemaErrorIndex]; - fileSchemaErrors.set(activeDocUri, schemaResolveDiagnostic.message); - } else { - schemaResolutionErrorStatusBarItem.hide(); - } - schemaResolutionErrorStatusBarItem.text = '$(alert)'; - }); - } - }; + const activeDocUri = activeEditor.document.uri.toString(); + + if (activeDocUri && fileSchemaErrors.has(activeDocUri)) { + schemaResolutionErrorStatusBarItem.show(); + } else { + schemaResolutionErrorStatusBarItem.hide(); + } + }; - toDispose.push(commands.registerCommand('_json.retryResolveSchema', handleRetryResolveSchemaCommand)); + toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri.toString()))); + toDispose.push(workspace.onDidCloseTextDocument(d => { + const uriString = d.uri.toString(); + if (handleContentChange(uriString)) { + delete schemaDocuments[uriString]; + } + fileSchemaErrors.delete(uriString); + })); + toDispose.push(window.onDidChangeActiveTextEditor(handleActiveEditorChange)); + const handleRetryResolveSchemaCommand = () => { + if (window.activeTextEditor) { + schemaResolutionErrorStatusBarItem.text = '$(watch)'; + const activeDocUri = window.activeTextEditor.document.uri.toString(); + client.sendRequest(ForceValidateRequest.type, activeDocUri).then((diagnostics) => { + const schemaErrorIndex = diagnostics.findIndex(isSchemaResolveError); + if (schemaErrorIndex !== -1) { + // Show schema resolution errors in status bar only; ref: #51032 + const schemaResolveDiagnostic = diagnostics[schemaErrorIndex]; + fileSchemaErrors.set(activeDocUri, schemaResolveDiagnostic.message); + } else { + schemaResolutionErrorStatusBarItem.hide(); + } + schemaResolutionErrorStatusBarItem.text = '$(alert)'; + }); + } + }; + + toDispose.push(commands.registerCommand('_json.retryResolveSchema', handleRetryResolveSchemaCommand)); + + client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations(context)); + + toDispose.push(extensions.onDidChange(_ => { client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations(context)); + })); - toDispose.push(extensions.onDidChange(_ => { - client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociations(context)); - })); + // manually register / deregister format provider based on the `json.format.enable` setting avoiding issues with late registration. See #71652. + updateFormatterRegistration(); + toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); - // manually register / deregister format provider based on the `json.format.enable` setting avoiding issues with late registration. See #71652. - updateFormatterRegistration(); - toDispose.push({ dispose: () => rangeFormatting && rangeFormatting.dispose() }); + updateSchemaDownloadSetting(); - updateSchemaDownloadSetting(); + toDispose.push(workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(SettingIds.enableFormatter)) { + updateFormatterRegistration(); + } else if (e.affectsConfiguration(SettingIds.enableSchemaDownload)) { + updateSchemaDownloadSetting(); + } + })); - toDispose.push(workspace.onDidChangeConfiguration(e => { - if (e.affectsConfiguration(SettingIds.enableFormatter)) { - updateFormatterRegistration(); - } else if (e.affectsConfiguration(SettingIds.enableSchemaDownload)) { - updateSchemaDownloadSetting(); + client.onNotification(ResultLimitReachedNotification.type, async message => { + const shouldPrompt = context.globalState.get<boolean>(StorageIds.maxItemsExceededInformation) !== false; + if (shouldPrompt) { + const ok = localize('ok', "OK"); + const openSettings = localize('goToSetting', 'Open Settings'); + const neverAgain = localize('yes never again', "Don't Show Again"); + const pick = await window.showInformationMessage(`${message}\n${localize('configureLimit', 'Use setting \'{0}\' to configure the limit.', SettingIds.maxItemsComputed)}`, ok, openSettings, neverAgain); + if (pick === neverAgain) { + await context.globalState.update(StorageIds.maxItemsExceededInformation, false); + } else if (pick === openSettings) { + await commands.executeCommand('workbench.action.openSettings', SettingIds.maxItemsComputed); } - })); - - client.onNotification(ResultLimitReachedNotification.type, async message => { - const shouldPrompt = context.globalState.get<boolean>(StorageIds.maxItemsExceededInformation) !== false; - if (shouldPrompt) { - const ok = localize('ok', "OK"); - const openSettings = localize('goToSetting', 'Open Settings'); - const neverAgain = localize('yes never again', "Don't Show Again"); - const pick = await window.showInformationMessage(`${message}\n${localize('configureLimit', 'Use setting \'{0}\' to configure the limit.', SettingIds.maxItemsComputed)}`, ok, openSettings, neverAgain); - if (pick === neverAgain) { - await context.globalState.update(StorageIds.maxItemsExceededInformation, false); - } else if (pick === openSettings) { - await commands.executeCommand('workbench.action.openSettings', SettingIds.maxItemsComputed); + } + }); + + toDispose.push(createLanguageStatusItem(documentSelector, (uri: string) => client.sendRequest(LanguageStatusRequest.type, uri))); + + function updateFormatterRegistration() { + const formatEnabled = workspace.getConfiguration().get(SettingIds.enableFormatter); + if (!formatEnabled && rangeFormatting) { + rangeFormatting.dispose(); + rangeFormatting = undefined; + } else if (formatEnabled && !rangeFormatting) { + rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, { + provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> { + const filesConfig = workspace.getConfiguration('files', document); + const fileFormattingOptions = { + trimTrailingWhitespace: filesConfig.get<boolean>('trimTrailingWhitespace'), + trimFinalNewlines: filesConfig.get<boolean>('trimFinalNewlines'), + insertFinalNewline: filesConfig.get<boolean>('insertFinalNewline'), + }; + const params: DocumentRangeFormattingParams = { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), + range: client.code2ProtocolConverter.asRange(range), + options: client.code2ProtocolConverter.asFormattingOptions(options, fileFormattingOptions) + }; + + return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( + client.protocol2CodeConverter.asTextEdits, + (error) => { + client.handleFailedRequest(DocumentRangeFormattingRequest.type, undefined, error, []); + return Promise.resolve([]); + } + ); } - } - }); - - toDispose.push(createLanguageStatusItem(documentSelector, (uri: string) => client.sendRequest(LanguageStatusRequest.type, uri))); - - function updateFormatterRegistration() { - const formatEnabled = workspace.getConfiguration().get(SettingIds.enableFormatter); - if (!formatEnabled && rangeFormatting) { - rangeFormatting.dispose(); - rangeFormatting = undefined; - } else if (formatEnabled && !rangeFormatting) { - rangeFormatting = languages.registerDocumentRangeFormattingEditProvider(documentSelector, { - provideDocumentRangeFormattingEdits(document: TextDocument, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult<TextEdit[]> { - const filesConfig = workspace.getConfiguration('files', document); - const fileFormattingOptions = { - trimTrailingWhitespace: filesConfig.get<boolean>('trimTrailingWhitespace'), - trimFinalNewlines: filesConfig.get<boolean>('trimFinalNewlines'), - insertFinalNewline: filesConfig.get<boolean>('insertFinalNewline'), - }; - const params: DocumentRangeFormattingParams = { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), - range: client.code2ProtocolConverter.asRange(range), - options: client.code2ProtocolConverter.asFormattingOptions(options, fileFormattingOptions) - }; - - return client.sendRequest(DocumentRangeFormattingRequest.type, params, token).then( - client.protocol2CodeConverter.asTextEdits, - (error) => { - client.handleFailedRequest(DocumentRangeFormattingRequest.type, error, []); - return Promise.resolve([]); - } - ); - } - }); - } + }); } + } - function updateSchemaDownloadSetting() { - schemaDownloadEnabled = workspace.getConfiguration().get(SettingIds.enableSchemaDownload) !== false; - if (schemaDownloadEnabled) { - schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionErrorMessage', 'Unable to resolve schema. Click to retry.'); - schemaResolutionErrorStatusBarItem.command = '_json.retryResolveSchema'; - handleRetryResolveSchemaCommand(); - } else { - schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionDisabledMessage', 'Downloading schemas is disabled. Click to configure.'); - schemaResolutionErrorStatusBarItem.command = { command: 'workbench.action.openSettings', arguments: [SettingIds.enableSchemaDownload], title: '' }; - } + function updateSchemaDownloadSetting() { + schemaDownloadEnabled = workspace.getConfiguration().get(SettingIds.enableSchemaDownload) !== false; + if (schemaDownloadEnabled) { + schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionErrorMessage', 'Unable to resolve schema. Click to retry.'); + schemaResolutionErrorStatusBarItem.command = '_json.retryResolveSchema'; + handleRetryResolveSchemaCommand(); + } else { + schemaResolutionErrorStatusBarItem.tooltip = localize('json.schemaResolutionDisabledMessage', 'Downloading schemas is disabled. Click to configure.'); + schemaResolutionErrorStatusBarItem.command = { command: 'workbench.action.openSettings', arguments: [SettingIds.enableSchemaDownload], title: '' }; } + } - }); + return client; } function getSchemaAssociations(_context: ExtensionContext): ISchemaAssociation[] { diff --git a/extensions/json-language-features/client/src/node/jsonClientMain.ts b/extensions/json-language-features/client/src/node/jsonClientMain.ts index 9809074a5a9..752abe59a9f 100644 --- a/extensions/json-language-features/client/src/node/jsonClientMain.ts +++ b/extensions/json-language-features/client/src/node/jsonClientMain.ts @@ -5,7 +5,7 @@ import { ExtensionContext, OutputChannel, window, workspace } from 'vscode'; import { startClient, LanguageClientConstructor, SchemaRequestService, languageServerDescription } from '../jsonClient'; -import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient } from 'vscode-languageclient/node'; +import { ServerOptions, TransportKind, LanguageClientOptions, LanguageClient, BaseLanguageClient } from 'vscode-languageclient/node'; import { promises as fs } from 'fs'; import * as path from 'path'; @@ -15,6 +15,7 @@ import TelemetryReporter from '@vscode/extension-telemetry'; import { JSONSchemaCache } from './schemaCache'; let telemetry: TelemetryReporter | undefined; +let client: BaseLanguageClient | undefined; // this method is called when vs code is activated export async function activate(context: ExtensionContext) { @@ -45,11 +46,15 @@ export async function activate(context: ExtensionContext) { const schemaRequests = await getSchemaRequestService(context, log); - startClient(context, newLanguageClient, { schemaRequests, telemetry }); + client = await startClient(context, newLanguageClient, { schemaRequests, telemetry }); } -export function deactivate(): Promise<any> { - return telemetry ? telemetry.dispose() : Promise.resolve(null); +export async function deactivate(): Promise<any> { + if (client) { + await client.stop(); + client = undefined; + } + telemetry?.dispose(); } interface IPackageInfo { diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 4941fced265..1fc6753efbb 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -149,8 +149,8 @@ "dependencies": { "@vscode/extension-telemetry": "0.5.1", "request-light": "^0.5.8", - "vscode-languageclient": "^7.0.0", - "vscode-nls": "^5.0.0" + "vscode-languageclient": "^8.0.1", + "vscode-nls": "^5.0.1" }, "devDependencies": { "@types/node": "16.x" diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index cd04f24c3ab..a60bc177dc1 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,8 +14,8 @@ "dependencies": { "jsonc-parser": "^3.0.0", "request-light": "^0.5.8", - "vscode-json-languageservice": "^4.2.1", - "vscode-languageserver": "^7.0.0", + "vscode-json-languageservice": "^5.0.0", + "vscode-languageserver": "^8.0.1", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/json-language-features/server/src/jsonServer.ts b/extensions/json-language-features/server/src/jsonServer.ts index e105859371f..b818bcefbf2 100644 --- a/extensions/json-language-features/server/src/jsonServer.ts +++ b/extensions/json-language-features/server/src/jsonServer.ts @@ -6,11 +6,11 @@ import { Connection, TextDocuments, InitializeParams, InitializeResult, NotificationType, RequestType, - DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentSyncKind, TextEdit, DocumentFormattingRequest, TextDocumentIdentifier, FormattingOptions + DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentSyncKind, TextEdit, DocumentFormattingRequest, TextDocumentIdentifier, FormattingOptions, Diagnostic } from 'vscode-languageserver'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; -import { TextDocument, JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, Diagnostic, Range, Position } from 'vscode-json-languageservice'; +import { TextDocument, JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, Range, Position } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { Utils, URI } from 'vscode-uri'; @@ -117,7 +117,9 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) // in the passed params the rootPath of the workspace plus the client capabilities. connection.onInitialize((params: InitializeParams): InitializeResult => { - const handledProtocols = params.initializationOptions?.handledSchemaProtocols; + const initializationOptions = params.initializationOptions as any || {}; + + const handledProtocols = initializationOptions?.handledSchemaProtocols; languageService = getLanguageService({ schemaRequestService: getSchemaRequestService(handledProtocols), @@ -138,11 +140,13 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) return c; } + + clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false); - dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (typeof params.initializationOptions?.provideFormatter !== 'boolean'); + dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (typeof initializationOptions.provideFormatter !== 'boolean'); foldingRangeLimitDefault = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false); - formatterMaxNumberOfEdits = params.initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; + formatterMaxNumberOfEdits = initializationOptions.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE; const capabilities: ServerCapabilities = { textDocumentSync: TextDocumentSyncKind.Incremental, completionProvider: clientSnippetSupport ? { @@ -151,8 +155,8 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) } : undefined, hoverProvider: true, documentSymbolProvider: true, - documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true, - documentFormattingProvider: params.initializationOptions?.provideFormatter === true, + documentRangeFormattingProvider: initializationOptions.provideFormatter === true, + documentFormattingProvider: initializationOptions.provideFormatter === true, colorProvider: {}, foldingRangeProvider: true, selectionRangeProvider: true, @@ -403,7 +407,7 @@ export function startServer(connection: Connection, runtime: RuntimeEnvironment) runtime.timer.setImmediate(() => { const currDocument = documents.get(textDocument.uri); if (currDocument && currDocument.version === version) { - respond(diagnostics); // Send the computed diagnostics to VSCode. + respond(diagnostics as Diagnostic[]); // Send the computed diagnostics to VSCode. } }); }, error => { diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 5cd1cf5f480..2e74a77e9d3 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -22,51 +22,51 @@ request-light@^0.5.8: resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.8.tgz#8bf73a07242b9e7b601fac2fa5dc22a094abcc27" integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg== -vscode-json-languageservice@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-4.2.1.tgz#94b6f471ece193bf4a1ef37f6ab5cce86d50a8b4" - integrity sha512-xGmv9QIWs2H8obGbWg+sIPI/3/pFgj/5OWBhNzs00BkYQ9UaB2F6JJaGB/2/YOZJ3BvLXQTC4Q7muqU25QgAhA== +vscode-json-languageservice@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.0.0.tgz#465d76cfe5dfeed4c3d5a2123b50e3f115bb7f78" + integrity sha512-1/+1TJBRFrfCNizmrW0fbIvguKzzO+4ehlqWCCnF7ioSACUGHrYop4ANb+eRnFaCP6fi3+i+llJC5Y5yAvmL6w== dependencies: jsonc-parser "^3.0.0" - vscode-languageserver-textdocument "^1.0.3" - vscode-languageserver-types "^3.16.0" - vscode-nls "^5.0.0" + vscode-languageserver-textdocument "^1.0.4" + vscode-languageserver-types "^3.17.1" + vscode-nls "^5.0.1" vscode-uri "^3.0.3" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" -vscode-languageserver-textdocument@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.3.tgz#879f2649bfa5a6e07bc8b392c23ede2dfbf43eff" - integrity sha512-ynEGytvgTb6HVSUwPJIAZgiHQmPCx8bZ8w5um5Lz+q5DjP0Zj8wTFhQpyg8xaMvefDytw2+HH5yzqS+FhsR28A== +vscode-languageserver-textdocument@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" + integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== -vscode-languageserver-types@3.16.0, vscode-languageserver-types@^3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== +vscode-languageserver-types@3.17.1, vscode-languageserver-types@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== -vscode-languageserver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz#49b068c87cfcca93a356969d20f5d9bdd501c6b0" - integrity sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw== +vscode-languageserver@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.1.tgz#56bd7a01f5c88af075a77f1d220edcb30fc4bdc7" + integrity sha512-sn7SjBwWm3OlmLtgg7jbM0wBULppyL60rj8K5HF0ny/MzN+GzPBX1kCvYdybhl7UW63V5V5tRVnyB8iwC73lSQ== dependencies: - vscode-languageserver-protocol "3.16.0" + vscode-languageserver-protocol "3.17.1" -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== vscode-uri@^3.0.3: version "3.0.3" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index 7e56398f062..3b6ad62624a 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -49,44 +49,44 @@ request-light@^0.5.8: resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.5.8.tgz#8bf73a07242b9e7b601fac2fa5dc22a094abcc27" integrity sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg== -semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -vscode-jsonrpc@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz#108bdb09b4400705176b957ceca9e0880e9b6d4e" - integrity sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== -vscode-languageclient@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz#b505c22c21ffcf96e167799757fca07a6bad0fb2" - integrity sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg== +vscode-languageclient@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" + integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== dependencies: minimatch "^3.0.4" - semver "^7.3.4" - vscode-languageserver-protocol "3.16.0" + semver "^7.3.5" + vscode-languageserver-protocol "3.17.1" -vscode-languageserver-protocol@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz#34135b61a9091db972188a07d337406a3cdbe821" - integrity sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A== +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== dependencies: - vscode-jsonrpc "6.0.0" - vscode-languageserver-types "3.16.0" - -vscode-languageserver-types@3.16.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz#ecf393fc121ec6974b2da3efb3155644c514e247" - integrity sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA== - -vscode-nls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" - integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" + +vscode-languageserver-types@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== + +vscode-nls@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.1.tgz#ba23fc4d4420d25e7f886c8e83cbdcec47aa48b2" + integrity sha512-hHQV6iig+M21lTdItKPkJAaWrxALQb/nqpVffakO4knJOh3DrU2SXOMzUzNgo1eADPzu3qSsJY1weCzvR52q9A== yallist@^4.0.0: version "4.0.0" diff --git a/extensions/markdown-language-features/notebook/index.ts b/extensions/markdown-language-features/notebook/index.ts index 3fdb86bd8d7..079ed928f3f 100644 --- a/extensions/markdown-language-features/notebook/index.ts +++ b/extensions/markdown-language-features/notebook/index.ts @@ -207,7 +207,9 @@ export const activate: ActivationFunction<void> = (ctx) => { previewNode.classList.remove('emptyMarkdownCell'); const markdownText = outputInfo.mime.startsWith('text/x-') ? `\`\`\`${outputInfo.mime.substr(7)}\n${text}\n\`\`\`` : (outputInfo.mime.startsWith('application/') ? `\`\`\`${outputInfo.mime.substr(12)}\n${text}\n\`\`\`` : text); - const unsanitizedRenderedMarkdown = markdownIt.render(markdownText); + const unsanitizedRenderedMarkdown = markdownIt.render(markdownText, { + outputItem: outputInfo, + }); previewNode.innerHTML = (ctx.workspace.isTrusted ? unsanitizedRenderedMarkdown : DOMPurify.sanitize(unsanitizedRenderedMarkdown, sanitizerOptions)) as string; diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 1af496d0fce..b1d4d1bc529 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -420,10 +420,10 @@ "description": "%configuration.markdown.experimental.validate.enabled.description%", "default": false }, - "markdown.experimental.validate.referenceLinks": { + "markdown.experimental.validate.referenceLinks.enabled": { "type": "string", "scope": "resource", - "markdownDescription": "%configuration.markdown.experimental.validate.referenceLinks.description%", + "markdownDescription": "%configuration.markdown.experimental.validate.referenceLinks.enabled.description%", "default": "warning", "enum": [ "ignore", @@ -431,10 +431,10 @@ "error" ] }, - "markdown.experimental.validate.headerLinks": { + "markdown.experimental.validate.headerLinks.enabled": { "type": "string", "scope": "resource", - "markdownDescription": "%configuration.markdown.experimental.validate.headerLinks.description%", + "markdownDescription": "%configuration.markdown.experimental.validate.headerLinks.enabled.description%", "default": "warning", "enum": [ "ignore", @@ -442,16 +442,24 @@ "error" ] }, - "markdown.experimental.validate.fileLinks": { + "markdown.experimental.validate.fileLinks.enabled": { "type": "string", "scope": "resource", - "markdownDescription": "%configuration.markdown.experimental.validate.fileLinks.description%", + "markdownDescription": "%configuration.markdown.experimental.validate.fileLinks.enabled.description%", "default": "warning", "enum": [ "ignore", "warning", "error" ] + }, + "markdown.experimental.validate.fileLinks.skipPaths": { + "type": "array", + "scope": "resource", + "markdownDescription": "%configuration.markdown.experimental.validate.fileLinks.skipPaths.description%", + "items": { + "type": "string" + } } } }, @@ -504,6 +512,7 @@ "markdown-it": "^12.3.2", "markdown-it-front-matter": "^0.2.1", "morphdom": "^2.6.1", + "picomatch": "^2.3.1", "vscode-languageserver-textdocument": "^1.0.4", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.3" @@ -512,6 +521,7 @@ "@types/dompurify": "^2.3.1", "@types/lodash.throttle": "^4.1.3", "@types/markdown-it": "12.2.3", + "@types/picomatch": "^2.3.0", "@types/vscode-notebook-renderer": "^1.60.0", "@types/vscode-webview": "^1.57.0", "lodash.throttle": "^4.1.1" diff --git a/extensions/markdown-language-features/package.nls.json b/extensions/markdown-language-features/package.nls.json index 2d9ba258003..b2958199b91 100644 --- a/extensions/markdown-language-features/package.nls.json +++ b/extensions/markdown-language-features/package.nls.json @@ -30,8 +30,9 @@ "configuration.markdown.suggest.paths.enabled.description": "Enable/disable path suggestions for markdown links", "configuration.markdown.editor.drop.enabled": "Enable/disable dropping into the markdown editor to insert shift. Requires enabling `#workbenck.experimental.editor.dropIntoEditor.enabled#`.", "configuration.markdown.experimental.validate.enabled.description": "Enable/disable all error reporting in Markdown files.", - "configuration.markdown.experimental.validate.referenceLinks.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.", - "configuration.markdown.experimental.validate.headerLinks.description": "Validate links to headers in Markdown files, e.g. `[link](#header)`. Requires enabling `#markdown.experimental.validate.enabled#`.", - "configuration.markdown.experimental.validate.fileLinks.description": "Validate links to other files in Markdown files, e.g. `[link](/path/to/file.md)`. This checks that the target files exists. Requires enabling `#markdown.experimental.validate.enabled#`.", + "configuration.markdown.experimental.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, e.g. `[link][ref]`. Requires enabling `#markdown.experimental.validate.enabled#`.", + "configuration.markdown.experimental.validate.headerLinks.enabled.description": "Validate links to headers in Markdown files, e.g. `[link](#header)`. Requires enabling `#markdown.experimental.validate.enabled#`.", + "configuration.markdown.experimental.validate.fileLinks.enabled.description": "Validate links to other files in Markdown files, e.g. `[link](/path/to/file.md)`. This checks that the target files exists. Requires enabling `#markdown.experimental.validate.enabled#`.", + "configuration.markdown.experimental.validate.fileLinks.skipPaths.description": "Configure glob patterns for links to treat as valid, even if they don't exist in the workspace. For example `/about` would make the link `[about](/about)` valid, while the glob `/assets/**/*.svg` would let you link to any `.svg` asset under the `assets` directory", "workspaceTrust": "Required for loading styles configured in the workspace." } diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index 4938c1004bf..f088f91391a 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -76,7 +76,7 @@ function registerMarkdownLanguageFeatures( vscode.languages.registerRenameProvider(selector, new MdRenameProvider(referencesProvider, workspaceContents, githubSlugifier)), vscode.languages.registerDefinitionProvider(selector, new MdDefinitionProvider(referencesProvider)), MdPathCompletionProvider.register(selector, engine, linkProvider), - registerDiagnostics(engine, workspaceContents, linkProvider), + registerDiagnostics(selector, engine, workspaceContents, linkProvider, commandManager), registerDropIntoEditor(selector), registerFindFileReferences(commandManager, referencesProvider), ); diff --git a/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts b/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts index f53a83d670e..eb4c436afd5 100644 --- a/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts +++ b/extensions/markdown-language-features/src/languageFeatures/diagnostics.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; +import * as picomatch from 'picomatch'; import { MarkdownEngine } from '../markdownEngine'; import { TableOfContents } from '../tableOfContents'; import { Delayer } from '../util/async'; @@ -14,6 +15,7 @@ import { Limiter } from '../util/limiter'; import { MdWorkspaceContents, SkinnyTextDocument } from '../workspaceContents'; import { InternalHref, LinkDefinitionSet, MdLink, MdLinkProvider, MdLinkSource } from './documentLinkProvider'; import { tryFindMdDocumentForLink } from './references'; +import { CommandManager } from '../commandManager'; const localize = nls.loadMessageBundle(); @@ -37,6 +39,7 @@ export interface DiagnosticOptions { readonly validateReferences: DiagnosticLevel; readonly validateOwnHeaders: DiagnosticLevel; readonly validateFilePaths: DiagnosticLevel; + readonly skipPaths: readonly string[]; } function toSeverity(level: DiagnosticLevel): vscode.DiagnosticSeverity | undefined { @@ -56,7 +59,13 @@ class VSCodeDiagnosticConfiguration extends Disposable implements DiagnosticConf super(); this._register(vscode.workspace.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('markdown.experimental.validate.enabled')) { + if ( + e.affectsConfiguration('markdown.experimental.validate.enabled') + || e.affectsConfiguration('markdown.experimental.validate.referenceLinks.enabled') + || e.affectsConfiguration('markdown.experimental.validate.headerLinks.enabled') + || e.affectsConfiguration('markdown.experimental.validate.fileLinks.enabled') + || e.affectsConfiguration('markdown.experimental.validate.fileLinks.skipPaths') + ) { this._onDidChange.fire(); } })); @@ -66,9 +75,10 @@ class VSCodeDiagnosticConfiguration extends Disposable implements DiagnosticConf const config = vscode.workspace.getConfiguration('markdown', resource); return { enabled: config.get<boolean>('experimental.validate.enabled', false), - validateReferences: config.get<DiagnosticLevel>('experimental.validate.referenceLinks', DiagnosticLevel.ignore), - validateOwnHeaders: config.get<DiagnosticLevel>('experimental.validate.headerLinks', DiagnosticLevel.ignore), - validateFilePaths: config.get<DiagnosticLevel>('experimental.validate.fileLinks', DiagnosticLevel.ignore), + validateReferences: config.get<DiagnosticLevel>('experimental.validate.referenceLinks.enabled', DiagnosticLevel.ignore), + validateOwnHeaders: config.get<DiagnosticLevel>('experimental.validate.headerLinks.enabled', DiagnosticLevel.ignore), + validateFilePaths: config.get<DiagnosticLevel>('experimental.validate.fileLinks.enabled', DiagnosticLevel.ignore), + skipPaths: config.get('experimental.validate.fileLinks.skipPaths', []), }; } } @@ -206,6 +216,16 @@ class LinkWatcher extends Disposable { } } +class FileDoesNotExistDiagnostic extends vscode.Diagnostic { + + public readonly path: string; + + constructor(range: vscode.Range, message: string, severity: vscode.DiagnosticSeverity, path: string) { + super(range, message, severity); + this.path = path; + } +} + export class DiagnosticManager extends Disposable { private readonly collection: vscode.DiagnosticCollection; @@ -459,9 +479,11 @@ export class DiagnosticComputer { } if (!hrefDoc && !await this.workspaceContents.pathExists(path)) { - const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.toString(true)); + const msg = localize('invalidPathLink', 'File does not exist at path: {0}', path.fsPath); for (const link of links) { - diagnostics.push(new vscode.Diagnostic(link.source.hrefRange, msg, severity)); + if (!options.skipPaths.some(glob => picomatch.isMatch(link.source.pathText, glob))) { + diagnostics.push(new FileDoesNotExistDiagnostic(link.source.hrefRange, msg, severity, link.source.pathText)); + } } } else if (hrefDoc) { // Validate each of the links to headers in the file @@ -482,12 +504,64 @@ export class DiagnosticComputer { } } +class AddToSkipPathsQuickFixProvider implements vscode.CodeActionProvider { + + private static readonly _addToSkipPathsCommandId = '_markdown.addToSkipPaths'; + + private static readonly metadata: vscode.CodeActionProviderMetadata = { + providedCodeActionKinds: [ + vscode.CodeActionKind.QuickFix + ], + }; + + public static register(selector: vscode.DocumentSelector, commandManager: CommandManager): vscode.Disposable { + const reg = vscode.languages.registerCodeActionsProvider(selector, new AddToSkipPathsQuickFixProvider(), AddToSkipPathsQuickFixProvider.metadata); + const commandReg = commandManager.register({ + id: AddToSkipPathsQuickFixProvider._addToSkipPathsCommandId, + execute(resource: vscode.Uri, path: string) { + const settingId = 'experimental.validate.fileLinks.skipPaths'; + const config = vscode.workspace.getConfiguration('markdown', resource); + const paths = new Set(config.get<string[]>(settingId, [])); + paths.add(path); + config.update(settingId, [...paths], vscode.ConfigurationTarget.WorkspaceFolder); + } + }); + return vscode.Disposable.from(reg, commandReg); + } + + provideCodeActions(document: vscode.TextDocument, _range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, _token: vscode.CancellationToken): vscode.ProviderResult<(vscode.CodeAction | vscode.Command)[]> { + const fixes: vscode.CodeAction[] = []; + + for (const diagnostic of context.diagnostics) { + if (diagnostic instanceof FileDoesNotExistDiagnostic) { + const fix = new vscode.CodeAction( + localize('skipPathsQuickFix.title', "Add '{0}' to paths that skip link validation.", diagnostic.path), + vscode.CodeActionKind.QuickFix); + + fix.command = { + command: AddToSkipPathsQuickFixProvider._addToSkipPathsCommandId, + title: '', + arguments: [document.uri, diagnostic.path] + }; + fixes.push(fix); + } + } + + return fixes; + } +} + export function register( + selector: vscode.DocumentSelector, engine: MarkdownEngine, workspaceContents: MdWorkspaceContents, linkProvider: MdLinkProvider, + commandManager: CommandManager, ): vscode.Disposable { const configuration = new VSCodeDiagnosticConfiguration(); const manager = new DiagnosticManager(new DiagnosticComputer(engine, workspaceContents, linkProvider), configuration); - return vscode.Disposable.from(configuration, manager); + return vscode.Disposable.from( + configuration, + manager, + AddToSkipPathsQuickFixProvider.register(selector, commandManager)); } diff --git a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts index 2a239a04491..e58094d7b7f 100644 --- a/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/languageFeatures/documentLinkProvider.ts @@ -93,7 +93,16 @@ function getWorkspaceFolder(document: SkinnyTextDocument) { } export interface MdLinkSource { + /** + * The original text of the link destination in code. + */ readonly text: string; + + /** + * The original text of just the link's path in code. + */ + readonly pathText: string; + readonly resource: vscode.Uri; readonly hrefRange: vscode.Range; readonly fragmentRange: vscode.Range | undefined; @@ -138,7 +147,7 @@ function extractDocumentLink( text: link, resource: document.uri, hrefRange: new vscode.Range(linkStart, linkEnd), - fragmentRange: getFragmentRange(link, linkStart, linkEnd), + ...getLinkSourceFragmentInfo(document, link, linkStart, linkEnd), } }; } catch { @@ -154,6 +163,14 @@ function getFragmentRange(text: string, start: vscode.Position, end: vscode.Posi return new vscode.Range(start.translate({ characterDelta: index + 1 }), end); } +function getLinkSourceFragmentInfo(document: SkinnyTextDocument, link: string, linkStart: vscode.Position, linkEnd: vscode.Position): { fragmentRange: vscode.Range | undefined; pathText: string } { + const fragmentRange = getFragmentRange(link, linkStart, linkEnd); + return { + pathText: document.getText(new vscode.Range(linkStart, fragmentRange ? fragmentRange.start.translate(0, -1) : linkEnd)), + fragmentRange, + }; +} + const angleBracketLinkRe = /^<(.*)>$/; /** @@ -314,7 +331,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider { text: link, resource: document.uri, hrefRange: new vscode.Range(linkStart, linkEnd), - fragmentRange: getFragmentRange(link, linkStart, linkEnd), + ...getLinkSourceFragmentInfo(document, link, linkStart, linkEnd), } }; } @@ -350,6 +367,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider { kind: 'link', source: { text: reference, + pathText: reference, resource: document.uri, hrefRange, fragmentRange: undefined, @@ -402,7 +420,7 @@ export class MdLinkProvider implements vscode.DocumentLinkProvider { text: link, resource: document.uri, hrefRange, - fragmentRange: getFragmentRange(link, linkStart, linkEnd), + ...getLinkSourceFragmentInfo(document, link, linkStart, linkEnd), }, ref: { text: reference, range: refRange }, href: target, diff --git a/extensions/markdown-language-features/src/test/diagnostic.test.ts b/extensions/markdown-language-features/src/test/diagnostic.test.ts index a9f54978b7d..e58dabd983e 100644 --- a/extensions/markdown-language-features/src/test/diagnostic.test.ts +++ b/extensions/markdown-language-features/src/test/diagnostic.test.ts @@ -26,6 +26,7 @@ async function getComputedDiagnostics(doc: InMemoryDocument, workspaceContents: validateFilePaths: DiagnosticLevel.warning, validateOwnHeaders: DiagnosticLevel.warning, validateReferences: DiagnosticLevel.warning, + skipPaths: [], }, noopToken) ).diagnostics; } @@ -43,6 +44,7 @@ class MemoryDiagnosticConfiguration implements DiagnosticConfiguration { constructor( private readonly enabled: boolean = true, + private readonly skipPaths: string[] = [], ) { } getOptions(_resource: vscode.Uri): DiagnosticOptions { @@ -52,6 +54,7 @@ class MemoryDiagnosticConfiguration implements DiagnosticConfiguration { validateFilePaths: DiagnosticLevel.ignore, validateOwnHeaders: DiagnosticLevel.ignore, validateReferences: DiagnosticLevel.ignore, + skipPaths: this.skipPaths, }; } return { @@ -59,6 +62,7 @@ class MemoryDiagnosticConfiguration implements DiagnosticConfiguration { validateFilePaths: DiagnosticLevel.warning, validateOwnHeaders: DiagnosticLevel.warning, validateReferences: DiagnosticLevel.warning, + skipPaths: this.skipPaths, }; } } @@ -179,4 +183,48 @@ suite('markdown: Diagnostics', () => { const diagnostics = await getComputedDiagnostics(doc1, new InMemoryWorkspaceMarkdownDocuments([doc1])); assert.deepStrictEqual(diagnostics.length, 0); }); + + test('Should allow ignoring invalid file link using glob', async () => { + const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( + `[text](/no-such-file)`, + `![img](/no-such-file)`, + `[text]: /no-such-file`, + )); + + const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file'])); + const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken); + assert.deepStrictEqual(diagnostics.length, 0); + }); + + test('skipPaths should allow skipping non-existent file', async () => { + const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( + `[text](/no-such-file#header)`, + )); + + const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file'])); + const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken); + assert.deepStrictEqual(diagnostics.length, 0); + }); + + test('skipPaths should not consider link fragment', async () => { + const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( + `[text](/no-such-file#header)`, + )); + + const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/no-such-file'])); + const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken); + assert.deepStrictEqual(diagnostics.length, 0); + }); + + test('skipPaths should support globs', async () => { + const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( + `![i](/images/aaa.png)`, + `![i](/images/sub/bbb.png)`, + `![i](/images/sub/sub2/ccc.png)`, + )); + + const manager = createDiagnosticsManager(new InMemoryWorkspaceMarkdownDocuments([doc1]), new MemoryDiagnosticConfiguration(true, ['/images/**/*.png'])); + const { diagnostics } = await manager.recomputeDiagnosticState(doc1, noopToken); + assert.deepStrictEqual(diagnostics.length, 0); + }); }); diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 5268b01f46c..eaa76d9abbf 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -39,6 +39,11 @@ resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== +"@types/picomatch@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@types/picomatch/-/picomatch-2.3.0.tgz#75db5e75a713c5a83d5b76780c3da84a82806003" + integrity sha512-O397rnSS9iQI4OirieAtsDqvCj4+3eY1J+EPdNTKuHuRWIfUoGyzX294o8C4KJYaLqgSrd2o60c5EqCU8Zv02g== + "@types/trusted-types@*": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" @@ -117,6 +122,11 @@ morphdom@^2.6.1: resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.6.1.tgz#e868e24f989fa3183004b159aed643e628b4306e" integrity sha512-Y8YRbAEP3eKykroIBWrjcfMw7mmwJfjhqdpSvoqinu8Y702nAwikpXcNFDiIkyvfCLxLM9Wu95RZqo4a9jFBaA== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" diff --git a/extensions/markdown-math/package.json b/extensions/markdown-math/package.json index 8267989daee..d3bb21a553a 100644 --- a/extensions/markdown-math/package.json +++ b/extensions/markdown-math/package.json @@ -90,7 +90,7 @@ "build-notebook": "node ./esbuild" }, "dependencies": { - "@iktakahiro/markdown-it-katex": "https://github.com/mjbvz/markdown-it-katex.git" + "@iktakahiro/markdown-it-katex": "mjbvz/markdown-it-katex" }, "devDependencies": { "@types/markdown-it": "^0.0.0", diff --git a/extensions/markdown-math/yarn.lock b/extensions/markdown-math/yarn.lock index 645b0080707..2b979935781 100644 --- a/extensions/markdown-math/yarn.lock +++ b/extensions/markdown-math/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@iktakahiro/markdown-it-katex@https://github.com/mjbvz/markdown-it-katex.git": +"@iktakahiro/markdown-it-katex@mjbvz/markdown-it-katex": version "4.0.1" - resolved "https://github.com/mjbvz/markdown-it-katex.git#2e3736e4b916ee64ed92ebfabeaa94643612665a" + resolved "https://codeload.github.com/mjbvz/markdown-it-katex/tar.gz/1e0d09f9174b3ee1537de2586ce8d8a460284ce4" dependencies: katex "^0.13.0" diff --git a/extensions/notebook-renderers/src/textHelper.ts b/extensions/notebook-renderers/src/textHelper.ts index af53635710d..9daafb721f8 100644 --- a/extensions/notebook-renderers/src/textHelper.ts +++ b/extensions/notebook-renderers/src/textHelper.ts @@ -25,7 +25,7 @@ function generateViewMoreElement(outputId: string) { } export function truncatedArrayOfString(id: string, outputs: string[], linesLimit: number, container: HTMLElement) { - let buffer = outputs.join('\n').split(/\r|\n|\r\n/g); + let buffer = outputs.join('\n').split(/\r\n|\r|\n/g); let lineCount = buffer.length; if (lineCount < linesLimit) { diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index e5ca635d50c..14618b75330 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -686,7 +686,7 @@ }, "js/ts.implicitProjectConfig.checkJs": { "type": "boolean", - "default": true, + "default": false, "markdownDescription": "%configuration.implicitProjectConfig.checkJs%", "scope": "window" }, @@ -705,7 +705,7 @@ }, "js/ts.implicitProjectConfig.strictNullChecks": { "type": "boolean", - "default": false, + "default": true, "markdownDescription": "%configuration.implicitProjectConfig.strictNullChecks%", "scope": "window" }, diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index 34355b5e3e5..2690f743848 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -82,7 +82,7 @@ export class ImplicitProjectConfiguration { private static readCheckJs(configuration: vscode.WorkspaceConfiguration): boolean { return configuration.get<boolean>('js/ts.implicitProjectConfig.checkJs') - ?? configuration.get<boolean>('javascript.implicitProjectConfig.checkJs', true); + ?? configuration.get<boolean>('javascript.implicitProjectConfig.checkJs', false); } private static readExperimentalDecorators(configuration: vscode.WorkspaceConfiguration): boolean { @@ -91,7 +91,7 @@ export class ImplicitProjectConfiguration { } private static readImplicitStrictNullChecks(configuration: vscode.WorkspaceConfiguration): boolean { - return configuration.get<boolean>('js/ts.implicitProjectConfig.strictNullChecks', false); + return configuration.get<boolean>('js/ts.implicitProjectConfig.strictNullChecks', true); } private static readImplicitStrictFunctionTypes(configuration: vscode.WorkspaceConfiguration): boolean { diff --git a/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html index 13fd84fbd06..be1437797f8 100644 --- a/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html +++ b/extensions/vscode-colorize-tests/test/colorize-fixtures/test.html @@ -39,4 +39,4 @@ <span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span> </div> </body> -</html>
\ No newline at end of file +</html> diff --git a/package.json b/package.json index 9a63b8672fe..82aca1ba5cf 100644 --- a/package.json +++ b/package.json @@ -85,12 +85,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.43", - "xterm-addon-search": "0.9.0-beta.35", + "xterm": "4.19.0-beta.47", + "xterm-addon-search": "0.9.0-beta.37", "xterm-addon-serialize": "0.7.0-beta.12", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.34", - "xterm-headless": "4.19.0-beta.43", + "xterm-addon-webgl": "0.12.0-beta.36", + "xterm-headless": "4.19.0-beta.47", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, @@ -136,7 +136,7 @@ "cssnano": "^4.1.11", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "17.4.3", + "electron": "17.4.4", "eslint": "8.7.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-jsdoc": "^19.1.0", @@ -200,7 +200,7 @@ "style-loader": "^1.0.0", "ts-loader": "^9.2.7", "tsec": "0.1.4", - "typescript": "^4.8.0-dev.20220511", + "typescript": "^4.8.0-dev.20220518", "typescript-formatter": "7.1.0", "underscore": "^1.12.1", "util": "^0.12.4", @@ -230,4 +230,4 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4" } -}
\ No newline at end of file +} diff --git a/product.json b/product.json index e80c93598d5..ca0f29df1da 100644 --- a/product.json +++ b/product.json @@ -27,7 +27,7 @@ "licenseFileName": "LICENSE.txt", "reportIssueUrl": "https://github.com/microsoft/vscode/issues/new", "urlProtocol": "code-oss", - "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-cdn.net/insider/181b43c0e2949e36ecb623d8cc6de29d4fa2bae8/out/vs/workbench/contrib/webview/browser/pre/", + "webviewContentExternalBaseUrlTemplate": "https://{{uuid}}.vscode-cdn.net/insider/3c8520fab514b9f56070214496b26ff68d1b1cb5/out/vs/workbench/contrib/webview/browser/pre/", "builtInExtensions": [ { "name": "ms-vscode.js-debug-companion", @@ -61,7 +61,7 @@ }, { "name": "ms-vscode.vscode-js-profile-table", - "version": "1.0.1", + "version": "1.0.2", "repo": "https://github.com/microsoft/vscode-js-profile-visualizer", "metadata": { "id": "7e52b41b-71ad-457b-ab7e-0620f1fc4feb", diff --git a/remote/package.json b/remote/package.json index 80e835671ce..75e83acbde5 100644 --- a/remote/package.json +++ b/remote/package.json @@ -24,12 +24,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.43", - "xterm-addon-search": "0.9.0-beta.35", + "xterm": "4.19.0-beta.47", + "xterm-addon-search": "0.9.0-beta.37", "xterm-addon-serialize": "0.7.0-beta.12", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.34", - "xterm-headless": "4.19.0-beta.43", + "xterm-addon-webgl": "0.12.0-beta.36", + "xterm-headless": "4.19.0-beta.47", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index cdbbf667adf..ece7c79fe5c 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -10,9 +10,9 @@ "tas-client-umd": "0.1.5", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.43", - "xterm-addon-search": "0.9.0-beta.35", + "xterm": "4.19.0-beta.47", + "xterm-addon-search": "0.9.0-beta.37", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.34" + "xterm-addon-webgl": "0.12.0-beta.36" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 8316dc85a0e..97609688b6d 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -113,22 +113,22 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-search@0.9.0-beta.35: - version "0.9.0-beta.35" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.35.tgz#524ee3be855c1e8db234c6795bdb44bb6baff8fd" - integrity sha512-hTDqAhqlhBvz3dtdK1Tg5Al2U3HquSHpV1xCX+bbOmbgprAxUrSQxslUPDD69CTazzTyif3L19M08hccRyr1Ug== +xterm-addon-search@0.9.0-beta.37: + version "0.9.0-beta.37" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.37.tgz#84a020f03b2cacc5afac78ca6ff2f1eb86fb6710" + integrity sha512-bfeFgKJkDYyIgqpWiV1oWYqDiTo+SHTeIPEbpOfxDr97pc3PtDF1Tyd79PrvJNfoxaV3VMUo//UEOy4D+KY9OQ== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.34: - version "0.12.0-beta.34" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.34.tgz#51cac31cc7a78377be5d481b624ee82948360de1" - integrity sha512-TTIwun+a45oDN54sHhdUxsEx6VflgF2p9YGqS5+gVzpvPrEqP6GoDr6XFCDsZcSqi0ZT2FNGAKWlh7XSxsKQQw== +xterm-addon-webgl@0.12.0-beta.36: + version "0.12.0-beta.36" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.36.tgz#460f80829a78c979a448d5b764699af3f0366ff1" + integrity sha512-sgX7OHSGZQZE5b4xtPqd/5NEcll0Z+00tnTVxKZlXf5XEENcG0tnBF4I4f+k9K3cmjE1UIUVG2yYPrqWlYCdpA== -xterm@4.19.0-beta.43: - version "4.19.0-beta.43" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.43.tgz#f2113c8ce303d22c5cfad1a4a119b81c103285fa" - integrity sha512-eQ3fzkUApGdl4/rrhzK4OIdMb3+qO0c2iCZIMbeP9SqqDltZnhWncz+3lGa0tnxKizVoUV9kmGaP7orsQ/IavQ== +xterm@4.19.0-beta.47: + version "4.19.0-beta.47" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.47.tgz#f5931201346a485e3bcb29d24e83583727e55707" + integrity sha512-c8EcCSWCHnFYNdRMTnJIpYTV9J2Ze7kdB1GhTcPO2ipMEsqaP/u6Ca8rgBWwV9HeEVfe4rGRqWW2qcSy4U9hMQ== diff --git a/remote/yarn.lock b/remote/yarn.lock index a6201c6d433..f023194fa26 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -914,10 +914,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-search@0.9.0-beta.35: - version "0.9.0-beta.35" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.35.tgz#524ee3be855c1e8db234c6795bdb44bb6baff8fd" - integrity sha512-hTDqAhqlhBvz3dtdK1Tg5Al2U3HquSHpV1xCX+bbOmbgprAxUrSQxslUPDD69CTazzTyif3L19M08hccRyr1Ug== +xterm-addon-search@0.9.0-beta.37: + version "0.9.0-beta.37" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.37.tgz#84a020f03b2cacc5afac78ca6ff2f1eb86fb6710" + integrity sha512-bfeFgKJkDYyIgqpWiV1oWYqDiTo+SHTeIPEbpOfxDr97pc3PtDF1Tyd79PrvJNfoxaV3VMUo//UEOy4D+KY9OQ== xterm-addon-serialize@0.7.0-beta.12: version "0.7.0-beta.12" @@ -929,20 +929,20 @@ xterm-addon-unicode11@0.4.0-beta.3: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.34: - version "0.12.0-beta.34" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.34.tgz#51cac31cc7a78377be5d481b624ee82948360de1" - integrity sha512-TTIwun+a45oDN54sHhdUxsEx6VflgF2p9YGqS5+gVzpvPrEqP6GoDr6XFCDsZcSqi0ZT2FNGAKWlh7XSxsKQQw== +xterm-addon-webgl@0.12.0-beta.36: + version "0.12.0-beta.36" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.36.tgz#460f80829a78c979a448d5b764699af3f0366ff1" + integrity sha512-sgX7OHSGZQZE5b4xtPqd/5NEcll0Z+00tnTVxKZlXf5XEENcG0tnBF4I4f+k9K3cmjE1UIUVG2yYPrqWlYCdpA== -xterm-headless@4.19.0-beta.43: - version "4.19.0-beta.43" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.43.tgz#12fe4abe624265240a7de8a922bfc4fd28c5f92a" - integrity sha512-4T8TlWy5u+sS23aPtd8gBHJ0BVljbNQRPMFHzLigDNOMCwc4uWa9JsxYmKteKifcG5aMm11ALPUTxWZCgpATww== +xterm-headless@4.19.0-beta.47: + version "4.19.0-beta.47" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.47.tgz#9d5af8145c42b9a6241a040bb244b877c149761b" + integrity sha512-chVTURPMNDEerQIsN4lIRotpXCfJsTHioZGQxDBNdktZO1gMXGvNxDjzsbsJg5ikLN5llz/HLDfXZrjCeb3elg== -xterm@4.19.0-beta.43: - version "4.19.0-beta.43" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.43.tgz#f2113c8ce303d22c5cfad1a4a119b81c103285fa" - integrity sha512-eQ3fzkUApGdl4/rrhzK4OIdMb3+qO0c2iCZIMbeP9SqqDltZnhWncz+3lGa0tnxKizVoUV9kmGaP7orsQ/IavQ== +xterm@4.19.0-beta.47: + version "4.19.0-beta.47" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.47.tgz#f5931201346a485e3bcb29d24e83583727e55707" + integrity sha512-c8EcCSWCHnFYNdRMTnJIpYTV9J2Ze7kdB1GhTcPO2ipMEsqaP/u6Ca8rgBWwV9HeEVfe4rGRqWW2qcSy4U9hMQ== yallist@^4.0.0: version "4.0.0" diff --git a/src/buildfile.js b/src/buildfile.js index 8c30339da6e..6b49aa30083 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -38,10 +38,6 @@ exports.base = [ }, { name: 'vs/base/common/worker/simpleWorker', - }, - { - name: 'vs/platform/extensions/node/extensionHostStarterWorker', - exclude: ['vs/base/common/worker/simpleWorker'] } ]; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index d30acf1fff9..d2fa1bd3ba8 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -577,6 +577,24 @@ export function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePositi }; } +/** + * Returns the effective zoom on a given element before window zoom level is applied + */ +export function getDomNodeZoomLevel(domNode: HTMLElement): number { + let testElement: HTMLElement | null = domNode; + let zoom = 1.0; + do { + const elementZoomLevel = (getComputedStyle(testElement) as any).zoom; + if (elementZoomLevel !== null && elementZoomLevel !== undefined && elementZoomLevel !== '1') { + zoom *= elementZoomLevel; + } + + testElement = testElement.parentElement; + } while (testElement !== null && testElement !== document.documentElement); + + return zoom; +} + export interface IStandardWindow { readonly scrollX: number; readonly scrollY: number; diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index c34f711ae9f..1aa24bde272 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -262,11 +262,16 @@ export class ContextView extends Disposable { if (DOM.isHTMLElement(anchor)) { let elementPosition = DOM.getDomNodePagePosition(anchor); + // In areas where zoom is applied to the element or its ancestors, we need to adjust the size of the element + // e.g. The title bar has counter zoom behavior meaning it applies the inverse of zoom level. + // Window Zoom Level: 1.5, Title Bar Zoom: 1/1.5, Size Multiplier: 1.5 + const zoom = DOM.getDomNodeZoomLevel(anchor); + around = { - top: elementPosition.top, - left: elementPosition.left, - width: elementPosition.width, - height: elementPosition.height + top: elementPosition.top * zoom, + left: elementPosition.left * zoom, + width: elementPosition.width * zoom, + height: elementPosition.height * zoom }; } else { around = { diff --git a/src/vs/base/browser/ui/menu/menubar.css b/src/vs/base/browser/ui/menu/menubar.css index d2a70146718..b9dd13780e9 100644 --- a/src/vs/base/browser/ui/menu/menubar.css +++ b/src/vs/base/browser/ui/menu/menubar.css @@ -9,7 +9,8 @@ display: flex; flex-shrink: 1; box-sizing: border-box; - height: 30px; + height: 100%; + padding: 4px 0; overflow: hidden; flex-wrap: wrap; } @@ -23,6 +24,7 @@ align-items: center; box-sizing: border-box; padding: 0px 8px; + border-radius: 5px; cursor: default; -webkit-app-region: no-drag; zoom: 1; diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 64085aad356..a162ae7db70 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -46,7 +46,7 @@ import { getResolvedShellEnv } from 'vs/platform/shell/node/shellEnv'; import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust'; import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService'; import { IExtensionHostStarter, ipcExtensionHostStarterChannelName } from 'vs/platform/extensions/common/extensionHostStarter'; -import { WorkerMainProcessExtensionHostStarter } from 'vs/platform/extensions/electron-main/workerMainProcessExtensionHostStarter'; +import { ExtensionHostStarter } from 'vs/platform/extensions/electron-main/extensionHostStarter'; import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal'; import { LinuxExternalTerminalService, MacExternalTerminalService, WindowsExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService'; import { LOCAL_FILE_SYSTEM_CHANNEL_NAME } from 'vs/platform/files/common/diskFileSystemProviderClient'; @@ -643,7 +643,7 @@ export class CodeApplication extends Disposable { services.set(IExtensionUrlTrustService, new SyncDescriptor(ExtensionUrlTrustService)); // Extension Host Starter - services.set(IExtensionHostStarter, new SyncDescriptor(WorkerMainProcessExtensionHostStarter)); + services.set(IExtensionHostStarter, new SyncDescriptor(ExtensionHostStarter)); // Storage services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); diff --git a/src/vs/css.js b/src/vs/css.js index a719c310ec3..8a0f9912902 100644 --- a/src/vs/css.js +++ b/src/vs/css.js @@ -16,10 +16,6 @@ 'use strict'; var CSSLoaderPlugin; (function (CSSLoaderPlugin) { - /** - * Known issue: - * - In IE there is no way to know if the CSS file loaded successfully or not. - */ var BrowserCSSLoader = /** @class */ (function () { function BrowserCSSLoader() { this._pendingLoads = 0; diff --git a/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.test.ts b/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.test.ts index d801c2c7722..096713ed3b0 100644 --- a/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.test.ts +++ b/src/vs/editor/contrib/documentSymbols/test/browser/outlineModel.test.ts @@ -77,9 +77,9 @@ suite('OutlineModel', function () { }); assert.strictEqual(isCancelled, false); - let s1 = new CancellationTokenSource(); + const s1 = new CancellationTokenSource(); service.getOrCreate(model, s1.token); - let s2 = new CancellationTokenSource(); + const s2 = new CancellationTokenSource(); service.getOrCreate(model, s2.token); s1.cancel(); diff --git a/src/vs/editor/contrib/folding/test/browser/foldingModel.test.ts b/src/vs/editor/contrib/folding/test/browser/foldingModel.test.ts index 6b54319a21a..9db0f7f572d 100644 --- a/src/vs/editor/contrib/folding/test/browser/foldingModel.test.ts +++ b/src/vs/editor/contrib/folding/test/browser/foldingModel.test.ts @@ -347,20 +347,20 @@ suite('Folding Model', () => { let textModel = createTextModel(lines.join('\n')); try { - let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel)); + const foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel)); - let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); + const ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ }); foldingModel.update(ranges); - let r1 = r(1, 2, false); - let r2 = r(3, 11, false); - let r3 = r(4, 10, false); - let r4 = r(5, 6, false); - let r5 = r(8, 9, false); + const r1 = r(1, 2, false); + const r2 = r(3, 11, false); + const r3 = r(4, 10, false); + const r4 = r(5, 6, false); + const r5 = r(8, 9, false); - let region1 = foldingModel.getRegionAtLine(r1.startLineNumber); - let region2 = foldingModel.getRegionAtLine(r2.startLineNumber); - let region3 = foldingModel.getRegionAtLine(r3.startLineNumber); + const region1 = foldingModel.getRegionAtLine(r1.startLineNumber); + const region2 = foldingModel.getRegionAtLine(r2.startLineNumber); + const region3 = foldingModel.getRegionAtLine(r3.startLineNumber); assertRanges(foldingModel, [r1, r2, r3, r4, r5]); diff --git a/src/vs/loader.js b/src/vs/loader.js index d66392e23a0..69554c5fac4 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -277,8 +277,10 @@ var AMDLoader; return; } if (err.phase === 'factory') { - console.error('The factory method of "' + err.moduleId + '" has thrown an exception'); + console.error('The factory function of "' + err.moduleId + '" has thrown an exception'); console.error(err); + console.error('Here are the modules that depend on it:'); + console.error(err.neededBy); return; } } @@ -1183,7 +1185,7 @@ var AMDLoader; producedError: null }; }; - Module.prototype.complete = function (recorder, config, dependenciesValues) { + Module.prototype.complete = function (recorder, config, dependenciesValues, inversedependenciesProvider) { this._isComplete = true; var producedError = null; if (this._callback) { @@ -1204,6 +1206,7 @@ var AMDLoader; var err = AMDLoader.ensureError(producedError); err.phase = 'factory'; err.moduleId = this.strId; + err.neededBy = inversedependenciesProvider(this.id); this.error = err; config.onError(err); } @@ -1815,7 +1818,10 @@ var AMDLoader; dependenciesValues[i] = null; } } - module.complete(recorder, this._config, dependenciesValues); + var inversedependenciesProvider = function (moduleId) { + return (_this._inverseDependencies2[moduleId] || []).map(function (intModuleId) { return _this._moduleIdProvider.getStrModuleId(intModuleId); }); + }; + module.complete(recorder, this._config, dependenciesValues, inversedependenciesProvider); // Fetch and clear inverse dependencies var inverseDeps = this._inverseDependencies2[module.id]; this._inverseDependencies2[module.id] = null; diff --git a/src/vs/nls.js b/src/vs/nls.js index f969d159f4a..793f0d6eecb 100644 --- a/src/vs/nls.js +++ b/src/vs/nls.js @@ -114,6 +114,7 @@ var NLSLoaderPlugin; }; NLSPlugin.prototype.load = function (name, req, load, config) { var _this = this; + var _a; config = config || {}; if (!name || name.length === 0) { load({ @@ -148,7 +149,13 @@ var NLSLoaderPlugin; }); } else { - req([name + suffix], messagesLoaded_1); + var base = (_a = pluginConfig.baseUrl) !== null && _a !== void 0 ? _a : ''; + req([base + name + suffix], messagesLoaded_1, function (err) { + var _a; + // We have an error. Load the English default strings instead. + console.warn("Falling back to default strings. Unable to load translations because of: " + ((_a = err.message) !== null && _a !== void 0 ? _a : err)); + req([name + '.nls'], messagesLoaded_1); + }); } } }; diff --git a/src/vs/platform/assignment/common/assignment.ts b/src/vs/platform/assignment/common/assignment.ts index 7ca130fe9f3..9f9b72aea17 100644 --- a/src/vs/platform/assignment/common/assignment.ts +++ b/src/vs/platform/assignment/common/assignment.ts @@ -31,6 +31,7 @@ https://experimentation.visualstudio.com/Analysis%20and%20Experimentation/_git/A "X-VSCode-Build": "build", "X-MSEdge-ClientId": "clientid", "X-VSCode-ExtensionName": "extensionname", +"X-VSCode-ExtensionVersion": "extensionversion", "X-VSCode-TargetPopulation": "targetpopulation", "X-VSCode-Language": "language" */ @@ -66,6 +67,11 @@ export enum Filters { ExtensionName = 'X-VSCode-ExtensionName', /** + * The version of the extension. + */ + ExtensionVersion = 'X-VSCode-ExtensionVersion', + + /** * The language in use by VS Code */ Language = 'X-VSCode-Language', @@ -97,6 +103,8 @@ export class AssignmentFilterProvider implements IExperimentationFilterProvider return platform.language; case Filters.ExtensionName: return 'vscode-core'; // always return vscode-core for exp service + case Filters.ExtensionVersion: + return '999999.0'; // always return a very large number for cross-extension experimentation case Filters.TargetPopulation: return this.targetPopulation; default: diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts index a73af96a7c8..94e9a31abc7 100644 --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -10,7 +10,6 @@ import { CancellationError, getErrorMessage } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; -import { isBoolean } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as nls from 'vs/nls'; import { @@ -364,9 +363,11 @@ export abstract class AbstractExtensionManagementService extends Disposable impl throw new ExtensionManagementError(nls.localize('malicious extension', "Can't install '{0}' extension since it was reported to be problematic.", extension.identifier.id), ExtensionManagementErrorCode.Malicious); } - const deprecated = report.deprecated ? report.deprecated[extension.identifier.id.toLowerCase()] : undefined; - if (deprecated && !isBoolean(deprecated)) { - throw new ExtensionManagementError(nls.localize('unsupported prerelease extension', "Can't install '{0}' extension because it is deprecated. Use '{1}' extension instead.", extension.identifier.id, deprecated.displayName), ExtensionManagementErrorCode.UnsupportedPreRelease); + const deprecated = report.deprecated[extension.identifier.id.toLowerCase()]; + if (deprecated?.disallowInstall) { + const message = deprecated.extension ? nls.localize('unsupported extension with alternative', "Can't install '{0}' extension because it is deprecated. Use {1} extension instead.", extension.identifier.id, deprecated.extension.displayName) + : nls.localize('unsupported extension without alternative and no message', "Can't install '{0}' extension because it is deprecated.", extension.identifier.id); + throw new ExtensionManagementError(message, ExtensionManagementErrorCode.Deprecated); } if (!await this.canInstall(extension)) { @@ -581,7 +582,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl return manifest; } catch (err) { this.logService.trace('ExtensionManagementService.refreshControlCache - failed to get extension control manifest'); - return { malicious: [] }; + return { malicious: [], deprecated: {} }; } } diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index b75a76752b8..a6556211581 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -16,7 +16,7 @@ import { URI } from 'vs/base/common/uri'; import { IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionInfo, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement'; import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; @@ -537,7 +537,20 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller interface IRawExtensionsControlManifest { malicious: string[]; - deprecated?: IStringDictionary<boolean | { id: string; displayName: string; migrateStorage?: boolean; engine?: string; preRelease?: boolean }>; + migrateToPreRelease?: IStringDictionary<{ + id: string; + displayName: string; + migrateStorage?: boolean; + engine?: string; + }>; + deprecated?: IStringDictionary<boolean | { + disallowInstall?: boolean; + extension?: { + id: string; + displayName: string; + }; + settings?: string[]; + }>; } abstract class AbstractExtensionGalleryService implements IExtensionGalleryService { @@ -1138,7 +1151,7 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi } if (!this.extensionsControlUrl) { - return { malicious: [] }; + return { malicious: [], deprecated: {} }; } const context = await this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }, CancellationToken.None); @@ -1148,13 +1161,36 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const result = await asJson<IRawExtensionsControlManifest>(context); const malicious: IExtensionIdentifier[] = []; + const deprecated: IStringDictionary<IDeprecationInfo> = {}; if (result) { for (const id of result.malicious) { malicious.push({ id }); } + if (result.migrateToPreRelease) { + for (const [unsupportedPreReleaseExtensionId, preReleaseExtensionInfo] of Object.entries(result.migrateToPreRelease)) { + if (!preReleaseExtensionInfo.engine || isEngineValid(preReleaseExtensionInfo.engine, this.productService.version, this.productService.date)) { + deprecated[unsupportedPreReleaseExtensionId.toLowerCase()] = { + disallowInstall: true, + extension: { + id: preReleaseExtensionInfo.id, + displayName: preReleaseExtensionInfo.displayName, + autoMigrate: { storage: !!preReleaseExtensionInfo.migrateStorage }, + preRelease: true + } + }; + } + } + } + if (result.deprecated) { + for (const [deprecatedExtensionId, deprecationInfo] of Object.entries(result.deprecated)) { + if (deprecationInfo) { + deprecated[deprecatedExtensionId.toLowerCase()] = isBoolean(deprecationInfo) ? {} : deprecationInfo; + } + } + } } - return { malicious, deprecated: result?.deprecated }; + return { malicious, deprecated }; } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 061de6580a9..d041814268b 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -282,9 +282,20 @@ export const enum StatisticType { Uninstall = 'uninstall' } +export interface IDeprecationInfo { + readonly disallowInstall?: boolean; + readonly extension?: { + readonly id: string; + readonly displayName: string; + readonly autoMigrate?: { readonly storage: boolean }; + readonly preRelease?: boolean; + }; + readonly settings?: readonly string[]; +} + export interface IExtensionsControlManifest { - malicious: IExtensionIdentifier[]; - deprecated?: IStringDictionary<boolean | { id: string; displayName: string; migrateStorage?: boolean; preRelease?: boolean }>; + readonly malicious: IExtensionIdentifier[]; + readonly deprecated: IStringDictionary<IDeprecationInfo>; } export const enum InstallOperation { @@ -349,7 +360,7 @@ export interface DidUninstallExtensionEvent { export enum ExtensionManagementErrorCode { Unsupported = 'Unsupported', - UnsupportedPreRelease = 'UnsupportedPreRelease', + Deprecated = 'Deprecated', Malicious = 'Malicious', Incompatible = 'Incompatible', IncompatiblePreRelease = 'IncompatiblePreRelease', diff --git a/src/vs/platform/extensionManagement/common/unsupportedExtensionsMigration.ts b/src/vs/platform/extensionManagement/common/unsupportedExtensionsMigration.ts index 87eaf1447a6..57aadd8fc1d 100644 --- a/src/vs/platform/extensionManagement/common/unsupportedExtensionsMigration.ts +++ b/src/vs/platform/extensionManagement/common/unsupportedExtensionsMigration.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from 'vs/base/common/cancellation'; -import { isBoolean } from 'vs/base/common/types'; import { IExtensionGalleryService, IExtensionManagementService, IGlobalExtensionEnablementService, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; @@ -26,10 +25,13 @@ export async function migrateUnsupportedExtensions(extensionManagementService: I } const installed = await extensionManagementService.getInstalled(ExtensionType.User); for (const [unsupportedExtensionId, deprecated] of Object.entries(extensionsControlManifest.deprecated)) { - if (isBoolean(deprecated)) { + if (!deprecated?.extension) { + continue; + } + const { id: preReleaseExtensionId, autoMigrate, preRelease } = deprecated.extension; + if (!autoMigrate) { continue; } - const { id: preReleaseExtensionId, migrateStorage, preRelease } = deprecated; const unsupportedExtension = installed.find(i => areSameExtensions(i.identifier, { id: unsupportedExtensionId })); // Unsupported Extension is not installed if (!unsupportedExtension) { @@ -57,7 +59,7 @@ export async function migrateUnsupportedExtensions(extensionManagementService: I await extensionEnablementService.disableExtension(preReleaseExtension.identifier); logService.info(`Disabled the pre-release extension '${preReleaseExtension.identifier.id}' because the unsupported extension '${unsupportedExtension.identifier.id}' is disabled`); } - if (migrateStorage) { + if (autoMigrate.storage) { extensionStorageService.addToMigrationList(getExtensionId(unsupportedExtension.manifest.publisher, unsupportedExtension.manifest.name), getExtensionId(preReleaseExtension.manifest.publisher, preReleaseExtension.manifest.name)); logService.info(`Added pre-release extension to the storage migration list`); } diff --git a/src/vs/platform/extensions/node/extensionHostStarterWorker.ts b/src/vs/platform/extensions/electron-main/extensionHostStarter.ts index e0f8d8b03e4..493168507e8 100644 --- a/src/vs/platform/extensions/node/extensionHostStarterWorker.ts +++ b/src/vs/platform/extensions/electron-main/extensionHostStarter.ts @@ -3,21 +3,134 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { canceled, SerializedError, transformErrorForSerialization } from 'vs/base/common/errors'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform/extensions/common/extensionHostStarter'; +import { Emitter, Event } from 'vs/base/common/event'; +import { ILogService } from 'vs/platform/log/common/log'; +import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; +import { StopWatch } from 'vs/base/common/stopwatch'; import { ChildProcess, fork } from 'child_process'; import { StringDecoder } from 'string_decoder'; import { Promises, timeout } from 'vs/base/common/async'; -import { SerializedError, transformErrorForSerialization } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { FileAccess } from 'vs/base/common/network'; import { mixin } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { cwd } from 'vs/base/common/process'; -import { StopWatch } from 'vs/base/common/stopwatch'; -import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform/extensions/common/extensionHostStarter'; -export interface IExtensionHostStarterWorkerHost { - logInfo(message: string): Promise<void>; +export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter { + _serviceBrand: undefined; + + private static _lastId: number = 0; + + protected readonly _extHosts: Map<string, ExtensionHostProcess>; + private _shutdown = false; + + constructor( + @ILogService private readonly _logService: ILogService, + @ILifecycleMainService lifecycleMainService: ILifecycleMainService + ) { + this._extHosts = new Map<string, ExtensionHostProcess>(); + + // On shutdown: gracefully await extension host shutdowns + lifecycleMainService.onWillShutdown((e) => { + this._shutdown = true; + e.join(this._waitForAllExit(6000)); + }); + } + + dispose(): void { + // Intentionally not killing the extension host processes + } + + private _getExtHost(id: string): ExtensionHostProcess { + const extHostProcess = this._extHosts.get(id); + if (!extHostProcess) { + throw new Error(`Unknown extension host!`); + } + return extHostProcess; + } + + onDynamicStdout(id: string): Event<string> { + return this._getExtHost(id).onStdout; + } + + onDynamicStderr(id: string): Event<string> { + return this._getExtHost(id).onStderr; + } + + onDynamicMessage(id: string): Event<any> { + return this._getExtHost(id).onMessage; + } + + onDynamicError(id: string): Event<{ error: SerializedError }> { + return this._getExtHost(id).onError; + } + + onDynamicExit(id: string): Event<{ code: number; signal: string }> { + return this._getExtHost(id).onExit; + } + + async createExtensionHost(): Promise<{ id: string }> { + if (this._shutdown) { + throw canceled(); + } + const id = String(++ExtensionHostStarter._lastId); + const extHost = new ExtensionHostProcess(id, this._logService); + this._extHosts.set(id, extHost); + extHost.onExit(({ pid, code, signal }) => { + this._logService.info(`Extension host with pid ${pid} exited with code: ${code}, signal: ${signal}.`); + setTimeout(() => { + extHost.dispose(); + this._extHosts.delete(id); + }); + }); + return { id }; + } + + async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number }> { + if (this._shutdown) { + throw canceled(); + } + return this._getExtHost(id).start(opts); + } + + async enableInspectPort(id: string): Promise<boolean> { + if (this._shutdown) { + throw canceled(); + } + const extHostProcess = this._extHosts.get(id); + if (!extHostProcess) { + return false; + } + return extHostProcess.enableInspectPort(); + } + + async kill(id: string): Promise<void> { + if (this._shutdown) { + throw canceled(); + } + const extHostProcess = this._extHosts.get(id); + if (!extHostProcess) { + // already gone! + return; + } + extHostProcess.kill(); + } + + async _killAllNow(): Promise<void> { + for (const [, extHost] of this._extHosts) { + extHost.kill(); + } + } + + async _waitForAllExit(maxWaitTimeMs: number): Promise<void> { + const exitPromises: Promise<void>[] = []; + for (const [, extHost] of this._extHosts) { + exitPromises.push(extHost.waitForExit(maxWaitTimeMs)); + } + return Promises.settled(exitPromises).then(() => { }); + } } class ExtensionHostProcess extends Disposable { @@ -42,14 +155,14 @@ class ExtensionHostProcess extends Disposable { constructor( public readonly id: string, - private readonly _host: IExtensionHostStarterWorkerHost + @ILogService private readonly _logService: ILogService, ) { super(); } start(opts: IExtensionHostProcessOptions): { pid: number } { if (platform.isCI) { - this._host.logInfo(`Calling fork to start extension host...`); + this._logService.info(`Calling fork to start extension host...`); } const sw = StopWatch.create(false); this._process = fork( @@ -60,7 +173,7 @@ class ExtensionHostProcess extends Disposable { const forkTime = sw.elapsed(); const pid = this._process.pid!; - this._host.logInfo(`Starting extension host with pid ${pid} (fork() took ${forkTime} ms).`); + this._logService.info(`Starting extension host with pid ${pid} (fork() took ${forkTime} ms).`); const stdoutDecoder = new StringDecoder('utf-8'); this._process.stdout?.on('data', (chunk) => { @@ -95,7 +208,7 @@ class ExtensionHostProcess extends Disposable { return false; } - this._host.logInfo(`Enabling inspect port on extension host with pid ${this._process.pid}.`); + this._logService.info(`Enabling inspect port on extension host with pid ${this._process.pid}.`); interface ProcessExt { _debugProcess?(n: number): any; @@ -119,7 +232,7 @@ class ExtensionHostProcess extends Disposable { if (!this._process) { return; } - this._host.logInfo(`Killing extension host with pid ${this._process.pid}.`); + this._logService.info(`Killing extension host with pid ${this._process.pid}.`); this._process.kill(); } @@ -128,116 +241,13 @@ class ExtensionHostProcess extends Disposable { return; } const pid = this._process.pid; - this._host.logInfo(`Waiting for extension host with pid ${pid} to exit.`); + this._logService.info(`Waiting for extension host with pid ${pid} to exit.`); await Promise.race([Event.toPromise(this.onExit), timeout(maxWaitTimeMs)]); if (!this._hasExited) { // looks like we timed out - this._host.logInfo(`Extension host with pid ${pid} did not exit within ${maxWaitTimeMs}ms.`); + this._logService.info(`Extension host with pid ${pid} did not exit within ${maxWaitTimeMs}ms.`); this._process.kill(); } } } - -export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter { - _serviceBrand: undefined; - - private static _lastId: number = 0; - - protected readonly _extHosts: Map<string, ExtensionHostProcess>; - - constructor( - private readonly _host: IExtensionHostStarterWorkerHost - ) { - this._extHosts = new Map<string, ExtensionHostProcess>(); - } - - dispose(): void { - // Intentionally not killing the extension host processes - } - - private _getExtHost(id: string): ExtensionHostProcess { - const extHostProcess = this._extHosts.get(id); - if (!extHostProcess) { - throw new Error(`Unknown extension host!`); - } - return extHostProcess; - } - - onDynamicStdout(id: string): Event<string> { - return this._getExtHost(id).onStdout; - } - - onDynamicStderr(id: string): Event<string> { - return this._getExtHost(id).onStderr; - } - - onDynamicMessage(id: string): Event<any> { - return this._getExtHost(id).onMessage; - } - - onDynamicError(id: string): Event<{ error: SerializedError }> { - return this._getExtHost(id).onError; - } - - onDynamicExit(id: string): Event<{ code: number; signal: string }> { - return this._getExtHost(id).onExit; - } - - async createExtensionHost(): Promise<{ id: string }> { - const id = String(++ExtensionHostStarter._lastId); - const extHost = new ExtensionHostProcess(id, this._host); - this._extHosts.set(id, extHost); - extHost.onExit(({ pid, code, signal }) => { - this._host.logInfo(`Extension host with pid ${pid} exited with code: ${code}, signal: ${signal}.`); - setTimeout(() => { - extHost.dispose(); - this._extHosts.delete(id); - }); - }); - return { id }; - } - - async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number }> { - return this._getExtHost(id).start(opts); - } - - async enableInspectPort(id: string): Promise<boolean> { - const extHostProcess = this._extHosts.get(id); - if (!extHostProcess) { - return false; - } - return extHostProcess.enableInspectPort(); - } - - async kill(id: string): Promise<void> { - const extHostProcess = this._extHosts.get(id); - if (!extHostProcess) { - // already gone! - return; - } - extHostProcess.kill(); - } - - async killAllNow(): Promise<void> { - for (const [, extHost] of this._extHosts) { - extHost.kill(); - } - } - - async waitForAllExit(maxWaitTimeMs: number): Promise<void> { - const exitPromises: Promise<void>[] = []; - for (const [, extHost] of this._extHosts) { - exitPromises.push(extHost.waitForExit(maxWaitTimeMs)); - } - return Promises.settled(exitPromises).then(() => { }); - } -} - -/** - * The `create` function needs to be there by convention because - * we are loaded via the `vs/base/common/worker/simpleWorker` utility. - */ -export function create(host: IExtensionHostStarterWorkerHost) { - return new ExtensionHostStarter(host); -} diff --git a/src/vs/platform/extensions/electron-main/workerMainProcessExtensionHostStarter.ts b/src/vs/platform/extensions/electron-main/workerMainProcessExtensionHostStarter.ts deleted file mode 100644 index f78d3e2db1f..00000000000 --- a/src/vs/platform/extensions/electron-main/workerMainProcessExtensionHostStarter.ts +++ /dev/null @@ -1,173 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { canceled, SerializedError } from 'vs/base/common/errors'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform/extensions/common/extensionHostStarter'; -import { Event } from 'vs/base/common/event'; -import { FileAccess } from 'vs/base/common/network'; -import { ILogService } from 'vs/platform/log/common/log'; -import { Worker } from 'worker_threads'; -import { IWorker, IWorkerCallback, IWorkerFactory, SimpleWorkerClient } from 'vs/base/common/worker/simpleWorker'; -import type { ExtensionHostStarter, IExtensionHostStarterWorkerHost } from 'vs/platform/extensions/node/extensionHostStarterWorker'; -import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; -import { StopWatch } from 'vs/base/common/stopwatch'; - -class NodeWorker implements IWorker { - - private readonly _worker: Worker; - - public readonly onError: Event<Error>; - public readonly onExit: Event<number>; - public readonly onMessageError: Event<Error>; - - constructor(callback: IWorkerCallback, onErrorCallback: (err: any) => void) { - this._worker = new Worker( - FileAccess.asFileUri('vs/platform/extensions/node/extensionHostStarterWorkerMain.js', require).fsPath, - ); - this._worker.on('message', callback); - this._worker.on('error', onErrorCallback); - this.onError = Event.fromNodeEventEmitter(this._worker, 'error'); - this.onExit = Event.fromNodeEventEmitter(this._worker, 'exit'); - this.onMessageError = Event.fromNodeEventEmitter(this._worker, 'messageerror'); - } - - getId(): number { - return 1; - } - - postMessage(message: any, transfer: ArrayBuffer[]): void { - this._worker.postMessage(message, transfer); - } - - dispose(): void { - this._worker.terminate(); - } -} - -class ExtensionHostStarterWorkerHost implements IExtensionHostStarterWorkerHost { - constructor( - @ILogService private readonly _logService: ILogService - ) { } - - public async logInfo(message: string): Promise<void> { - this._logService.info(message); - } -} - -export class WorkerMainProcessExtensionHostStarter implements IDisposable, IExtensionHostStarter { - _serviceBrand: undefined; - - private _proxy: ExtensionHostStarter | null; - private readonly _worker: SimpleWorkerClient<ExtensionHostStarter, IExtensionHostStarterWorkerHost>; - private _shutdown = false; - - constructor( - @ILogService private readonly _logService: ILogService, - @ILifecycleMainService lifecycleMainService: ILifecycleMainService - ) { - this._proxy = null; - - const workerFactory: IWorkerFactory = { - create: (moduleId: string, callback: IWorkerCallback, onErrorCallback: (err: any) => void): IWorker => { - const worker = new NodeWorker(callback, onErrorCallback); - worker.onError((err) => { - this._logService.error(`ExtensionHostStarterWorker has encountered an error:`); - this._logService.error(err); - }); - worker.onMessageError((err) => { - this._logService.error(`ExtensionHostStarterWorker has encountered a message error:`); - this._logService.error(err); - }); - worker.onExit((exitCode) => this._logService.info(`ExtensionHostStarterWorker exited with code ${exitCode}.`)); - worker.postMessage(moduleId, []); - return worker; - } - }; - this._worker = new SimpleWorkerClient<ExtensionHostStarter, IExtensionHostStarterWorkerHost>( - workerFactory, - 'vs/platform/extensions/node/extensionHostStarterWorker', - new ExtensionHostStarterWorkerHost(this._logService) - ); - this._initialize(); - - // On shutdown: gracefully await extension host shutdowns - lifecycleMainService.onWillShutdown((e) => { - this._shutdown = true; - if (this._proxy) { - e.join(this._proxy.waitForAllExit(6000)); - } - }); - } - - dispose(): void { - // Intentionally not killing the extension host processes - } - - async _initialize(): Promise<void> { - this._proxy = await this._worker.getProxyObject(); - this._logService.info(`ExtensionHostStarterWorker created`); - } - - onDynamicStdout(id: string): Event<string> { - return this._proxy!.onDynamicStdout(id); - } - - onDynamicStderr(id: string): Event<string> { - return this._proxy!.onDynamicStderr(id); - } - - onDynamicMessage(id: string): Event<any> { - return this._proxy!.onDynamicMessage(id); - } - - onDynamicError(id: string): Event<{ error: SerializedError }> { - return this._proxy!.onDynamicError(id); - } - - onDynamicExit(id: string): Event<{ code: number; signal: string }> { - return this._proxy!.onDynamicExit(id); - } - - async createExtensionHost(): Promise<{ id: string }> { - const proxy = await this._worker.getProxyObject(); - if (this._shutdown) { - throw canceled(); - } - return proxy.createExtensionHost(); - } - - async start(id: string, opts: IExtensionHostProcessOptions): Promise<{ pid: number }> { - const sw = StopWatch.create(false); - const proxy = await this._worker.getProxyObject(); - if (this._shutdown) { - throw canceled(); - } - const timeout = setTimeout(() => { - this._logService.info(`ExtensionHostStarterWorker.start() did not return within 30s. This might be a problem.`); - }, 30000); - const result = await proxy.start(id, opts); - const duration = sw.elapsed(); - this._logService.info(`ExtensionHostStarterWorker.start() took ${duration} ms.`); - clearTimeout(timeout); - return result; - } - - async enableInspectPort(id: string): Promise<boolean> { - const proxy = await this._worker.getProxyObject(); - if (this._shutdown) { - throw canceled(); - } - return proxy.enableInspectPort(id); - } - - async kill(id: string): Promise<void> { - const proxy = await this._worker.getProxyObject(); - if (this._shutdown) { - throw canceled(); - } - return proxy.kill(id); - } -} diff --git a/src/vs/platform/extensions/node/extensionHostStarterWorkerMain.ts b/src/vs/platform/extensions/node/extensionHostStarterWorkerMain.ts deleted file mode 100644 index b4efa0c798f..00000000000 --- a/src/vs/platform/extensions/node/extensionHostStarterWorkerMain.ts +++ /dev/null @@ -1,66 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -(function () { - 'use strict'; - - const loader = require('../../../loader'); - const bootstrap = require('../../../../bootstrap'); - const path = require('path'); - const parentPort = require('worker_threads').parentPort; - - // Bootstrap: NLS - const nlsConfig = bootstrap.setupNLS(); - - // Bootstrap: Loader - loader.config({ - baseUrl: bootstrap.fileUriFromPath(path.join(__dirname, '../../../../'), { isWindows: process.platform === 'win32' }), - catchError: true, - nodeRequire: require, - nodeMain: __filename, - 'vs/nls': nlsConfig, - amdModulesPattern: /^vs\//, - recordStats: true - }); - - let isFirstMessage = true; - let beforeReadyMessages: any[] = []; - - const initialMessageHandler = (data: any) => { - if (!isFirstMessage) { - beforeReadyMessages.push(data); - return; - } - - isFirstMessage = false; - loadCode(data); - }; - - parentPort.on('message', initialMessageHandler); - - const loadCode = function (moduleId: string) { - loader([moduleId], function (ws: any) { - setTimeout(() => { - - const messageHandler = ws.create((msg: any, transfer?: ArrayBuffer[]) => { - parentPort.postMessage(msg, transfer); - }, null); - parentPort.off('message', initialMessageHandler); - parentPort.on('message', (data: any) => { - messageHandler.onmessage(data); - }); - while (beforeReadyMessages.length > 0) { - const msg = beforeReadyMessages.shift()!; - messageHandler.onmessage(msg); - } - - }); - }, (err: any) => console.error(err)); - }; - - parentPort.on('messageerror', (err: Error) => { - console.error(err); - }); -})(); diff --git a/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts index 6655be6e360..a7911a49048 100644 --- a/src/vs/platform/theme/test/common/testThemeService.ts +++ b/src/vs/platform/theme/test/common/testThemeService.ts @@ -14,7 +14,7 @@ export class TestColorTheme implements IColorTheme { public readonly label = 'test'; constructor( - private colors: { [id: string]: string } = {}, + private colors: { [id: string]: string | undefined } = {}, public type = ColorScheme.DARK, public readonly semanticHighlighting = false ) { } diff --git a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts index a0c161312fb..3da845d011a 100644 --- a/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts +++ b/src/vs/platform/webview/electron-main/webviewProtocolProvider.ts @@ -14,7 +14,6 @@ export class WebviewProtocolProvider extends Disposable { private static validWebviewFilePaths = new Map([ ['/index.html', 'index.html'], ['/fake.html', 'fake.html'], - ['/main.js', 'main.js'], ['/service-worker.js', 'service-worker.js'], ]); diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index 9036d7a754a..7bb7cee0895 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -89,9 +89,14 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { const disposables = new DisposableStore(); - const webview = this._webviewService.createWebviewElement('mainThreadCodeInsets_' + handle, { - enableFindWidget: false, - }, reviveWebviewContentOptions(options), { id: extensionId, location: URI.revive(extensionLocation) }); + const webview = this._webviewService.createWebviewElement({ + id: 'mainThreadCodeInsets_' + handle, + options: { + enableFindWidget: false, + }, + contentOptions: reviveWebviewContentOptions(options), + extension: { id: extensionId, location: URI.revive(extensionLocation) } + }); const webviewZone = new EditorWebviewZone(editor, line, height, webview); diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 6f247115e34..3be47943f1a 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -662,6 +662,7 @@ class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustom } : undefined, webview: { id: primaryEditor.id, + origin: primaryEditor.webview.origin, options: primaryEditor.webview.options, state: primaryEditor.webview.state, } diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index 6659298ef14..5737029a6a4 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -165,7 +165,13 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc const extension = reviveWebviewExtension(extensionData); - const webview = this._webviewWorkbenchService.createWebview(handle, this.webviewPanelViewType.fromExternal(viewType), initData.title, mainThreadShowOptions, reviveWebviewOptions(initData.panelOptions), reviveWebviewContentOptions(initData.webviewOptions), extension); + const webview = this._webviewWorkbenchService.createWebview({ + id: handle, + options: reviveWebviewOptions(initData.panelOptions), + contentOptions: reviveWebviewContentOptions(initData.webviewOptions), + extension + }, this.webviewPanelViewType.fromExternal(viewType), initData.title, mainThreadShowOptions); + this.addWebviewInput(handle, webview, { serializeBuffersForPostMessage: initData.serializeBuffersForPostMessage }); const payload = { diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 35b374ece47..8b516b544a7 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -42,7 +42,7 @@ .monaco-workbench.windows .part.titlebar>.titlebar-container, .monaco-workbench.linux .part.titlebar>.titlebar-container { height: 30px; - line-height: 30px; + line-height: 22px; justify-content: left; } diff --git a/src/vs/workbench/browser/parts/titlebar/titleMenuControl.ts b/src/vs/workbench/browser/parts/titlebar/titleMenuControl.ts index a68616a47d8..77e1ebb32eb 100644 --- a/src/vs/workbench/browser/parts/titlebar/titleMenuControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/titleMenuControl.ts @@ -95,7 +95,19 @@ export class TitleMenuControl { } private _updateFromWindowTitle() { - this.workspaceTitle.innerText = windowTitle.workspaceName; + + // label: just workspace name and optional decorations + const { prefix, suffix } = windowTitle.getTitleDecorations(); + let label = windowTitle.workspaceName; + if (prefix) { + label = localize('label1', "{0} {1}", prefix, label); + } + if (suffix) { + label = localize('label2', "{0} {1}", label, suffix); + } + this.workspaceTitle.innerText = label; + + // tooltip: full windowTitle const kb = keybindingService.lookupKeybinding(action.id)?.getLabel(); const title = kb ? localize('title', "Search {0} ({1}) \u2014 {2}", windowTitle.workspaceName, kb, windowTitle.value) diff --git a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts index cdae94ad277..1920790f520 100644 --- a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts +++ b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts @@ -108,28 +108,41 @@ export class WindowTitle extends Disposable { } private getWindowTitle(): string { - let title = this.doGetWindowTitle(); + let title = this.doGetWindowTitle() || this.productService.nameLong; + let { prefix, suffix } = this.getTitleDecorations(); + if (prefix) { + title = `${prefix} ${title}`; + } + if (suffix) { + title = `${title} ${suffix}`; + } + // Replace non-space whitespace + title = title.replace(/[^\S ]/g, ' '); + return title; + } + + getTitleDecorations() { + let prefix: string | undefined; + let suffix: string | undefined; if (this.properties.prefix) { - title = `${this.properties.prefix} ${title || this.productService.nameLong}`; + prefix = this.properties.prefix; + } + if (this.environmentService.isExtensionDevelopment) { + prefix = !prefix + ? WindowTitle.NLS_EXTENSION_HOST + : `${WindowTitle.NLS_EXTENSION_HOST} - ${prefix}`; } if (this.properties.isAdmin) { - title = `${title || this.productService.nameLong} ${WindowTitle.NLS_USER_IS_ADMIN}`; + suffix = WindowTitle.NLS_USER_IS_ADMIN; } - if (!this.properties.isPure) { - title = `${title || this.productService.nameLong} ${WindowTitle.NLS_UNSUPPORTED}`; + suffix = !suffix + ? WindowTitle.NLS_UNSUPPORTED + : `${suffix} ${WindowTitle.NLS_UNSUPPORTED}`; } - - if (this.environmentService.isExtensionDevelopment) { - title = `${WindowTitle.NLS_EXTENSION_HOST} - ${title || this.productService.nameLong}`; - } - - // Replace non-space whitespace - title = title.replace(/[^\S ]/g, ' '); - - return title; + return { prefix, suffix }; } updateProperties(properties: ITitleProperties): void { diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index bf7c818fb94..7258b951aff 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground, listActiveSelectionBackground, listActiveSelectionForeground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, editorBackground, contrastBorder, transparent, editorWidgetBackground, textLinkForeground, lighten, darken, focusBorder, activeContrastBorder, editorWidgetForeground, editorErrorForeground, editorWarningForeground, editorInfoForeground, treeIndentGuidesStroke, errorForeground, listActiveSelectionBackground, listActiveSelectionForeground, editorForeground, toolbarHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; import { ColorScheme } from 'vs/platform/theme/common/theme'; @@ -763,8 +763,8 @@ export const MENUBAR_SELECTION_FOREGROUND = registerColor('menubar.selectionFore }, localize('menubarSelectionForeground', "Foreground color of the selected menu item in the menubar.")); export const MENUBAR_SELECTION_BACKGROUND = registerColor('menubar.selectionBackground', { - dark: transparent(Color.white, 0.1), - light: transparent(Color.black, 0.1), + dark: toolbarHoverBackground, + light: toolbarHoverBackground, hcDark: null, hcLight: null, }, localize('menubarSelectionBackground', "Background color of the selected menu item in the menubar.")); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index 81dfae861af..e275174e00a 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -38,7 +38,12 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { const untitledString = accessor.get(IUntitledTextEditorService).getValue(resource); let untitledDocumentData = untitledString ? VSBuffer.fromString(untitledString) : undefined; const id = generateUuid(); - const webview = accessor.get(IWebviewService).createWebviewOverlay(id, { customClasses: options?.customClasses }, {}, undefined); + const webview = accessor.get(IWebviewService).createWebviewOverlay({ + id, + options: { customClasses: options?.customClasses }, + contentOptions: {}, + extension: undefined, + }); const input = instantiationService.createInstance(CustomEditorInput, resource, viewType, id, webview, { untitledDocumentData: untitledDocumentData, oldResource: options?.oldResource }); if (typeof group !== 'undefined') { input.updateGroup(group); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index 3304e1334a0..a1670e79b80 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -32,6 +32,7 @@ export interface CustomDocumentBackupData extends IWorkingCopyBackupMeta { readonly webview: { readonly id: string; + readonly origin: string | undefined; readonly options: SerializedWebviewOptions; readonly state: any; }; @@ -107,12 +108,18 @@ export class CustomEditorInputSerializer extends WebviewEditorInputSerializer { } } -function reviveWebview(webviewService: IWebviewService, data: { id: string; state: any; webviewOptions: WebviewOptions; contentOptions: WebviewContentOptions; extension?: WebviewExtensionDescription }) { - const webview = webviewService.createWebviewOverlay(data.id, { - purpose: WebviewContentPurpose.CustomEditor, - enableFindWidget: data.webviewOptions.enableFindWidget, - retainContextWhenHidden: data.webviewOptions.retainContextWhenHidden - }, data.contentOptions, data.extension); +function reviveWebview(webviewService: IWebviewService, data: { id: string; origin: string | undefined; state: any; webviewOptions: WebviewOptions; contentOptions: WebviewContentOptions; extension?: WebviewExtensionDescription }) { + const webview = webviewService.createWebviewOverlay({ + id: data.id, + origin: data.origin, + options: { + purpose: WebviewContentPurpose.CustomEditor, + enableFindWidget: data.webviewOptions.enableFindWidget, + retainContextWhenHidden: data.webviewOptions.retainContextWhenHidden + }, + contentOptions: data.contentOptions, + extension: data.extension, + }); webview.state = data.state; return webview; } @@ -180,6 +187,7 @@ export class ComplexCustomWorkingCopyEditorHandler extends Disposable implements const extension = reviveWebviewExtensionDescription(backupData.extension?.id, backupData.extension?.location); const webview = reviveWebview(this._webviewService, { id, + origin: backupData.webview.origin, webviewOptions: restoreWebviewOptions(backupData.webview.options), contentOptions: restoreWebviewContentOptions(backupData.webview.options), state: backupData.webview.state, diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index c061b736c55..36390d28f6a 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -71,8 +71,7 @@ /* Expressions */ -.monaco-workbench .debug-pane .monaco-list-row .expression, -.monaco-workbench .debug-hover-widget .monaco-list-row .expression { +.monaco-workbench .monaco-list-row .expression { display: flex; } diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index d28e388e474..38c3431d3b3 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -23,6 +23,10 @@ line-height: var(--vscode-repl-line-height); } +.monaco-workbench .repl .repl-tree .monaco-tl-contents .expression .lazy-button { + cursor: pointer; +} + .monaco-workbench .repl .repl-tree .monaco-tl-twistie { background-position-y: calc(100% - (var(--vscode-repl-font-size-for-twistie))); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 2f1244e6ebd..4cfe2517ef5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -658,7 +658,7 @@ export class ExtensionEditor extends EditorPane { } }; reset(template.recommendation); - if (extension.deprecated || extension.state === ExtensionState.Installed) { + if (extension.deprecationInfo || extension.state === ExtensionState.Installed) { return; } updateRecommendationText(false); @@ -744,10 +744,15 @@ export class ExtensionEditor extends EditorPane { return Promise.resolve(null); } - const webview = this.contentDisposables.add(this.webviewService.createWebviewOverlay(generateUuid(), { - enableFindWidget: true, - tryRestoreScrollPosition: true, - }, {}, undefined)); + const webview = this.contentDisposables.add(this.webviewService.createWebviewOverlay({ + id: generateUuid(), + options: { + enableFindWidget: true, + tryRestoreScrollPosition: true, + }, + contentOptions: {}, + extension: undefined, + })); webview.initialScrollProgress = this.initialScrollProgress.get(webviewIndex) || 0; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index d3b1573086e..e578b8359cb 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -64,7 +64,6 @@ import { escapeMarkdownSyntaxTokens, IMarkdownString, MarkdownString } from 'vs/ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { ViewContainerLocation } from 'vs/workbench/common/views'; import { flatten } from 'vs/base/common/arrays'; -import { isBoolean } from 'vs/base/common/types'; import { fromNow } from 'vs/base/common/date'; export class PromptExtensionInstallFailureAction extends Action { @@ -104,7 +103,7 @@ export class PromptExtensionInstallFailureAction extends Action { return; } - if ([ExtensionManagementErrorCode.Incompatible, ExtensionManagementErrorCode.IncompatibleTargetPlatform, ExtensionManagementErrorCode.Malicious, ExtensionManagementErrorCode.ReleaseVersionNotFound, ExtensionManagementErrorCode.UnsupportedPreRelease].includes(<ExtensionManagementErrorCode>this.error.name)) { + if ([ExtensionManagementErrorCode.Incompatible, ExtensionManagementErrorCode.IncompatibleTargetPlatform, ExtensionManagementErrorCode.Malicious, ExtensionManagementErrorCode.ReleaseVersionNotFound, ExtensionManagementErrorCode.Deprecated].includes(<ExtensionManagementErrorCode>this.error.name)) { await this.dialogService.show(Severity.Info, getErrorMessage(this.error)); return; } @@ -276,11 +275,11 @@ export abstract class AbstractInstallAction extends ExtensionAction { return; } - if (this.extension.deprecated && isBoolean(this.extension.deprecated)) { + if (this.extension.deprecationInfo) { const result = await this.dialogService.confirm({ type: 'warning', - title: localize('install confirmation', "Are you sure you want to install '{0}'?", this.extension.displayName), - message: localize('deprecated message', "This extension is no longer being maintained and is deprecated."), + message: localize('install confirmation', "Are you sure you want to install '{0}'?", this.extension.displayName), + detail: localize('deprecated message', "This extension is no longer being maintained and is deprecated."), primaryButton: localize('install anyway', "Install Anyway"), }); if (!result.confirmed) { @@ -2172,14 +2171,15 @@ export class ExtensionStatusAction extends ExtensionAction { return; } - if (this.extension.deprecated) { - if (isBoolean(this.extension.deprecated)) { - this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('unsupported tooltip', "This extension is no longer being maintained and is deprecated.")) }, true); + if (this.extension.deprecationInfo) { + if (this.extension.deprecationInfo.extension) { + const link = `[${this.extension.deprecationInfo.extension.displayName}](${URI.parse(`command:extension.open?${encodeURIComponent(JSON.stringify([this.extension.deprecationInfo.extension.id]))}`)})`; + this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('deprecated with alternate extension tooltip', "This extension has been deprecated. Use {0} extension instead.", link)) }, true); + } else if (this.extension.deprecationInfo.settings) { + const link = `[${localize('settings', "settings")}](${URI.parse(`command:workbench.action.openSettings?${encodeURIComponent(JSON.stringify([this.extension.deprecationInfo.settings.map(setting => `@id:${setting}`).join(' ')]))}`)})`; + this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('deprecated with alternate settings tooltip', "This extension is deprecated and has become a native feature in VS Code. Configure these {0} instead.", link)) }, true); } else { - const link = `[${this.extension.deprecated.displayName}](${URI.parse(`command:extension.open?${encodeURIComponent(JSON.stringify([this.extension.deprecated.id]))}`)})`; - if (this.extension.state !== ExtensionState.Installed) { - this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('unsupported prerelease switch tooltip', "This extension has been deprecated. Use {0} instead.", link)) }, true); - } + this.updateStatus({ icon: warningIcon, message: new MarkdownString(localize('deprecated tooltip', "This extension is no longer being maintained and is deprecated.")) }, true); } return; } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 4755c672581..9b5c1397ee4 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -188,7 +188,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> { const updateEnablement = async () => { let isDisabled = false; if (extension.state === ExtensionState.Uninstalled) { - isDisabled = !!extension.deprecated || !(await this.extensionsWorkbenchService.canInstall(extension)); + isDisabled = !!extension.deprecationInfo || !(await this.extensionsWorkbenchService.canInstall(extension)); } else if (extension.local && !isLanguagePackExtension(extension.local.manifest)) { const runningExtensions = await this.extensionService.getExtensions(); const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier))[0]; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts index e4592383fe6..1760db32044 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWidgets.ts @@ -185,7 +185,7 @@ export class RecommendationWidget extends ExtensionWidget { render(): void { this.clear(); - if (!this.extension || this.extension.state === ExtensionState.Installed || this.extension.deprecated) { + if (!this.extension || this.extension.state === ExtensionState.Installed || this.extension.deprecationInfo) { return; } const extRecommendations = this.extensionRecommendationsService.getAllRecommendationsWithReason(); @@ -549,7 +549,7 @@ export class ExtensionHoverWidget extends ExtensionWidget { if (extension.state === ExtensionState.Installed) { return undefined; } - if (extension.deprecated) { + if (extension.deprecationInfo) { return undefined; } const recommendation = this.extensionRecommendationsService.getAllRecommendationsWithReason()[extension.identifier.id.toLowerCase()]; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 7fda957ef46..ece35b058d1 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -15,7 +15,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, InstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier, InstallOperation, InstallOptions, WEB_EXTENSION_TAG, InstallExtensionResult, - IExtensionsControlManifest, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions + IExtensionsControlManifest, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService, DefaultIconPath } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, groupByExtension, ExtensionKey, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -198,7 +198,7 @@ export class Extension implements IExtension { } public isMalicious: boolean = false; - public deprecated: boolean | { id: string; displayName: string } = false; + public deprecationInfo: IDeprecationInfo | undefined; get installCount(): number | undefined { return this.gallery ? this.gallery.installCount : undefined; @@ -399,10 +399,8 @@ ${this.description} class Extensions extends Disposable { static updateExtensionFromControlManifest(extension: Extension, extensionsControlManifest: IExtensionsControlManifest): void { - const isMalicious = extensionsControlManifest.malicious.some(identifier => areSameExtensions(extension.identifier, identifier)); - extension.isMalicious = isMalicious; - const deprecated = extensionsControlManifest.deprecated ? extensionsControlManifest.deprecated[extension.identifier.id.toLowerCase()] : undefined; - extension.deprecated = deprecated ?? false; + extension.isMalicious = extensionsControlManifest.malicious.some(identifier => areSameExtensions(extension.identifier, identifier)); + extension.deprecationInfo = extensionsControlManifest.deprecated ? extensionsControlManifest.deprecated[extension.identifier.id.toLowerCase()] : undefined; } private readonly _onChange: Emitter<{ extension: Extension; operation?: InstallOperation } | undefined> = this._register(new Emitter<{ extension: Extension; operation?: InstallOperation } | undefined>()); @@ -1166,7 +1164,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return false; } - if (extension.deprecated && !isBoolean(extension.deprecated)) { + if (extension.deprecationInfo?.disallowInstall) { return false; } diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 23744cd4f9b..47be2a6e355 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -6,7 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { IPager } from 'vs/base/common/paging'; -import { IQueryOptions, ILocalExtension, IGalleryExtension, IExtensionIdentifier, InstallOptions, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IQueryOptions, ILocalExtension, IGalleryExtension, IExtensionIdentifier, InstallOptions, InstallVSIXOptions, IExtensionInfo, IExtensionQueryOptions, IDeprecationInfo } from 'vs/platform/extensionManagement/common/extensionManagement'; import { EnablementState, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -78,7 +78,7 @@ export interface IExtension { readonly local?: ILocalExtension; gallery?: IGalleryExtension; readonly isMalicious: boolean; - readonly deprecated: boolean | { id: string; displayName: string }; + readonly deprecationInfo?: IDeprecationInfo; } export const SERVICE_ID = 'extensionsWorkbenchService'; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts index 54ddc028ea9..add1a477c3f 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionRecommendationsService.test.ts @@ -218,7 +218,7 @@ suite('ExtensionRecommendationsService Test', () => { onDidUninstallExtension: didUninstallEvent.event, async getInstalled() { return []; }, async canInstall() { return true; }, - async getExtensionsControlManifest() { return { malicious: [] }; }, + async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getTargetPlatform() { return getTargetPlatform(platform, arch); } }); instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{ diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 7e5b0d2a156..93b1ba0e871 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -100,7 +100,7 @@ async function setupTest() { onUninstallExtension: uninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event, async getInstalled() { return []; }, - async getExtensionsControlManifest() { return { malicious: [] }; }, + async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) { local.identifier.uuid = metadata.id; local.publisherDisplayName = metadata.publisherDisplayName; @@ -2424,7 +2424,7 @@ function createExtensionManagementService(installed: ILocalExtension[] = []): IE return local; }, async getTargetPlatform() { return getTargetPlatform(platform, arch); }, - async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [] }; }, + async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {} }; }, }; } diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 39f0b2ca026..1212a0ed3b2 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -98,7 +98,7 @@ suite('ExtensionsListView Tests', () => { onDidUninstallExtension: didUninstallEvent.event, async getInstalled() { return []; }, async canInstall() { return true; }, - async getExtensionsControlManifest() { return { malicious: [] }; }, + async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async getTargetPlatform() { return getTargetPlatform(platform, arch); } }); instantiationService.stub(IRemoteAgentService, RemoteAgentService); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 09723bab668..0c7d5816688 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -95,7 +95,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { onUninstallExtension: uninstallEvent.event, onDidUninstallExtension: didUninstallEvent.event, async getInstalled() { return []; }, - async getExtensionsControlManifest() { return { malicious: [] }; }, + async getExtensionsControlManifest() { return { malicious: [], deprecated: {} }; }, async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata) { local.identifier.uuid = metadata.id; local.publisherDisplayName = metadata.publisherDisplayName; @@ -1489,7 +1489,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { return local; }, getTargetPlatform: async () => getTargetPlatform(platform, arch), - async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [] }; }, + async getExtensionsControlManifest() { return <IExtensionsControlManifest>{ malicious: [], deprecated: {} }; }, }; } }); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts b/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts index 81fd6185e59..212b41dbdb5 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/viewportCustomMarkdown/viewportCustomMarkdown.ts @@ -70,7 +70,7 @@ class NotebookViewportContribution extends Disposable implements INotebookEditor return; } - const visibleRanges = this._notebookEditor.getVisibleRangesPlusViewportBelow(); + const visibleRanges = this._notebookEditor.getVisibleRangesPlusViewportAboveAndBelow(); cellRangesToIndexes(visibleRanges).forEach(index => { const cell = this._notebookEditor.cellAt(index); diff --git a/src/vs/workbench/contrib/notebook/browser/docs/cell-resize-above-viewport.drawio.svg b/src/vs/workbench/contrib/notebook/browser/docs/cell-resize-above-viewport.drawio.svg index 909b8665213..6a2f80fc98d 100644 --- a/src/vs/workbench/contrib/notebook/browser/docs/cell-resize-above-viewport.drawio.svg +++ b/src/vs/workbench/contrib/notebook/browser/docs/cell-resize-above-viewport.drawio.svg @@ -1,42 +1,42 @@ -<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="2362px" height="1022px" viewBox="-0.5 -0.5 2362 1022" content="<mxfile><diagram id="b1th27OaiNIVZPbSBiyb" name="Page-1">7V1bk5s2FP41nj41gxA3P+4l3T40ncwkbZJHDFqbBlsewGtvfn0lI2yQ5Fi7EWKN/LIL4mLrOzq3T0fyBN4tdw9FvF58wCnKJ66T7ibwfuK6YBp45B9teWYtjgPrlnmRpazt2PAp+4GaG1nrJktR2bmxwjivsnW3McGrFUqqTltcFHjbve0R591PXcdzJDR8SuJcbP2SpdWibo1859j+J8rmi+aTSQfrK8u4uZk1lIs4xdtWE3w/gXcFxlV9tNzdoZyi1+BSP/fHiauHL1agVaXygDutn3iK8w3rHPti1XPTW/Id1/QQ7cgrb1O8me2vAHJS4M0qRfRdDjnbLrIKfVrHCb28JbInbYtqmbObH7M8v8M5LvavhamPotQj7WVV4O+odSVyZzAIyBWxN6yDT6io0K7VxHr3gPASVcUzuYVd9YBfP8LG2pQBvz3KDUSsbdGSmdeILGZjZX549RFOcsAQlaPrB+fRRSkZWux0hVeoi9lJBEq8KRL2Co/pE33VTzEpUB5X2VN3FMs6yB79iDPysQcsoeu+i/wQeG79Nwg60EKPg6yKizmq2Es41A7fSgnIwLkCqQdIcAVSD5DuFUgtQDY9/BmQRzcDzruZ2p00ftlljudLY9upx1nEyWJToAf66H10bLhZzfcf6fmiuwKzGCD6tvI7qpLFOSG+wEO5XQ8ldVGB1EX9uocCCvbgov3/74ALAAAwGQEoDO7LhtcfFF6F+GrUtuN33+GMhwz+voyHpxCVjRt+wMEPXYPwQwH9v3GFZhh/J61/ZSV17/9maCvIpKpNTQv4OM/mK3KcECwQQe2WYpCRhPeGXVhmaUofvy1Qmf2IaxNFjdKahgD7Tvi3E/+evmtT4bJO2YFgflgYpAP7AHKWJ5Bg70qwd3VkdgL2X9DsaQ82eXsQL+nIXs1K+q/Ca9JKxkpj8UYnCt4JyCKYviSh4mI1BOJh3VTHveyTmQLqi82VozbR8FJFX+OiGukIC7kRBqE4xGR2VscIAwqpnl1uzmiUAUQ/J8CvK4bWAZbL+yWJNXQd2ViNdKAlmkOrogIBfZNRAQhttxQub6dNkhmu9fkID78bKsIf6ID/BVzSNn7e2wgeBGYigsaGoOL9E6pNCZDalVPQ8hapwFVctS0UKjLSQ2rWmH37eGy5LVfx+jOu6U3ejegcGH1YPJnMvb407gW++SpyfSL3BhS5yLk9FJjmvWzK23Vm9Lv6Y012YROm/czGgr6yXTHCKJMC5/nnPckwYo4hdLuwy8LqaV+oR7aiDnl63yDq0PZwjp8ZlIHfH7usUBk0avSFuRWz5L7BiVkNYLlTbqhKnGJ/pAcUGTqbSA8BfE8yUPviPKDt9Ru8i4SqObcWMyFORNmNvusroq+D8YAK9QfX9Fd3+subO5nI+8p+oQLDe5W4dolHA0r8XO43VqLDdc6HdL0l3Opa9gaCX7EURXnKT4cXsn7SKXjtrIcO+yCaB8vRNxr/egrx70UX2EbegOuXPNvrayN/QArIs92w8+gb5T89BcP+hmKQkOeKjRJwnkgW20TACeCbJOB8BaZ41GYi9AYMQHyFVMUq9I0ScP61/mQAOoY3dybpGP8FK+quEtcmcQWWvTeJiymeHQScwCoZJOAClVU1q/SGbqZCUc3jssySLuSk58Xz1/bJNwrpO785vd8xiOuzZ3Z2EjrZwvj2gpwmXT27IKcFoC8BsGn7xTX1QcDFJbzHq/sjLKIXXiQsfgHcizRuayAq203632Yfv+/XsY1S0Xh8HVHRwr4UTSHJP6tou6z62jr+1qgVOT7qGD1pVOygms47x/G76ulN4RkF3Z+1PJm61jZredpa20ywvBGt9Tmt9XhlU9VaYeMBPtHWqLUiV/HPOo1JmnF0lGNUXL7upcGhnXpIOQ8NijvQxlkMvDQuF4dAkZ58jCsitdW+hQRFAugTatWCQNu+DyHPjMooj6lMT3XwTYGIvs3rr3lTY3L9deMYr6KovUVXEjIqqjdJiESgxZLgJ85MSgI4BicPhpmW5CpyAqPzksCxvTg9mvIW3yDnDST7T9gNf2h2z7bLWhsQchlVKCEPe9wQQbJ9h1Vzkzz6shKG3hyhyuYdo7YUIecop6rTY3oshe2LM3j4I8m+Qb3NTh7SsutkldHJquC8zPuarALguiRkCJH7Q4r83Jr80U5QhucDu74mKMFrtmCcjlUSUQNzk47Looy+9qQAKtvwXjTbAaA7KN1h/RIPAOGQfIf1izwE/EOTNZbA5GSbDrT4pXOGGQ/Jxik2MR4i/EYpD5WdO8ZtLFx3SM5DshmI5fibJT3gtSZ7gAxYMHpGU2CVTWCuMtcuczAdUua21mUDvtzGKO8h2XPGXt4DHH4HYBDiQ2U3mFcV79Y18ifLd08i16m1bbr9Rgpr+XL48LXl8MCLTsy+66+sBZJtEMdfEA8cvr4hEtWqr4r4w+JZLWtPDvXq39onJwrbuYjiMUpQksjIxVnke76yJjZItaveDyVib0U7OZ/m8zqlqp28mvv9/XQkaAaGpUXYAb83iITnmMryPC0sk2QlJhDQJ89k6xKdhzcu1/UvdT9mO4rpq4l+AT4JyKcrqfmlVkDCM/fGHElWOkos34UhKvwgi1FExWAZXjqiwqoXo4CKMyHepQMq7N5hFFAxvvR+u3hE4fnp0t4QlfzEuX/pgAIQGkOUnBYYV+2ojKCy+IBTRO/4Hw==</diagram></mxfile>"> +<svg host="65bd71144e" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="2361px" height="1021px" viewBox="-0.5 -0.5 2361 1021" content="<mxfile><diagram id="b1th27OaiNIVZPbSBiyb" name="Page-1">7V1bc5s4FP41nn1qB0nc/JhLm33Y7nSm3W37iI1is8GWB3Di9NevAGGDJMdKK0SM3IfUCIPNd3Run86RJ+hmtbvLos3yE4lxOoFOvJug2wmEwAtC+l858lyPQBgG9cgiS2L2rsPAl+QnZoMOG90mMc47bywISYtk0x2ck/Uaz4vOWJRl5Kn7tnuSdj91Ey2wMPBlHqXi6LckLpb1aOg5h/E/cbJYNp8MHHZmFs0fFhnZrtnnTSC6r/7Vp1dRcy/2/nwZxeSpNYQ+TNBNRkhRv1rtbnBagtvAVl/38cjZ/ffO8LpQuQBO6yseo3SLm69cfbHiuQGDfsdN+RLv6C2vY7KdVWcAPaieFJf3cujR0zIp8JdNNC9PP9GpQceWxSplb75P0vSGpCSrbotiD4exS8fzIiMPuHUmhDPk+/SM+DTsAR9xVuBda4g93R0mK1xkz/Qt7KwLvPoSNhWnDPing1hByMaWLZG6jUQjNpUW+1sf4KQvGKJydD3/NLo4pjOPHa7JGncxO4pATrbZnN3Cdeux8lYvYpLhNCqSx+4klz0gu/QzSejH7rFEEL4PvQC4sP7r+x1okctBVkTZAhfsJhxq+2+lBKTvXIDUAyS4AKkHSHgBUguQzRO+BOTBzYDTbqZ2J43bhszxfGtse+lxltF8uc3wXXnpbXgYuFovqo90PdFdgVkEcHm3/AEX8+UpIb7CQ8Guh5K6KF/qon7fQwEFe3DW/v8d4AIAAExGAAqT+7zh9QaFVyG+GrXteOc5nPGQwd+X8XAVorJxww84+BE0CD8S0P+bFHhGyAMd/SvJS/f+b4KfBJkUtalpAR+lyWJNX88pFpiidl1ikNB8+IqdWCVxXF5+neE8+RnVJqo0SpsyBKgewrueeLflvbYFyeuMHgjmh4VBOrD3EWd5fAn2UII91JHZCdh/w7PHCmw/WpXTej3LN9WTOgXZ0L90rjQWb3Si4J2ALILpSxIqLlZDIM74qzruZZ/MFFBfbK4ctYmGt1T0DcmKkc6wgJthCIlTTGZndcwwoJDq2eXmjEYZQPRzAvy6YmgdYEHeL0msIXRkczXUgZZoDq2KCgT0TUYFILDdUkDeTpskM6D1+QgPPwwU4fd1wP8KLukpeq5sBA8CMxF+Y0Nw9uER16YESO3KMWh5i5SRIiraFgpnCX3C0qwx+/b5MHKdr6PNV1LTm7wb0Tkx+rB4Mpm7fWncK3zzReT6RO4OKHKRc7vLCA0nHLYiDp1Z+V29sSa7qAnTXrKxoK9sV4ww8nlG0vRrRTKMmGMIYBd2WVg97Qv10FbUEU/vG0Qd2R7O8SuDMvD7Y5cVKoNGjb6wtmKW3De4MKsBLDjlpqrEKfZHeiCRobOJ9BDAdyUTtS/OA9lev8G7SKSac2sxE+JClN3oQ08RfR2MB1KoP7ikv7rTX97cyUTeV/aLFBjei8S1SzwcUOKncr+xEh3QOR3S9ZZwq2vZGwh+xVIU5SU/HV7I+kUn/1dXPXTYB9E8WI6+0fjXVYh/z7rANnQH7F9yba+vDb0BKSDXdsPOo2+U/3QVDPsbikECnis2SsC5IllsEwEngG+SgPMUmOJRm4nAHTAA8RRSFavQN0rAeZf6kwHoGN7cmaRjvFd01F0krk3iCix7bxIXUzw7CDiBVTJIwPkqXTXr+Krca6VENY3yPJl3IadPnj1/bx/8KCF97zWHtzsGcX30zI6OQidrjG835DTp6smGnBaAngTAZuw3e+p9n4tLeI9XP4/QRC/cSGh+AdyNNG5rICrbVfzftorfqz62USoaj68jKlrQl6IpJPknFW2XFN9br380akVfH3SsPGhUbK+aznvH8brq6U7RCQWtjlqeTF1rm16ettY2CyxvRGs9TmtdXtlUtVbYeIBPtDVqrchV/LOJI5pmHBzlGBWXr3tpcGinHlLOQ4PiDrRxFgMvjvLlPlAsDz5HBZXauhqhQZEA+qS0ar6vbd+HgGdGZZTHVKanOvgmX0R/33/t8C3Y4++/5k2Nyf7rxjFeRFF7i64kZFRUb5IQiUCLJcEvnJmUBHAMLh4MsyzJVeT4RtclgWN7cXo45S2+Qc4bSPafsBv+wOyebefVGxBwGVUgIQ973BBBsn2HVWuTPPqyEobeHKHK5h2jthQB5yinqstjeiyF7c0ZPPyhZN+g3lYn92nZZbHK6GKVf1rmfS1WAXBpCRlC5N6QIj/Vkz/aBcrgdGDX1wIleGkLxmNsx3SskggbmJt0XBZl9LUnBVDZhves2Q6A4KB0h/UtHgChIfkO65s8BPwDkzWWwORimw60+NY5w4yHZOMUmxgPEX6jlIfKzh3jNhYQDsl5SDYDsRx/s6QHutRkD5ABC0bPaAqssgnMRebaZQ6mQ8rc1rpswJfbGOU9JHvO2Mt7gP3vAAxCfKjsBvNLxbt1jfzR8t2jyHVqbZvHfiOFtXw5fPCr5fDADY+svuuvrAWSbRDHXxAPHL6+IRTVqq+K+H3zrJbek329+o/2wZHCdi6iuA/neD6XkYuz0HM9ZU1skGpXve9LxN6KdnI+zeN1SlU7eTX3+vvpSNBMDEuLsH1+bxAJzzGV5XlaWCZJJyYQ0KfXJJscn4Y3yjf1D3nfJ7sS04F+zpBvtQISnrk35kjS6SixfGeGqPCDLEYRFYNldO6ICl0vRgEVV0LccwdU2L3DKKBifOn+cfaIotPLpb0hKvmJc+/cAQUgMIYoPcwIKdpRGUVl+YnEuHzH/w==</diagram></mxfile>" style="background-color: rgb(255, 255, 255);"> <defs/> <g> <rect x="1170" y="20" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="1172" y="22" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> - <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1180 253.18 L 1084.14 268.97" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 1078.96 269.82 L 1085.3 265.23 L 1084.14 268.97 L 1086.44 272.13 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> <rect x="1180" y="220" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1181.61 258.61 C 1181.61 258.61 1181.61 258.61 1181.61 258.61 M 1181.61 258.61 C 1181.61 258.61 1181.61 258.61 1181.61 258.61 M 1188.68 254.36 C 1187.67 253.86 1187.08 252.74 1184.43 250.12 M 1188.68 254.36 C 1187.56 253.31 1185.95 251.79 1184.43 250.12 M 1199.99 254.36 C 1192.41 250.6 1189.22 243.55 1184.43 238.81 M 1199.99 254.36 C 1193.4 248.52 1188.15 242.01 1184.43 238.81 M 1211.3 254.36 C 1200.98 247.03 1192.59 236.08 1181.61 224.66 M 1211.3 254.36 C 1200.18 244.59 1191.07 234.74 1181.61 224.66 M 1222.62 254.36 C 1214.4 243.39 1204.58 233.86 1187.26 219.01 M 1222.62 254.36 C 1211.74 243 1201.28 233.79 1187.26 219.01 M 1233.93 254.36 C 1222.91 242.22 1209.87 227.13 1198.58 219.01 M 1233.93 254.36 C 1223.6 244.82 1212.97 233.77 1198.58 219.01 M 1245.24 254.36 C 1233.63 243.18 1225.53 233.87 1209.89 219.01 M 1245.24 254.36 C 1231.63 239.76 1217.33 225.97 1209.89 219.01 M 1256.56 254.36 C 1243.13 243.57 1233.96 232.73 1221.2 219.01 M 1256.56 254.36 C 1246.77 243.93 1235.24 232.15 1221.2 219.01 M 1267.87 254.36 C 1255.25 243.67 1242.37 229.96 1232.52 219.01 M 1267.87 254.36 C 1255.69 241.1 1242.84 230.72 1232.52 219.01 M 1279.19 254.36 C 1271.5 247.66 1265.48 240.73 1243.83 219.01 M 1279.19 254.36 C 1266.33 242.54 1255.31 228.77 1243.83 219.01 M 1290.5 254.36 C 1279.04 243.11 1271.33 234.37 1255.14 219.01 M 1290.5 254.36 C 1282.44 245.26 1274.42 237.37 1255.14 219.01 M 1301.81 254.36 C 1292.72 245 1281.2 236.27 1266.46 219.01 M 1301.81 254.36 C 1291.08 244.16 1282.71 234.35 1266.46 219.01 M 1313.13 254.36 C 1299.51 241.54 1289.64 229.37 1277.77 219.01 M 1313.13 254.36 C 1302.03 242.57 1289.45 231.46 1277.77 219.01 M 1324.44 254.36 C 1315.53 246.64 1305.3 234.36 1289.09 219.01 M 1324.44 254.36 C 1310.3 240.96 1297.72 227.55 1289.09 219.01 M 1339.29 257.9 C 1327.16 243.58 1314.44 231.76 1300.4 219.01 M 1339.29 257.9 C 1327.46 246.88 1314.98 233.87 1300.4 219.01 M 1344.24 251.53 C 1336.71 244.24 1330.22 236.83 1311.71 219.01 M 1344.24 251.53 C 1331.86 238.5 1318.48 226.7 1311.71 219.01 M 1344.95 240.93 C 1338.27 233.35 1328.8 224 1323.03 219.01 M 1344.95 240.93 C 1339.54 234.78 1335.47 230.84 1323.03 219.01 M 1340.7 225.37 C 1340.11 223.71 1338 222.84 1334.34 219.01 M 1340.7 225.37 C 1339.14 223.43 1336.78 221.63 1334.34 219.01" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1186 220 M 1186 220 C 1244.1 220.48 1303.51 217.74 1334 220 M 1186 220 C 1219.19 220.41 1250.9 220.24 1334 220 M 1334 220 C 1336.24 220.37 1339.95 220.4 1340 226 M 1334 220 C 1336.62 221.05 1340.88 223.36 1340 226 M 1340 226 C 1338.61 235.25 1342.13 240.94 1340 254 M 1340 226 C 1339.42 230.95 1340.62 237.92 1340 254 M 1340 254 C 1338.68 256.16 1337.07 258.41 1334 260 M 1340 254 C 1339.88 257.88 1337.07 260.29 1334 260 M 1334 260 C 1283.39 262.26 1234.01 259.03 1186 260 M 1334 260 C 1295.32 261.8 1255.95 260.54 1186 260 M 1186 260 C 1180.05 258.72 1179.66 258.55 1180 254 M 1186 260 C 1182.67 257.98 1179.44 255.93 1180 254 M 1180 254 C 1179.72 244.64 1181.32 236.18 1180 226 M 1180 254 C 1180.36 247.19 1179.77 240.55 1180 226 M 1180 226 C 1179.35 223.63 1183.32 218.95 1186 220 M 1180 226 C 1181.48 221.35 1183.31 220.8 1186 220" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1181.62 258.62 C 1181.62 258.62 1181.62 258.62 1181.62 258.62 M 1181.62 258.62 C 1181.62 258.62 1181.62 258.62 1181.62 258.62 M 1188.69 254.38 C 1187.69 253.87 1187.1 252.76 1184.45 250.13 M 1188.69 254.38 C 1187.57 253.32 1185.97 251.8 1184.45 250.13 M 1200 254.38 C 1192.42 250.61 1189.23 243.56 1184.45 238.82 M 1200 254.38 C 1193.41 248.54 1188.17 242.02 1184.45 238.82 M 1211.32 254.38 C 1200.99 247.04 1192.6 236.09 1181.62 224.68 M 1211.32 254.38 C 1200.19 244.6 1191.08 234.75 1181.62 224.68 M 1222.63 254.38 C 1214.41 243.4 1204.6 233.87 1187.27 219.02 M 1222.63 254.38 C 1211.75 243.01 1201.29 233.81 1187.27 219.02 M 1233.94 254.38 C 1222.92 242.23 1209.89 227.15 1198.59 219.02 M 1233.94 254.38 C 1223.62 244.84 1212.98 233.78 1198.59 219.02 M 1245.26 254.38 C 1233.64 243.2 1225.54 233.88 1209.9 219.02 M 1245.26 254.38 C 1231.64 239.77 1217.34 225.98 1209.9 219.02 M 1256.57 254.38 C 1243.14 243.58 1233.98 232.74 1221.22 219.02 M 1256.57 254.38 C 1246.79 243.95 1235.25 232.16 1221.22 219.02 M 1267.88 254.38 C 1255.26 243.68 1242.38 229.97 1232.53 219.02 M 1267.88 254.38 C 1255.7 241.12 1242.85 230.73 1232.53 219.02 M 1279.2 254.38 C 1271.51 247.67 1265.49 240.75 1243.84 219.02 M 1279.2 254.38 C 1266.34 242.55 1255.32 228.78 1243.84 219.02 M 1290.51 254.38 C 1279.05 243.12 1271.34 234.38 1255.16 219.02 M 1290.51 254.38 C 1282.46 245.28 1274.43 237.38 1255.16 219.02 M 1301.83 254.38 C 1292.73 245.02 1281.21 236.29 1266.47 219.02 M 1301.83 254.38 C 1291.1 244.17 1282.72 234.36 1266.47 219.02 M 1313.14 254.38 C 1299.52 241.55 1289.66 229.38 1277.78 219.02 M 1313.14 254.38 C 1302.04 242.58 1289.46 231.47 1277.78 219.02 M 1324.45 254.38 C 1315.54 246.65 1305.31 234.37 1289.1 219.02 M 1324.45 254.38 C 1310.31 240.97 1297.73 227.57 1289.1 219.02 M 1339.3 257.91 C 1327.18 243.59 1314.46 231.78 1300.41 219.02 M 1339.3 257.91 C 1327.47 246.89 1314.99 233.88 1300.41 219.02 M 1344.25 251.55 C 1336.72 244.25 1330.23 236.84 1311.73 219.02 M 1344.25 251.55 C 1331.87 238.51 1318.49 226.71 1311.73 219.02 M 1344.96 240.94 C 1338.28 233.37 1328.81 224.01 1323.04 219.02 M 1344.96 240.94 C 1339.55 234.79 1335.48 230.85 1323.04 219.02 M 1340.72 225.38 C 1340.12 223.72 1338.02 222.85 1334.35 219.02 M 1340.72 225.38 C 1339.16 223.45 1336.79 221.64 1334.35 219.02" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1186 220 M 1186 220 C 1244.1 220.48 1303.51 217.74 1334 220 M 1186 220 C 1219.19 220.41 1250.9 220.24 1334 220 M 1334 220 C 1336.24 220.37 1339.95 220.4 1340 226 M 1334 220 C 1336.62 221.05 1340.88 223.36 1340 226 M 1340 226 C 1338.61 235.25 1342.13 240.94 1340 254 M 1340 226 C 1339.42 230.95 1340.62 237.92 1340 254 M 1340 254 C 1338.68 256.16 1337.07 258.41 1334 260 M 1340 254 C 1339.88 257.88 1337.07 260.29 1334 260 M 1334 260 C 1283.39 262.26 1234.01 259.03 1186 260 M 1334 260 C 1295.32 261.8 1255.95 260.54 1186 260 M 1186 260 C 1180.05 258.72 1179.66 258.55 1180 254 M 1186 260 C 1182.67 257.98 1179.44 255.93 1180 254 M 1180 254 C 1179.72 244.64 1181.32 236.18 1180 226 M 1180 254 C 1180.36 247.19 1179.77 240.55 1180 226 M 1180 226 C 1179.35 223.63 1183.32 218.95 1186 220 M 1180 226 C 1181.48 221.35 1183.31 220.8 1186 220" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="640" y="40" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="642" y="42" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="240" y="40" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="242" y="42" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="250" y="140" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 251.73 178.73 C 251.73 178.73 251.73 178.73 251.73 178.73 M 251.73 178.73 C 251.73 178.73 251.73 178.73 251.73 178.73 M 258.8 174.49 C 256.28 172.08 255.47 171.1 253.85 169.54 M 258.8 174.49 C 257.11 172.8 255.73 171.81 253.85 169.54 M 270.12 174.49 C 262.95 167.29 257.68 165.36 253.85 158.22 M 270.12 174.49 C 266.29 170.88 260.78 165.8 253.85 158.22 M 281.43 174.49 C 271.19 164.11 261.64 155.15 251.73 144.79 M 281.43 174.49 C 273.89 166.38 265.75 158.56 251.73 144.79 M 292.74 174.49 C 282.33 165.41 273.55 153.59 257.39 139.13 M 292.74 174.49 C 285.29 165.71 276.87 157.09 257.39 139.13 M 304.06 174.49 C 293.37 162.71 281.03 154.15 268.7 139.13 M 304.06 174.49 C 293.16 164.32 281.38 152.56 268.7 139.13 M 315.37 174.49 C 308.19 166.94 299.73 160.5 280.02 139.13 M 315.37 174.49 C 300.4 159.92 286.93 146.85 280.02 139.13 M 326.68 174.49 C 315.89 164.89 305.33 152.6 291.33 139.13 M 326.68 174.49 C 314.46 162.1 301.55 149.63 291.33 139.13 M 338 174.49 C 324.81 162.28 310.62 148.77 302.64 139.13 M 338 174.49 C 325.63 161.67 312.77 148.7 302.64 139.13 M 349.31 174.49 C 339.22 165.77 330.08 151.77 313.96 139.13 M 349.31 174.49 C 336.42 161.8 324.27 150.35 313.96 139.13 M 360.63 174.49 C 349.81 163.93 338.01 153.22 325.27 139.13 M 360.63 174.49 C 348.08 161.01 334.9 148.8 325.27 139.13 M 371.94 174.49 C 363.21 165.43 355.46 157.27 336.58 139.13 M 371.94 174.49 C 364.09 166.65 358.36 159.93 336.58 139.13 M 383.25 174.49 C 371.05 165.07 364.69 152.1 347.9 139.13 M 383.25 174.49 C 373.01 163.94 363.29 153.5 347.9 139.13 M 394.57 174.49 C 385.78 165.05 379.44 157.51 359.21 139.13 M 394.57 174.49 C 386.29 165.84 377.68 157.73 359.21 139.13 M 409.42 178.02 C 400.78 168.07 392.76 161.81 370.52 139.13 M 409.42 178.02 C 398.47 167 388.21 158.27 370.52 139.13 M 414.37 171.66 C 405.52 164.59 396.79 153.74 381.84 139.13 M 414.37 171.66 C 403.67 161.21 391.82 148.76 381.84 139.13 M 414.37 160.35 C 407.59 155.78 402.9 147.44 393.15 139.13 M 414.37 160.35 C 410.07 155.44 404.51 151.24 393.15 139.13 M 410.83 145.5 C 409.6 144.05 407.43 141.88 404.47 139.13 M 410.83 145.5 C 408.19 142.66 406.06 140.91 404.47 139.13" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 256 140 M 256 140 C 298.76 140.44 346.4 140.8 404 140 M 256 140 C 304.93 141.96 353.03 141.27 404 140 M 404 140 C 406.59 140.44 411.67 141.68 410 146 M 404 140 C 406.12 137.85 409.03 140.05 410 146 M 410 146 C 408.69 157.44 408.42 164.75 410 174 M 410 146 C 409.15 151.42 410.37 159.48 410 174 M 410 174 C 408.98 179.41 406.93 181.4 404 180 M 410 174 C 409.69 179.34 407.87 179.67 404 180 M 404 180 C 360.04 179.15 312.38 179.46 256 180 M 404 180 C 350.62 178.6 299.02 180.14 256 180 M 256 180 C 252.31 181.71 250.9 178.66 250 174 M 256 180 C 252.96 179.44 248.22 176.86 250 174 M 250 174 C 251.11 165.87 251.47 157.88 250 146 M 250 174 C 250.84 162.69 250.61 154.29 250 146 M 250 146 C 250.18 140.86 252.68 141.74 256 140 M 250 146 C 247.94 141.23 252.87 141.44 256 140" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 251.74 178.74 C 251.74 178.74 251.74 178.74 251.74 178.74 M 251.74 178.74 C 251.74 178.74 251.74 178.74 251.74 178.74 M 258.81 174.5 C 256.29 172.1 255.49 171.11 253.86 169.55 M 258.81 174.5 C 257.13 172.82 255.74 171.83 253.86 169.55 M 270.13 174.5 C 262.97 167.31 257.7 165.37 253.86 158.24 M 270.13 174.5 C 266.3 170.89 260.8 165.81 253.86 158.24 M 281.44 174.5 C 271.21 164.13 261.66 155.16 251.74 144.8 M 281.44 174.5 C 273.9 166.39 265.76 158.57 251.74 144.8 M 292.76 174.5 C 282.35 165.42 273.56 153.6 257.4 139.15 M 292.76 174.5 C 285.3 165.72 276.88 157.1 257.4 139.15 M 304.07 174.5 C 293.39 162.72 281.04 154.17 268.71 139.15 M 304.07 174.5 C 293.17 164.33 281.39 152.58 268.71 139.15 M 315.38 174.5 C 308.2 166.95 299.74 160.51 280.03 139.15 M 315.38 174.5 C 300.41 159.93 286.95 146.86 280.03 139.15 M 326.7 174.5 C 315.9 164.91 305.35 152.61 291.34 139.15 M 326.7 174.5 C 314.47 162.11 301.56 149.64 291.34 139.15 M 338.01 174.5 C 324.82 162.3 310.63 148.78 302.66 139.15 M 338.01 174.5 C 325.64 161.68 312.78 148.71 302.66 139.15 M 349.32 174.5 C 339.23 165.78 330.09 151.78 313.97 139.15 M 349.32 174.5 C 336.43 161.82 324.28 150.36 313.97 139.15 M 360.64 174.5 C 349.83 163.95 338.02 153.23 325.28 139.15 M 360.64 174.5 C 348.09 161.02 334.92 148.81 325.28 139.15 M 371.95 174.5 C 363.23 165.44 355.47 157.29 336.6 139.15 M 371.95 174.5 C 364.1 166.67 358.38 159.94 336.6 139.15 M 383.27 174.5 C 371.07 165.08 364.7 152.11 347.91 139.15 M 383.27 174.5 C 373.03 163.95 363.3 153.52 347.91 139.15 M 394.58 174.5 C 385.79 165.06 379.46 157.53 359.22 139.15 M 394.58 174.5 C 386.3 165.85 377.69 157.74 359.22 139.15 M 409.43 178.04 C 400.79 168.08 392.77 161.82 370.54 139.15 M 409.43 178.04 C 398.49 167.02 388.22 158.28 370.54 139.15 M 414.38 171.67 C 405.53 164.6 396.8 153.75 381.85 139.15 M 414.38 171.67 C 403.68 161.22 391.84 148.78 381.85 139.15 M 414.38 160.36 C 407.6 155.79 402.91 147.45 393.16 139.15 M 414.38 160.36 C 410.09 155.46 404.52 151.25 393.16 139.15 M 410.84 145.51 C 409.62 144.06 407.44 141.89 404.48 139.15 M 410.84 145.51 C 408.2 142.67 406.07 140.92 404.48 139.15" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 256 140 M 256 140 C 298.76 140.44 346.4 140.8 404 140 M 256 140 C 304.93 141.96 353.03 141.27 404 140 M 404 140 C 406.59 140.44 411.67 141.68 410 146 M 404 140 C 406.12 137.85 409.03 140.05 410 146 M 410 146 C 408.69 157.44 408.42 164.75 410 174 M 410 146 C 409.15 151.42 410.37 159.48 410 174 M 410 174 C 408.98 179.41 406.93 181.4 404 180 M 410 174 C 409.69 179.34 407.87 179.67 404 180 M 404 180 C 360.04 179.15 312.38 179.46 256 180 M 404 180 C 350.62 178.6 299.02 180.14 256 180 M 256 180 C 252.31 181.71 250.9 178.66 250 174 M 256 180 C 252.96 179.44 248.22 176.86 250 174 M 250 174 C 251.11 165.87 251.47 157.88 250 146 M 250 174 C 250.84 162.69 250.61 154.29 250 146 M 250 146 C 250.18 140.86 252.68 141.74 256 140 M 250 146 C 247.94 141.23 252.87 141.44 256 140" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="650" y="250" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 651.29 288.29 C 651.29 288.29 651.29 288.29 651.29 288.29 M 651.29 288.29 C 651.29 288.29 651.29 288.29 651.29 288.29 M 658.36 284.05 C 657.6 283.09 655.72 282.13 654.12 279.8 M 658.36 284.05 C 657.43 283.09 656.37 282.27 654.12 279.8 M 669.67 284.05 C 665.18 280.37 658.8 272.03 654.12 268.49 M 669.67 284.05 C 666.54 280.07 661.74 276.55 654.12 268.49 M 680.99 284.05 C 671.89 275.51 660.27 264.21 651.29 254.35 M 680.99 284.05 C 671.99 274.59 660.4 263.56 651.29 254.35 M 693.01 284.75 C 678.5 270.79 665.81 258.58 656.95 248.69 M 693.01 284.75 C 682.25 274.11 671.19 262.93 656.95 248.69 M 704.32 284.75 C 696.3 276.48 687.94 267.87 668.26 248.69 M 704.32 284.75 C 695.06 276.54 688.19 267.88 668.26 248.69 M 715.64 284.75 C 707.37 278.45 700.59 269.67 679.57 248.69 M 715.64 284.75 C 707.91 276.49 698.05 266.85 679.57 248.69 M 726.95 284.75 C 716.5 273.04 702.64 260.88 690.89 248.69 M 726.95 284.75 C 719.02 277.2 711.05 267.5 690.89 248.69 M 738.26 284.75 C 723.97 271.39 715.48 258.89 702.2 248.69 M 738.26 284.75 C 726.91 274.5 716.32 262.28 702.2 248.69 M 749.58 284.75 C 740.46 272.55 730.86 263.55 713.51 248.69 M 749.58 284.75 C 741.3 275.88 732.96 267.82 713.51 248.69 M 760.89 284.75 C 752.08 272.9 741.28 263.97 724.83 248.69 M 760.89 284.75 C 752.27 276.21 744.71 268.02 724.83 248.69 M 772.2 284.75 C 762.07 276.93 755.66 267.35 736.85 249.4 M 772.2 284.75 C 760.17 272.93 750.19 261.73 736.85 249.4 M 783.52 284.75 C 770.76 270.69 755.21 256.21 748.16 249.4 M 783.52 284.75 C 775.88 276.98 765.82 268.19 748.16 249.4 M 794.83 284.75 C 780.11 269.98 770.07 256.76 759.48 249.4 M 794.83 284.75 C 785.38 276.15 777.62 267.71 759.48 249.4 M 808.97 287.58 C 798.59 277.17 789.38 268.93 770.79 249.4 M 808.97 287.58 C 799.05 278.73 789.72 268.49 770.79 249.4 M 814.63 281.93 C 807.59 273.58 801.66 268.63 782.1 249.4 M 814.63 281.93 C 802.54 270.64 790.55 259.1 782.1 249.4 M 814.63 270.61 C 811.11 266.83 803.24 261.94 793.42 249.4 M 814.63 270.61 C 807.59 263.57 800.36 257.26 793.42 249.4 M 810.39 255.06 C 808.9 254.26 807.68 252.92 804.73 249.4 M 810.39 255.06 C 808.2 252.95 806.66 251.3 804.73 249.4" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 656 250 M 656 250 C 694.59 248.82 733.79 247.71 804 250 M 656 250 C 707.2 249.71 757.39 248.75 804 250 M 804 250 C 809.37 251.48 811.56 251.31 810 256 M 804 250 C 810.11 251.42 811.31 250.53 810 256 M 810 256 C 808.2 261.12 811.64 267.76 810 284 M 810 256 C 810.61 266.41 810.46 278.44 810 284 M 810 284 C 811.17 288.73 806.32 289.57 804 290 M 810 284 C 810 288.74 807.35 289.92 804 290 M 804 290 C 756.02 291.47 707.56 291.15 656 290 M 804 290 C 767.15 288.96 731.23 289.74 656 290 M 656 290 C 650.23 290.19 649.53 289.41 650 284 M 656 290 C 650.25 292.23 651.04 289.07 650 284 M 650 284 C 651.45 273.74 648.46 265.46 650 256 M 650 284 C 649.18 277.21 649.24 268.65 650 256 M 650 256 C 648.5 250.86 651.78 251.74 656 250 M 650 256 C 649.95 251.39 654.02 248.94 656 250" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 651.3 288.3 C 651.3 288.3 651.3 288.3 651.3 288.3 M 651.3 288.3 C 651.3 288.3 651.3 288.3 651.3 288.3 M 658.37 284.06 C 657.61 283.1 655.73 282.14 654.13 279.82 M 658.37 284.06 C 657.44 283.1 656.39 282.28 654.13 279.82 M 669.69 284.06 C 665.19 280.38 658.81 272.05 654.13 268.5 M 669.69 284.06 C 666.55 280.08 661.75 276.56 654.13 268.5 M 681 284.06 C 671.9 275.52 660.28 264.23 651.3 254.36 M 681 284.06 C 672.01 274.6 660.41 263.57 651.3 254.36 M 693.02 284.77 C 678.51 270.8 665.82 258.59 656.96 248.7 M 693.02 284.77 C 682.26 274.12 671.2 262.94 656.96 248.7 M 704.34 284.77 C 696.31 276.49 687.95 267.88 668.27 248.7 M 704.34 284.77 C 695.08 276.55 688.2 267.89 668.27 248.7 M 715.65 284.77 C 707.38 278.47 700.6 269.68 679.59 248.7 M 715.65 284.77 C 707.93 276.5 698.06 266.87 679.59 248.7 M 726.96 284.77 C 716.51 273.05 702.65 260.9 690.9 248.7 M 726.96 284.77 C 719.04 277.22 711.07 267.52 690.9 248.7 M 738.28 284.77 C 723.98 271.4 715.5 258.9 702.21 248.7 M 738.28 284.77 C 726.93 274.51 716.33 262.3 702.21 248.7 M 749.59 284.77 C 740.47 272.57 730.87 263.56 713.53 248.7 M 749.59 284.77 C 741.31 275.89 732.98 267.83 713.53 248.7 M 760.9 284.77 C 752.09 272.91 741.29 263.99 724.84 248.7 M 760.9 284.77 C 752.28 276.22 744.72 268.04 724.84 248.7 M 772.22 284.77 C 762.08 276.94 755.67 267.36 736.86 249.41 M 772.22 284.77 C 760.18 272.94 750.21 261.74 736.86 249.41 M 783.53 284.77 C 770.77 270.7 755.22 256.23 748.18 249.41 M 783.53 284.77 C 775.9 276.99 765.83 268.2 748.18 249.41 M 794.84 284.77 C 780.12 269.99 770.08 256.78 759.49 249.41 M 794.84 284.77 C 785.39 276.16 777.63 267.72 759.49 249.41 M 808.99 287.59 C 798.6 277.18 789.4 268.94 770.8 249.41 M 808.99 287.59 C 799.07 278.74 789.73 268.5 770.8 249.41 M 814.64 281.94 C 807.6 273.6 801.67 268.64 782.12 249.41 M 814.64 281.94 C 802.55 270.65 790.57 259.11 782.12 249.41 M 814.64 270.62 C 811.12 266.84 803.26 261.95 793.43 249.41 M 814.64 270.62 C 807.6 263.58 800.37 257.27 793.43 249.41 M 810.4 255.07 C 808.91 254.28 807.69 252.93 804.74 249.41 M 810.4 255.07 C 808.21 252.96 806.68 251.32 804.74 249.41" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 656 250 M 656 250 C 694.59 248.82 733.79 247.71 804 250 M 656 250 C 707.2 249.71 757.39 248.75 804 250 M 804 250 C 809.37 251.48 811.56 251.31 810 256 M 804 250 C 810.11 251.42 811.31 250.53 810 256 M 810 256 C 808.2 261.12 811.64 267.76 810 284 M 810 256 C 810.61 266.41 810.46 278.44 810 284 M 810 284 C 811.17 288.73 806.32 289.57 804 290 M 810 284 C 810 288.74 807.35 289.92 804 290 M 804 290 C 756.02 291.47 707.56 291.15 656 290 M 804 290 C 767.15 288.96 731.23 289.74 656 290 M 656 290 C 650.23 290.19 649.53 289.41 650 284 M 656 290 C 650.25 292.23 651.04 289.07 650 284 M 650 284 C 651.45 273.74 648.46 265.46 650 256 M 650 284 C 649.18 277.21 649.24 268.65 650 256 M 650 256 C 648.5 250.86 651.78 251.74 656 250 M 650 256 C 649.95 251.39 654.02 248.94 656 250" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="120" y="90" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 100px; margin-left: 180px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="180" y="104" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="180" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> @@ -44,86 +44,86 @@ <rect x="240" y="20" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 30px; margin-left: 300px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -1000 </div> </div> </div> </foreignObject> - <text x="300" y="34" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="300" y="34" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -1000 </text> </switch> </g> - <path d="M 300 220 L 523.63 220" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 528.88 220 L 521.88 223.5 L 523.63 220 L 521.88 216.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 300 220 L 523.63 220" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 528.88 220 L 521.88 223.5 L 523.63 220 L 521.88 216.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> <rect x="40" y="260" width="60" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 270px; margin-left: 70px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Viewport </div> </div> </div> </foreignObject> - <text x="70" y="274" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="70" y="274" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Viewport </text> </switch> </g> <rect x="650" y="140" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 651.84 178.84 C 651.84 178.84 651.84 178.84 651.84 178.84 M 651.84 178.84 C 651.84 178.84 651.84 178.84 651.84 178.84 M 658.91 174.6 C 657.23 172.92 656.32 172.25 653.96 169.65 M 658.91 174.6 C 657.66 173.67 656.31 171.73 653.96 169.65 M 670.23 174.6 C 666.63 169.33 661.66 165.95 653.96 158.34 M 670.23 174.6 C 664.66 170.75 661.31 165.07 653.96 158.34 M 681.54 174.6 C 670.47 163.77 662.41 155.78 651.13 144.19 M 681.54 174.6 C 669.93 163.87 660.6 152.73 651.13 144.19 M 692.85 174.6 C 683.43 168.08 677.71 160.16 656.79 138.54 M 692.85 174.6 C 682.35 164.44 674.09 155.19 656.79 138.54 M 704.17 174.6 C 690.96 161.91 675.59 145.19 668.81 139.24 M 704.17 174.6 C 693.15 163.34 681.43 151.75 668.81 139.24 M 715.48 174.6 C 703.75 162.94 688.12 148.08 680.13 139.24 M 715.48 174.6 C 704.89 163.43 693.82 152.77 680.13 139.24 M 726.8 174.6 C 717.85 164.63 707.04 158.33 691.44 139.24 M 726.8 174.6 C 716.6 166.13 707.6 156.74 691.44 139.24 M 738.11 174.6 C 729.91 164.5 720.2 159.32 702.75 139.24 M 738.11 174.6 C 728.07 165.07 716.12 153.48 702.75 139.24 M 749.42 174.6 C 743.58 167.83 734.72 160.67 714.07 139.24 M 749.42 174.6 C 738.1 162.05 725.18 151.24 714.07 139.24 M 760.74 174.6 C 752.87 167.11 744.66 158.07 725.38 139.24 M 760.74 174.6 C 752.71 165.26 743.27 157.11 725.38 139.24 M 772.05 174.6 C 762.46 167.17 752.87 155.87 736.69 139.24 M 772.05 174.6 C 759.84 162.1 747.11 148.47 736.69 139.24 M 783.36 174.6 C 775.6 164.92 768.37 156.4 748.01 139.24 M 783.36 174.6 C 772.78 163.38 760.54 150.81 748.01 139.24 M 794.68 174.6 C 784.03 165.04 772.6 151.95 759.32 139.24 M 794.68 174.6 C 787.03 168.4 778.98 160.37 759.32 139.24 M 809.53 178.13 C 797.62 164.76 787.72 156.15 770.64 139.24 M 809.53 178.13 C 801.29 169.82 791.8 160.34 770.64 139.24 M 814.48 171.77 C 804.01 159.92 794.64 152.48 781.95 139.24 M 814.48 171.77 C 803.16 159.87 791.09 148.16 781.95 139.24 M 814.48 160.46 C 806.71 151.82 798.82 144.83 793.26 139.24 M 814.48 160.46 C 809.81 154.15 804.17 149.24 793.26 139.24 M 810.94 145.61 C 808.19 143.76 806.65 140.9 804.58 139.24 M 810.94 145.61 C 808.94 143.65 807.67 142.2 804.58 139.24" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 656 140 M 656 140 C 707.36 139.37 763.42 138.34 804 140 M 656 140 C 687.27 139.19 717.1 138.72 804 140 M 804 140 C 807.46 140.7 810.31 143 810 146 M 804 140 C 808.05 139.52 808.32 140.53 810 146 M 810 146 C 809.74 157.07 809.32 167.44 810 174 M 810 146 C 810.25 153.57 809.86 159.55 810 174 M 810 174 C 809.93 179.17 806.26 181.9 804 180 M 810 174 C 808.2 178.69 807.89 179.71 804 180 M 804 180 C 746.73 181.14 688.12 180.86 656 180 M 804 180 C 748.29 181.05 693.13 181.37 656 180 M 656 180 C 652.18 180.69 650.42 176.05 650 174 M 656 180 C 652.55 182.25 648.32 175.71 650 174 M 650 174 C 649.21 161.32 648.99 152.1 650 146 M 650 174 C 650.13 164.35 650.38 157.1 650 146 M 650 146 C 649.04 143.85 650.79 140.18 656 140 M 650 146 C 652.01 139.91 651.92 139.33 656 140" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <rect x="520" y="120" width="200" height="280" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="522" y="122" width="196" height="276" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <path d="M 651.15 178.15 C 651.15 178.15 651.15 178.15 651.15 178.15 M 651.15 178.15 C 651.15 178.15 651.15 178.15 651.15 178.15 M 658.93 174.61 C 657.24 172.93 656.33 172.26 653.98 169.66 M 658.93 174.61 C 657.67 173.68 656.33 171.75 653.98 169.66 M 670.24 174.61 C 666.64 169.34 661.67 165.97 653.98 158.35 M 670.24 174.61 C 664.68 170.77 661.33 165.08 653.98 158.35 M 681.55 174.61 C 670.48 163.78 662.42 155.79 651.15 144.21 M 681.55 174.61 C 669.95 163.89 660.61 152.74 651.15 144.21 M 692.87 174.61 C 683.45 168.09 677.73 160.17 656.8 138.55 M 692.87 174.61 C 682.37 164.45 674.1 155.2 656.8 138.55 M 704.18 174.61 C 690.69 161.64 675.04 144.64 668.12 138.55 M 704.18 174.61 C 692.94 163.12 680.98 151.3 668.12 138.55 M 715.49 174.61 C 703.76 162.96 688.13 148.09 680.14 139.26 M 715.49 174.61 C 704.91 163.44 693.83 152.78 680.14 139.26 M 726.81 174.61 C 717.86 164.64 707.05 158.34 691.45 139.26 M 726.81 174.61 C 716.62 166.14 707.62 156.76 691.45 139.26 M 738.12 174.61 C 729.92 164.52 720.21 159.33 702.77 139.26 M 738.12 174.61 C 728.08 165.09 716.13 153.49 702.77 139.26 M 749.44 174.61 C 743.6 167.85 734.73 160.69 714.08 139.26 M 749.44 174.61 C 738.12 162.06 725.19 151.25 714.08 139.26 M 760.75 174.61 C 752.88 167.12 744.68 158.08 725.39 139.26 M 760.75 174.61 C 752.73 165.28 743.29 157.12 725.39 139.26 M 772.06 174.61 C 762.48 167.18 752.88 155.88 736.71 139.26 M 772.06 174.61 C 759.85 162.11 747.12 148.48 736.71 139.26 M 783.38 174.61 C 775.62 164.93 768.38 156.42 748.02 139.26 M 783.38 174.61 C 772.8 163.39 760.56 150.82 748.02 139.26 M 794.69 174.61 C 784.04 165.05 772.61 151.97 759.34 139.26 M 794.69 174.61 C 787.04 168.41 778.99 160.39 759.34 139.26 M 809.54 178.15 C 797.63 164.78 787.73 156.16 770.65 139.26 M 809.54 178.15 C 801.3 169.83 791.82 160.35 770.65 139.26 M 814.49 171.78 C 804.02 159.94 794.66 152.5 781.96 139.26 M 814.49 171.78 C 803.17 159.88 791.11 148.18 781.96 139.26 M 814.49 160.47 C 806.72 151.83 798.83 144.84 793.28 139.26 M 814.49 160.47 C 809.82 154.16 804.18 149.25 793.28 139.26 M 810.95 145.62 C 808.2 143.77 806.66 140.92 804.59 139.26 M 810.95 145.62 C 808.95 143.66 807.69 142.21 804.59 139.26" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 656 140 M 656 140 C 707.36 139.37 763.42 138.34 804 140 M 656 140 C 687.27 139.19 717.1 138.72 804 140 M 804 140 C 807.46 140.7 810.31 143 810 146 M 804 140 C 808.05 139.52 808.32 140.53 810 146 M 810 146 C 809.74 157.07 809.32 167.44 810 174 M 810 146 C 810.25 153.57 809.86 159.55 810 174 M 810 174 C 809.93 179.17 806.26 181.9 804 180 M 810 174 C 808.2 178.69 807.89 179.71 804 180 M 804 180 C 746.73 181.14 688.12 180.86 656 180 M 804 180 C 748.29 181.05 693.13 181.37 656 180 M 656 180 C 652.18 180.69 650.42 176.05 650 174 M 656 180 C 652.55 182.25 648.32 175.71 650 174 M 650 174 C 649.21 161.32 648.99 152.1 650 146 M 650 174 C 650.13 164.35 650.38 157.1 650 146 M 650 146 C 649.04 143.85 650.79 140.18 656 140 M 650 146 C 652.01 139.91 651.92 139.33 656 140" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <rect x="520" y="120" width="200" height="280" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="522" y="122" width="196" height="276" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="520" y="90" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 100px; margin-left: 580px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="580" y="104" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="580" y="104" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> </g> <rect x="540" y="320" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 541.49 358.49 C 541.49 358.49 541.49 358.49 541.49 358.49 M 541.49 358.49 C 541.49 358.49 541.49 358.49 541.49 358.49 M 548.56 354.25 C 547.85 352.53 546.66 352.46 544.32 350 M 548.56 354.25 C 547.17 352.72 545.84 351.61 544.32 350 M 559.88 354.25 C 557.35 350.82 554.32 346.98 544.32 338.69 M 559.88 354.25 C 554.59 349.08 550.5 343.97 544.32 338.69 M 571.19 354.25 C 563.61 346.65 557.31 338.81 541.49 324.55 M 571.19 354.25 C 562.69 344.86 553.7 336.42 541.49 324.55 M 582.5 354.25 C 574.61 345.76 569.78 339.49 547.15 318.89 M 582.5 354.25 C 569.24 341.22 556.11 329.32 547.15 318.89 M 593.82 354.25 C 586.22 346.9 578.19 337.27 558.46 318.89 M 593.82 354.25 C 582.2 342.19 568.84 329.67 558.46 318.89 M 605.13 354.25 C 595.04 341.54 583.87 329.13 569.77 318.89 M 605.13 354.25 C 595.66 345.79 588.16 337.56 569.77 318.89 M 616.44 354.25 C 607.94 346.31 599.69 336.35 581.09 318.89 M 616.44 354.25 C 604.82 342.95 594.94 333.53 581.09 318.89 M 627.76 354.25 C 618.05 342.06 606.77 332.3 592.4 318.89 M 627.76 354.25 C 618.62 344.7 609.11 335.66 592.4 318.89 M 639.07 354.25 C 631.46 345.63 621.52 334.51 603.72 318.89 M 639.07 354.25 C 629.22 344.54 620.79 335.45 603.72 318.89 M 650.38 354.25 C 638.34 342.73 621.68 328.58 615.03 318.89 M 650.38 354.25 C 642.22 345.02 632.01 336.03 615.03 318.89 M 662.41 354.95 C 654.54 346.57 644.16 338.93 626.34 318.89 M 662.41 354.95 C 651.78 343.43 639.33 331.31 626.34 318.89 M 673.72 354.95 C 664.6 347.88 657.51 336.3 637.66 318.89 M 673.72 354.95 C 662.94 345.67 653.66 335.31 637.66 318.89 M 685.03 354.95 C 677.11 346.13 667.73 335.49 648.97 318.89 M 685.03 354.95 C 671.26 342.11 656.92 327.11 648.97 318.89 M 699.18 357.78 C 691.89 350.11 682.6 341.02 660.28 318.89 M 699.18 357.78 C 685.14 345.54 673.51 331.88 660.28 318.89 M 704.12 351.42 C 697.46 345.29 690.64 336.04 671.6 318.89 M 704.12 351.42 C 694.71 342.26 683.66 330.48 671.6 318.89 M 704.83 340.81 C 702.09 336.08 697.74 330.06 682.91 318.89 M 704.83 340.81 C 698.36 334.02 690.89 326.3 682.91 318.89 M 700.59 325.26 C 698.74 322.6 696.73 320.55 694.23 318.89 M 700.59 325.26 C 699.11 323.33 696.64 321.75 694.23 318.89" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 546 320 M 546 320 C 595.15 319.96 641.86 319.9 694 320 M 546 320 C 582.87 320.54 620.19 321.57 694 320 M 694 320 C 696.55 321.31 700.29 322.86 700 326 M 694 320 C 699.42 317.91 698.93 324.07 700 326 M 700 326 C 700.42 335.04 698.1 347.01 700 354 M 700 326 C 699.62 334.65 699.42 343.7 700 354 M 700 354 C 698.81 357.96 698.2 360.46 694 360 M 700 354 C 698.04 356.47 696.39 359.01 694 360 M 694 360 C 665.04 359.86 630.87 361.96 546 360 M 694 360 C 658.19 360.88 623.93 361.64 546 360 M 546 360 C 543.96 361.84 540.59 359.97 540 354 M 546 360 C 543.28 361.54 538.62 359.84 540 354 M 540 354 C 540.05 345.24 540.56 335.59 540 326 M 540 354 C 540.19 345.32 539.14 337.98 540 326 M 540 326 C 540.11 321.32 540.71 319.7 546 320 M 540 326 C 539.32 322.16 541.03 318.19 546 320" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 541.5 358.5 C 541.5 358.5 541.5 358.5 541.5 358.5 M 541.5 358.5 C 541.5 358.5 541.5 358.5 541.5 358.5 M 548.57 354.26 C 547.86 352.55 546.67 352.48 544.33 350.02 M 548.57 354.26 C 547.18 352.73 545.85 351.62 544.33 350.02 M 559.89 354.26 C 557.36 350.83 554.33 346.99 544.33 338.7 M 559.89 354.26 C 554.6 349.09 550.51 343.99 544.33 338.7 M 571.2 354.26 C 563.63 346.67 557.32 338.83 541.5 324.56 M 571.2 354.26 C 562.71 344.87 553.71 336.44 541.5 324.56 M 582.52 354.26 C 574.62 345.77 569.79 339.5 547.16 318.91 M 582.52 354.26 C 569.25 341.23 556.12 329.34 547.16 318.91 M 593.83 354.26 C 586.23 346.91 578.2 337.29 558.47 318.91 M 593.83 354.26 C 582.21 342.2 568.86 329.69 558.47 318.91 M 605.14 354.26 C 595.05 341.55 583.88 329.15 569.79 318.91 M 605.14 354.26 C 595.67 345.8 588.18 337.57 569.79 318.91 M 616.46 354.26 C 607.96 346.32 599.71 336.36 581.1 318.91 M 616.46 354.26 C 604.83 342.96 594.95 333.55 581.1 318.91 M 627.77 354.26 C 618.06 342.07 606.79 332.31 592.41 318.91 M 627.77 354.26 C 618.63 344.71 609.13 335.67 592.41 318.91 M 639.08 354.26 C 631.47 345.64 621.53 334.52 603.73 318.91 M 639.08 354.26 C 629.23 344.56 620.8 335.46 603.73 318.91 M 650.4 354.26 C 638.36 342.74 621.69 328.6 615.04 318.91 M 650.4 354.26 C 642.24 345.04 632.02 336.04 615.04 318.91 M 662.42 354.97 C 654.55 346.58 644.17 338.94 626.36 318.91 M 662.42 354.97 C 651.79 343.44 639.34 331.32 626.36 318.91 M 673.73 354.97 C 664.61 347.89 657.52 336.31 637.67 318.91 M 673.73 354.97 C 662.95 345.68 653.67 335.33 637.67 318.91 M 685.05 354.97 C 677.12 346.14 667.74 335.51 648.98 318.91 M 685.05 354.97 C 671.27 342.12 656.93 327.13 648.98 318.91 M 699.19 357.8 C 691.91 350.12 682.61 341.04 660.3 318.91 M 699.19 357.8 C 685.15 345.56 673.52 331.9 660.3 318.91 M 704.14 351.43 C 697.47 345.31 690.66 336.05 671.61 318.91 M 704.14 351.43 C 694.72 342.28 683.67 330.49 671.61 318.91 M 704.84 340.83 C 702.1 336.1 697.75 330.08 682.92 318.91 M 704.84 340.83 C 698.38 334.04 690.9 326.31 682.92 318.91 M 700.6 325.27 C 698.75 322.61 696.74 320.56 694.24 318.91 M 700.6 325.27 C 699.13 323.34 696.65 321.76 694.24 318.91" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 546 320 M 546 320 C 595.15 319.96 641.86 319.9 694 320 M 546 320 C 582.87 320.54 620.19 321.57 694 320 M 694 320 C 696.55 321.31 700.29 322.86 700 326 M 694 320 C 699.42 317.91 698.93 324.07 700 326 M 700 326 C 700.42 335.04 698.1 347.01 700 354 M 700 326 C 699.62 334.65 699.42 343.7 700 354 M 700 354 C 698.81 357.96 698.2 360.46 694 360 M 700 354 C 698.04 356.47 696.39 359.01 694 360 M 694 360 C 665.04 359.86 630.87 361.96 546 360 M 694 360 C 658.19 360.88 623.93 361.64 546 360 M 546 360 C 543.96 361.84 540.59 359.97 540 354 M 546 360 C 543.28 361.54 538.62 359.84 540 354 M 540 354 C 540.05 345.24 540.56 335.59 540 326 M 540 354 C 540.19 345.32 539.14 337.98 540 326 M 540 326 C 540.11 321.32 540.71 319.7 546 320 M 540 326 C 539.32 322.16 541.03 318.19 546 320" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="540" y="200" width="160" height="60" rx="9" ry="9" fill="none" stroke="none" pointer-events="all"/> - <path d="M 542.04 257.54 C 542.04 257.54 542.04 257.54 542.04 257.54 M 542.04 257.54 C 542.04 257.54 542.04 257.54 542.04 257.54 M 549.81 254 C 548.15 251.26 546.39 250.87 543.45 247.64 M 549.81 254 C 547.43 251.93 545.18 249.65 543.45 247.64 M 561.83 254.71 C 554.36 248.41 548.71 242.48 543.45 236.32 M 561.83 254.71 C 555.97 250.52 551.91 244.18 543.45 236.32 M 573.15 254.71 C 567.26 247.23 558.39 243.48 543.45 225.01 M 573.15 254.71 C 562.82 244.21 552.74 234.87 543.45 225.01 M 584.46 254.71 C 574.94 243.35 563.26 237.09 543.45 213.7 M 584.46 254.71 C 570.51 239.4 555.75 226.14 543.45 213.7 M 595.78 254.71 C 582.05 240.37 564.29 226.22 542.74 201.67 M 595.78 254.71 C 580.6 239.94 566.95 225.33 542.74 201.67 M 607.09 254.71 C 592.04 239.44 575.24 222.21 550.52 198.14 M 607.09 254.71 C 594.47 243.28 582.03 229.76 550.52 198.14 M 618.4 254.71 C 607.72 241.4 593.61 229.32 561.83 198.14 M 618.4 254.71 C 598.76 234.71 579.15 214.44 561.83 198.14 M 629.72 254.71 C 608.51 231.29 585.01 208.41 573.15 198.14 M 629.72 254.71 C 612.48 237.41 597.11 221.04 573.15 198.14 M 641.03 254.71 C 617.7 231.65 594.48 210.26 584.46 198.14 M 641.03 254.71 C 625.18 238.94 608.89 223.82 584.46 198.14 M 652.34 254.71 C 638.84 241.87 626.45 226.51 595.78 198.14 M 652.34 254.71 C 631.66 233.56 612.13 213.76 595.78 198.14 M 663.66 254.71 C 640.42 234.95 619.7 212.71 607.8 198.85 M 663.66 254.71 C 644.21 235.59 625.33 215.77 607.8 198.85 M 674.97 254.71 C 660.31 239.91 642.3 221.2 619.11 198.85 M 674.97 254.71 C 652.98 233.08 630.78 211.02 619.11 198.85 M 691.24 259.66 C 678.6 244.85 665.4 233.12 630.42 198.85 M 691.24 259.66 C 669.25 237.68 646.98 213.92 630.42 198.85 M 699.01 256.12 C 677.27 235.23 656.38 210.21 641.74 198.85 M 699.01 256.12 C 685.29 243.83 673.45 230.23 641.74 198.85 M 703.96 249.76 C 687.09 231.68 670.82 217.65 653.05 198.85 M 703.96 249.76 C 687.05 232.39 669.78 215.14 653.05 198.85 M 704.67 239.15 C 691.2 226.54 677.09 209.63 664.37 198.85 M 704.67 239.15 C 689.19 223.64 673.91 207.41 664.37 198.85 M 704.67 227.84 C 694.07 215.31 683.15 202.66 675.68 198.85 M 704.67 227.84 C 693.41 216.46 682.36 206.54 675.68 198.85 M 704.67 216.52 C 698.99 210.95 691.23 202.98 686.99 198.85 M 704.67 216.52 C 699.21 212.16 695.19 206.73 686.99 198.85" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 549 200 M 549 200 C 589.62 199.98 631.67 201.85 691 200 M 549 200 C 595.2 200.38 642.58 199.46 691 200 M 691 200 C 698.63 198.42 698.99 204.78 700 209 M 691 200 C 697.12 199.42 699.91 203.43 700 209 M 700 209 C 701.63 222.93 698.31 234.71 700 251 M 700 209 C 700.8 223.17 700.18 237.85 700 251 M 700 251 C 701.08 257.52 695.61 261.42 691 260 M 700 251 C 698.67 257.02 698.68 261.15 691 260 M 691 260 C 642.67 262.77 591.95 259.45 549 260 M 691 260 C 638.75 261 588.59 261 549 260 M 549 260 C 544.51 258.6 539.85 256.29 540 251 M 549 260 C 542.04 259.13 541.51 257.61 540 251 M 540 251 C 538.98 235.18 539.97 220.01 540 209 M 540 251 C 540.81 237.9 538.91 226.34 540 209 M 540 209 C 538.24 203.35 542.72 199.24 549 200 M 540 209 C 541.82 203.38 542.2 198.48 549 200" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 542.05 257.55 C 542.05 257.55 542.05 257.55 542.05 257.55 M 542.05 257.55 C 542.05 257.55 542.05 257.55 542.05 257.55 M 549.83 254.01 C 548.16 251.27 546.4 250.89 543.46 247.65 M 549.83 254.01 C 547.44 251.94 545.19 249.67 543.46 247.65 M 561.85 254.72 C 554.37 248.43 548.73 242.49 543.46 236.34 M 561.85 254.72 C 555.98 250.53 551.93 244.19 543.46 236.34 M 573.16 254.72 C 567.28 247.24 558.41 243.49 543.46 225.02 M 573.16 254.72 C 562.84 244.22 552.75 234.88 543.46 225.02 M 584.47 254.72 C 574.96 243.36 563.28 237.1 543.46 213.71 M 584.47 254.72 C 570.52 239.41 555.76 226.16 543.46 213.71 M 595.79 254.72 C 582.07 240.38 564.3 226.24 542.76 201.69 M 595.79 254.72 C 580.62 239.96 566.96 225.34 542.76 201.69 M 607.1 254.72 C 592.05 239.46 575.25 222.23 550.53 198.15 M 607.1 254.72 C 594.49 243.29 582.04 229.78 550.53 198.15 M 618.42 254.72 C 607.73 241.41 593.62 229.34 561.85 198.15 M 618.42 254.72 C 598.77 234.72 579.17 214.46 561.85 198.15 M 629.73 254.72 C 608.52 231.3 585.02 208.42 573.16 198.15 M 629.73 254.72 C 612.5 237.42 597.12 221.05 573.16 198.15 M 641.04 254.72 C 617.72 231.67 594.49 210.28 584.47 198.15 M 641.04 254.72 C 625.2 238.95 608.91 223.84 584.47 198.15 M 652.36 254.72 C 638.86 241.88 626.46 226.52 595.79 198.15 M 652.36 254.72 C 631.68 233.58 612.14 213.77 595.79 198.15 M 663.67 254.72 C 640.44 234.96 619.71 212.72 607.81 198.86 M 663.67 254.72 C 644.22 235.6 625.34 215.78 607.81 198.86 M 674.98 254.72 C 660.32 239.92 642.32 221.21 619.12 198.86 M 674.98 254.72 C 653 233.1 630.79 211.03 619.12 198.86 M 691.25 259.67 C 678.61 244.86 665.42 233.13 630.44 198.86 M 691.25 259.67 C 669.26 237.7 646.99 213.93 630.44 198.86 M 699.03 256.13 C 677.28 235.24 656.4 210.22 641.75 198.86 M 699.03 256.13 C 685.3 243.84 673.46 230.24 641.75 198.86 M 703.98 249.77 C 687.1 231.69 670.84 217.67 653.06 198.86 M 703.98 249.77 C 687.07 232.41 669.79 215.15 653.06 198.86 M 704.68 239.16 C 691.22 226.56 677.1 209.65 664.38 198.86 M 704.68 239.16 C 689.21 223.65 673.92 207.42 664.38 198.86 M 704.68 227.85 C 694.08 215.32 683.16 202.67 675.69 198.86 M 704.68 227.85 C 693.42 216.48 682.37 206.55 675.69 198.86 M 704.68 216.54 C 699 210.96 691.24 202.99 687.01 198.86 M 704.68 216.54 C 699.22 212.18 695.2 206.74 687.01 198.86" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 549 200 M 549 200 C 589.62 199.98 631.67 201.85 691 200 M 549 200 C 595.2 200.38 642.58 199.46 691 200 M 691 200 C 698.63 198.42 698.99 204.78 700 209 M 691 200 C 697.12 199.42 699.91 203.43 700 209 M 700 209 C 701.63 222.93 698.31 234.71 700 251 M 700 209 C 700.8 223.17 700.18 237.85 700 251 M 700 251 C 701.08 257.52 695.61 261.42 691 260 M 700 251 C 698.67 257.02 698.68 261.15 691 260 M 691 260 C 642.67 262.77 591.95 259.45 549 260 M 691 260 C 638.75 261 588.59 261 549 260 M 549 260 C 544.51 258.6 539.85 256.29 540 251 M 549 260 C 542.04 259.13 541.51 257.61 540 251 M 540 251 C 538.98 235.18 539.97 220.01 540 209 M 540 251 C 540.81 237.9 538.91 226.34 540 209 M 540 209 C 538.24 203.35 542.72 199.24 549 200 M 540 209 C 541.82 203.38 542.2 198.48 549 200" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="540" cy="220" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="520" y="200" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 537.85 223.53 C 537.85 223.53 537.85 223.53 537.85 223.53 M 537.85 223.53 C 537.85 223.53 537.85 223.53 537.85 223.53" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 537.16 222.84 C 537.16 222.84 537.16 222.84 537.16 222.84 M 537.16 222.84 C 537.16 222.84 537.16 222.84 537.16 222.84" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="530" cy="220" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="510" y="200" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 528.7 224.2 C 528.7 224.2 528.7 224.2 528.7 224.2 M 528.7 224.2 C 528.7 224.2 528.7 224.2 528.7 224.2 M 534.35 218.55 C 533.12 217.78 533.16 216.61 530.82 215.01 M 534.35 218.55 C 533.16 217.38 532.2 216.37 530.82 215.01" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 528.71 224.22 C 528.71 224.22 528.71 224.22 528.71 224.22 M 528.71 224.22 C 528.71 224.22 528.71 224.22 528.71 224.22 M 534.37 218.56 C 533.13 217.79 533.17 216.63 530.83 215.03 M 534.37 218.56 C 533.18 217.39 532.21 216.38 530.83 215.03" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="375" y="200" width="110" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 210px; margin-left: 430px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Grow Height by 50 </div> </div> </div> </foreignObject> - <text x="430" y="214" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="430" y="214" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Grow Height by 50 </text> </switch> @@ -131,16 +131,16 @@ <rect x="35" y="120" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 130px; margin-left: 80px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1000 </div> </div> </div> </foreignObject> - <text x="80" y="134" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="80" y="134" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1000 </text> </switch> @@ -148,172 +148,172 @@ <rect x="440" y="120" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 130px; margin-left: 485px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1000 </div> </div> </div> </foreignObject> - <text x="485" y="134" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="485" y="134" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1000 </text> </switch> </g> <rect x="1180" y="120" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1181.4 158.4 C 1181.4 158.4 1181.4 158.4 1181.4 158.4 M 1181.4 158.4 C 1181.4 158.4 1181.4 158.4 1181.4 158.4 M 1188.47 154.16 C 1187.07 152.9 1184.52 150.66 1184.23 149.92 M 1188.47 154.16 C 1186.79 152.22 1185.08 150.93 1184.23 149.92 M 1199.79 154.16 C 1194.41 147.6 1190.84 144.91 1184.23 138.6 M 1199.79 154.16 C 1194.13 148.07 1189.56 142.99 1184.23 138.6 M 1211.1 154.16 C 1198.64 141.47 1189.42 132.98 1181.4 124.46 M 1211.1 154.16 C 1203.41 146.45 1197.54 139.23 1181.4 124.46 M 1222.41 154.16 C 1210.03 138.76 1195.09 126.77 1187.06 118.8 M 1222.41 154.16 C 1213.69 146.82 1207.39 138.21 1187.06 118.8 M 1233.73 154.16 C 1221.85 141.89 1207.86 127.58 1198.37 118.8 M 1233.73 154.16 C 1220.55 141.75 1208.29 128.12 1198.37 118.8 M 1245.04 154.16 C 1232.52 143.28 1220.27 131.81 1209.68 118.8 M 1245.04 154.16 C 1233.19 142.15 1221.93 131.48 1209.68 118.8 M 1257.06 154.86 C 1243.54 143.04 1228.16 129.52 1221 118.8 M 1257.06 154.86 C 1242.86 140.02 1229.11 126.08 1221 118.8 M 1268.37 154.86 C 1260.72 144.48 1248.41 136.48 1232.31 118.8 M 1268.37 154.86 C 1257.12 145.45 1247.08 133.1 1232.31 118.8 M 1279.69 154.86 C 1271.51 146.86 1262.74 137.29 1243.63 118.8 M 1279.69 154.86 C 1270.9 145.43 1261.45 136.7 1243.63 118.8 M 1291 154.86 C 1282.63 147.37 1271.49 135.69 1254.94 118.8 M 1291 154.86 C 1280.06 143.72 1270.18 134.39 1254.94 118.8 M 1302.32 154.86 C 1295.34 145.98 1287.07 137.37 1266.25 118.8 M 1302.32 154.86 C 1289.89 143.76 1278.83 130.61 1266.25 118.8 M 1313.63 154.86 C 1306.27 145.23 1297.91 137.05 1277.57 118.8 M 1313.63 154.86 C 1305.92 147.54 1297.24 139.56 1277.57 118.8 M 1324.94 154.86 C 1315.97 142.79 1304.97 134.95 1288.88 118.8 M 1324.94 154.86 C 1318.29 147.07 1310.43 139.11 1288.88 118.8 M 1339.09 157.69 C 1326.02 145.93 1312.44 132.75 1300.19 118.8 M 1339.09 157.69 C 1326.72 144.6 1312.15 131.7 1300.19 118.8 M 1344.74 152.04 C 1334.19 139.01 1318.88 129.3 1312.22 119.51 M 1344.74 152.04 C 1333.4 140.83 1321.95 128.62 1312.22 119.51 M 1344.74 140.72 C 1337.46 131.96 1327.65 124.24 1323.53 119.51 M 1344.74 140.72 C 1340.27 135.23 1334.77 130.71 1323.53 119.51 M 1340.5 125.17 C 1338.6 124.03 1337.55 122.57 1334.84 119.51 M 1340.5 125.17 C 1339.28 123.5 1337.95 122.34 1334.84 119.51" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1186 120 M 1186 120 C 1216.4 118.38 1245.98 120.9 1334 120 M 1186 120 C 1233.22 119.74 1279.71 119.15 1334 120 M 1334 120 C 1338.59 120.07 1340.08 121.36 1340 126 M 1334 120 C 1336.18 118.55 1341.15 121.59 1340 126 M 1340 126 C 1341.98 135.88 1338.79 144.72 1340 154 M 1340 126 C 1339.26 134.17 1339.14 142.5 1340 154 M 1340 154 C 1338.51 156.64 1339.51 160.54 1334 160 M 1340 154 C 1340.95 159.63 1338.34 160.56 1334 160 M 1334 160 C 1304.43 160.07 1271.14 160.25 1186 160 M 1334 160 C 1276.37 160.01 1219.14 159.64 1186 160 M 1186 160 C 1183.57 158.6 1178.47 159.1 1180 154 M 1186 160 C 1182.14 158.34 1181.93 159.24 1180 154 M 1180 154 C 1181.85 145.99 1178.35 137.28 1180 126 M 1180 154 C 1179.39 144.39 1179.96 134.41 1180 126 M 1180 126 C 1179.87 121.4 1183.86 118.35 1186 120 M 1180 126 C 1181.92 123.97 1180.37 119.53 1186 120" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1181.41 158.41 C 1181.41 158.41 1181.41 158.41 1181.41 158.41 M 1181.41 158.41 C 1181.41 158.41 1181.41 158.41 1181.41 158.41 M 1188.48 154.17 C 1187.08 152.91 1184.53 150.68 1184.24 149.93 M 1188.48 154.17 C 1186.8 152.23 1185.1 150.94 1184.24 149.93 M 1199.8 154.17 C 1194.42 147.62 1190.85 144.92 1184.24 138.61 M 1199.8 154.17 C 1194.14 148.08 1189.57 143 1184.24 138.61 M 1211.11 154.17 C 1198.65 141.49 1189.44 133 1181.41 124.47 M 1211.11 154.17 C 1203.42 146.46 1197.55 139.24 1181.41 124.47 M 1222.43 154.17 C 1210.04 138.77 1195.1 126.78 1187.07 118.82 M 1222.43 154.17 C 1213.71 146.83 1207.41 138.23 1187.07 118.82 M 1233.74 154.17 C 1221.86 141.9 1207.87 127.59 1198.38 118.82 M 1233.74 154.17 C 1220.56 141.76 1208.3 128.13 1198.38 118.82 M 1245.05 154.17 C 1232.54 143.3 1220.29 131.83 1209.7 118.82 M 1245.05 154.17 C 1233.2 142.17 1221.94 131.49 1209.7 118.82 M 1256.37 154.17 C 1243.11 142.61 1228 129.36 1221.01 118.82 M 1256.37 154.17 C 1242.45 139.6 1228.97 125.93 1221.01 118.82 M 1268.39 154.88 C 1260.73 144.49 1248.42 136.49 1232.32 118.82 M 1268.39 154.88 C 1257.13 145.46 1247.1 133.12 1232.32 118.82 M 1279.7 154.88 C 1271.52 146.87 1262.75 137.31 1243.64 118.82 M 1279.7 154.88 C 1270.92 145.44 1261.46 136.71 1243.64 118.82 M 1291.01 154.88 C 1282.64 147.38 1271.5 135.71 1254.95 118.82 M 1291.01 154.88 C 1280.07 143.73 1270.19 134.41 1254.95 118.82 M 1302.33 154.88 C 1295.35 145.99 1287.09 137.39 1266.27 118.82 M 1302.33 154.88 C 1289.9 143.77 1278.84 130.62 1266.27 118.82 M 1313.64 154.88 C 1306.29 145.24 1297.93 137.06 1277.58 118.82 M 1313.64 154.88 C 1305.93 147.55 1297.26 139.58 1277.58 118.82 M 1324.96 154.88 C 1315.98 142.81 1304.99 134.96 1288.89 118.82 M 1324.96 154.88 C 1318.31 147.08 1310.44 139.12 1288.89 118.82 M 1339.1 157.71 C 1326.04 145.94 1312.45 132.77 1300.21 118.82 M 1339.1 157.71 C 1326.74 144.61 1312.17 131.71 1300.21 118.82 M 1344.75 152.05 C 1334.21 139.02 1318.89 129.31 1312.23 119.52 M 1344.75 152.05 C 1333.41 140.85 1321.96 128.63 1312.23 119.52 M 1344.75 140.74 C 1337.47 131.98 1327.66 124.25 1323.54 119.52 M 1344.75 140.74 C 1340.28 135.25 1334.78 130.73 1323.54 119.52 M 1340.51 125.18 C 1338.62 124.04 1337.57 122.58 1334.86 119.52 M 1340.51 125.18 C 1339.29 123.51 1337.97 122.35 1334.86 119.52" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1186 120 M 1186 120 C 1216.4 118.38 1245.98 120.9 1334 120 M 1186 120 C 1233.22 119.74 1279.71 119.15 1334 120 M 1334 120 C 1338.59 120.07 1340.08 121.36 1340 126 M 1334 120 C 1336.18 118.55 1341.15 121.59 1340 126 M 1340 126 C 1341.98 135.88 1338.79 144.72 1340 154 M 1340 126 C 1339.26 134.17 1339.14 142.5 1340 154 M 1340 154 C 1338.51 156.64 1339.51 160.54 1334 160 M 1340 154 C 1340.95 159.63 1338.34 160.56 1334 160 M 1334 160 C 1304.43 160.07 1271.14 160.25 1186 160 M 1334 160 C 1276.37 160.01 1219.14 159.64 1186 160 M 1186 160 C 1183.57 158.6 1178.47 159.1 1180 154 M 1186 160 C 1182.14 158.34 1181.93 159.24 1180 154 M 1180 154 C 1181.85 145.99 1178.35 137.28 1180 126 M 1180 154 C 1179.39 144.39 1179.96 134.41 1180 126 M 1180 126 C 1179.87 121.4 1183.86 118.35 1186 120 M 1180 126 C 1181.92 123.97 1180.37 119.53 1186 120" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="250" y="250" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 251.18 288.18 C 251.18 288.18 251.18 288.18 251.18 288.18 M 251.18 288.18 C 251.18 288.18 251.18 288.18 251.18 288.18 M 258.96 284.64 C 257.99 283.48 256.04 281.29 254.01 279.69 M 258.96 284.64 C 257.49 283.21 255.64 281.12 254.01 279.69 M 270.27 284.64 C 262.14 279.1 259.27 272.81 254.01 268.38 M 270.27 284.64 C 264.11 280.05 259.02 275.23 254.01 268.38 M 281.58 284.64 C 275.57 275.39 266.93 270.97 251.18 254.24 M 281.58 284.64 C 276.48 278.96 269.04 273.25 251.18 254.24 M 292.9 284.64 C 283.72 273.65 271.93 265.38 256.83 248.58 M 292.9 284.64 C 280.67 273.81 269.48 261.92 256.83 248.58 M 304.21 284.64 C 290.56 272.75 278.85 262.68 268.15 248.58 M 304.21 284.64 C 296.09 276.85 287.19 268.64 268.15 248.58 M 315.52 284.64 C 308.09 277.9 301.75 271.14 279.46 248.58 M 315.52 284.64 C 307.62 275.03 298.25 267.36 279.46 248.58 M 326.84 284.64 C 314.1 271.79 302 259.96 291.48 249.29 M 326.84 284.64 C 316.55 274.58 305.53 261.7 291.48 249.29 M 338.15 284.64 C 325.89 270.07 311.58 260.23 302.8 249.29 M 338.15 284.64 C 327.66 274.9 317.81 264.93 302.8 249.29 M 349.47 284.64 C 340.2 276.24 333.89 268.78 314.11 249.29 M 349.47 284.64 C 339.58 273.83 329.95 265.11 314.11 249.29 M 360.78 284.64 C 352.62 276.77 347.18 271.23 325.42 249.29 M 360.78 284.64 C 348.31 273.1 337.24 261.28 325.42 249.29 M 372.09 284.64 C 364.91 278.29 355.07 270.52 336.74 249.29 M 372.09 284.64 C 362.31 274.6 353.58 264.82 336.74 249.29 M 383.41 284.64 C 373.48 278.49 367.3 269.91 348.05 249.29 M 383.41 284.64 C 374.39 275.59 364.51 265.86 348.05 249.29 M 394.72 284.64 C 383.6 273.7 367.8 258.56 359.37 249.29 M 394.72 284.64 C 382.75 272.89 373.24 262.48 359.37 249.29 M 408.86 287.47 C 395.87 273.13 383.78 260.32 370.68 249.29 M 408.86 287.47 C 396.19 275.68 386.5 264 370.68 249.29 M 414.52 281.81 C 402.64 271.55 393.3 261.58 381.99 249.29 M 414.52 281.81 C 402.79 271.61 392.96 259.05 381.99 249.29 M 414.52 270.5 C 405.09 261.83 397.63 255.03 393.31 249.29 M 414.52 270.5 C 409.86 265.84 404.09 259.29 393.31 249.29 M 410.98 255.65 C 407.75 253.31 405.9 251.85 404.62 249.29 M 410.98 255.65 C 409.11 254.23 407.58 252.85 404.62 249.29" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 256 250 M 256 250 C 303.69 250.64 348.15 248.49 404 250 M 256 250 C 290.82 248.83 326.3 250.52 404 250 M 404 250 C 408.56 249.57 408.45 250.31 410 256 M 404 250 C 408.65 251.16 411.34 253.36 410 256 M 410 256 C 409.07 262.38 408.05 266.28 410 284 M 410 256 C 409.44 267.4 410.86 277.32 410 284 M 410 284 C 408.89 286.86 408.2 291.94 404 290 M 410 284 C 410.68 286.55 406.57 290.22 404 290 M 404 290 C 370.51 289.58 331.14 289.23 256 290 M 404 290 C 364.44 289.72 324.67 287.76 256 290 M 256 290 C 251.18 288.29 248.77 288.16 250 284 M 256 290 C 250.7 287.99 250.63 290.23 250 284 M 250 284 C 250.96 276.81 248.77 271.5 250 256 M 250 284 C 250.63 275.34 249.24 265.19 250 256 M 250 256 C 251.79 251.63 251.32 249.08 256 250 M 250 256 C 250.75 251.59 253.36 250.25 256 250" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <rect x="1050" y="100" width="200" height="280" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="1052" y="102" width="196" height="276" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <path d="M 251.19 288.19 C 251.19 288.19 251.19 288.19 251.19 288.19 M 251.19 288.19 C 251.19 288.19 251.19 288.19 251.19 288.19 M 258.97 284.66 C 258 283.49 256.06 281.3 254.02 279.71 M 258.97 284.66 C 257.5 283.22 255.66 281.13 254.02 279.71 M 270.28 284.66 C 262.16 279.12 259.28 272.82 254.02 268.39 M 270.28 284.66 C 264.12 280.07 259.03 275.24 254.02 268.39 M 281.6 284.66 C 275.59 275.4 266.95 270.99 251.19 254.25 M 281.6 284.66 C 276.49 278.97 269.06 273.26 251.19 254.25 M 292.91 284.66 C 283.74 273.66 271.94 265.39 256.85 248.59 M 292.91 284.66 C 280.68 273.83 269.49 261.93 256.85 248.59 M 304.22 284.66 C 290.57 272.76 278.87 262.69 268.16 248.59 M 304.22 284.66 C 296.11 276.87 287.2 268.66 268.16 248.59 M 315.54 284.66 C 308.1 277.91 301.76 271.16 279.48 248.59 M 315.54 284.66 C 307.64 275.04 298.26 267.37 279.48 248.59 M 326.85 284.66 C 314.12 271.8 302.02 259.97 291.5 249.3 M 326.85 284.66 C 316.56 274.59 305.54 261.71 291.5 249.3 M 338.16 284.66 C 325.9 270.08 311.59 260.24 302.81 249.3 M 338.16 284.66 C 327.68 274.91 317.83 264.95 302.81 249.3 M 349.48 284.66 C 340.21 276.25 333.91 268.79 314.12 249.3 M 349.48 284.66 C 339.6 273.84 329.96 265.12 314.12 249.3 M 360.79 284.66 C 352.63 276.78 347.19 271.25 325.44 249.3 M 360.79 284.66 C 348.32 273.11 337.25 261.29 325.44 249.3 M 372.11 284.66 C 364.92 278.3 355.08 270.53 336.75 249.3 M 372.11 284.66 C 362.32 274.62 353.6 264.83 336.75 249.3 M 383.42 284.66 C 373.49 278.5 367.31 269.92 348.06 249.3 M 383.42 284.66 C 374.41 275.6 364.52 265.87 348.06 249.3 M 394.73 284.66 C 383.61 273.71 367.81 258.57 359.38 249.3 M 394.73 284.66 C 382.76 272.9 373.26 262.49 359.38 249.3 M 408.88 287.48 C 395.89 273.15 383.79 260.33 370.69 249.3 M 408.88 287.48 C 396.21 275.69 386.52 264.02 370.69 249.3 M 414.53 281.83 C 402.65 271.56 393.32 261.59 382.01 249.3 M 414.53 281.83 C 402.8 271.63 392.97 259.06 382.01 249.3 M 414.53 270.51 C 405.1 261.84 397.64 255.05 393.32 249.3 M 414.53 270.51 C 409.87 265.85 404.1 259.3 393.32 249.3 M 411 255.66 C 407.77 253.33 405.92 251.86 404.63 249.3 M 411 255.66 C 409.12 254.24 407.59 252.87 404.63 249.3" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 256 250 M 256 250 C 303.69 250.64 348.15 248.49 404 250 M 256 250 C 290.82 248.83 326.3 250.52 404 250 M 404 250 C 408.56 249.57 408.45 250.31 410 256 M 404 250 C 408.65 251.16 411.34 253.36 410 256 M 410 256 C 409.07 262.38 408.05 266.28 410 284 M 410 256 C 409.44 267.4 410.86 277.32 410 284 M 410 284 C 408.89 286.86 408.2 291.94 404 290 M 410 284 C 410.68 286.55 406.57 290.22 404 290 M 404 290 C 370.51 289.58 331.14 289.23 256 290 M 404 290 C 364.44 289.72 324.67 287.76 256 290 M 256 290 C 251.18 288.29 248.77 288.16 250 284 M 256 290 C 250.7 287.99 250.63 290.23 250 284 M 250 284 C 250.96 276.81 248.77 271.5 250 256 M 250 284 C 250.63 275.34 249.24 265.19 250 256 M 250 256 C 251.79 251.63 251.32 249.08 256 250 M 250 256 C 250.75 251.59 253.36 250.25 256 250" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <rect x="1050" y="100" width="200" height="280" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="1052" y="102" width="196" height="276" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="1050" y="70" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 80px; margin-left: 1110px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="1110" y="84" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1110" y="84" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> </g> <rect x="1070" y="300" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1071.76 338.76 C 1071.76 338.76 1071.76 338.76 1071.76 338.76 M 1071.76 338.76 C 1071.76 338.76 1071.76 338.76 1071.76 338.76 M 1078.83 334.51 C 1077.01 332.27 1075.53 330.89 1073.88 329.56 M 1078.83 334.51 C 1077.73 333.13 1076.09 331.8 1073.88 329.56 M 1090.14 334.51 C 1085.42 327.62 1076.79 321.95 1073.88 318.25 M 1090.14 334.51 C 1085.93 329.14 1079.79 323.95 1073.88 318.25 M 1101.45 334.51 C 1091.77 322.44 1081.78 314.29 1071.76 304.81 M 1101.45 334.51 C 1093.63 327.89 1086.25 319.86 1071.76 304.81 M 1112.77 334.51 C 1102.42 321.84 1090.1 312.28 1077.41 299.16 M 1112.77 334.51 C 1105.71 326.25 1097.8 319.4 1077.41 299.16 M 1124.08 334.51 C 1112.12 325.29 1104.37 315.42 1088.73 299.16 M 1124.08 334.51 C 1116.74 327.69 1109.62 320.57 1088.73 299.16 M 1135.4 334.51 C 1127.16 324.97 1120.51 315.9 1100.04 299.16 M 1135.4 334.51 C 1124.55 325.08 1115.76 315.14 1100.04 299.16 M 1146.71 334.51 C 1133.53 319.63 1118.86 307.46 1111.35 299.16 M 1146.71 334.51 C 1137.85 325.98 1127.72 315.13 1111.35 299.16 M 1158.02 334.51 C 1147.27 326.03 1138.52 312.77 1122.67 299.16 M 1158.02 334.51 C 1146.64 322.08 1134.34 311.56 1122.67 299.16 M 1169.34 334.51 C 1154.77 320.9 1142.47 310.32 1133.98 299.16 M 1169.34 334.51 C 1155.28 322.14 1143.15 307.71 1133.98 299.16 M 1180.65 334.51 C 1173.6 327.6 1165.54 316.09 1145.29 299.16 M 1180.65 334.51 C 1170.32 322.86 1158.03 311.87 1145.29 299.16 M 1191.96 334.51 C 1182.18 324.96 1172.96 317.36 1156.61 299.16 M 1191.96 334.51 C 1181.08 323.27 1169.85 313.75 1156.61 299.16 M 1203.28 334.51 C 1194.54 325.58 1188.03 319.88 1167.92 299.16 M 1203.28 334.51 C 1192.97 323.32 1181.93 313.19 1167.92 299.16 M 1214.59 334.51 C 1200.57 322.64 1186.53 308.87 1179.24 299.16 M 1214.59 334.51 C 1203.4 321.36 1190.86 310.58 1179.24 299.16 M 1229.44 338.05 C 1223.37 330.33 1214.22 321.54 1190.55 299.16 M 1229.44 338.05 C 1214.57 322.19 1199.04 306.71 1190.55 299.16 M 1234.39 331.68 C 1223.35 319.7 1207.47 307.54 1201.86 299.16 M 1234.39 331.68 C 1222.76 318.74 1209.92 306.25 1201.86 299.16 M 1234.39 320.37 C 1228.46 311.89 1221.55 308.22 1213.18 299.16 M 1234.39 320.37 C 1227.48 313.7 1219.06 305.48 1213.18 299.16 M 1230.85 305.52 C 1228.53 302.32 1225.34 300.05 1224.49 299.16 M 1230.85 305.52 C 1229.36 304.07 1228.13 302.82 1224.49 299.16" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1076 300 M 1076 300 C 1125.9 300.04 1175.7 300.93 1224 300 M 1076 300 C 1134.82 300.44 1192.42 300.64 1224 300 M 1224 300 C 1229.46 298.96 1228.47 300.45 1230 306 M 1224 300 C 1227.28 298.18 1230.72 299.82 1230 306 M 1230 306 C 1227.83 314.41 1228.72 320.7 1230 334 M 1230 306 C 1230.07 314.32 1229.3 325.18 1230 334 M 1230 334 C 1230.01 338.07 1226.26 339.38 1224 340 M 1230 334 C 1230.83 338.78 1228.06 340.92 1224 340 M 1224 340 C 1191.8 340.86 1157.58 338.13 1076 340 M 1224 340 C 1194.14 339.89 1165.07 339.48 1076 340 M 1076 340 C 1073.4 341.13 1068.6 338.24 1070 334 M 1076 340 C 1069.97 338.7 1070.33 336.1 1070 334 M 1070 334 C 1070.12 326.88 1071.2 318 1070 306 M 1070 334 C 1070.58 324.37 1070.49 314.32 1070 306 M 1070 306 C 1070.72 300.17 1071.4 299.56 1076 300 M 1070 306 C 1068.84 303.93 1074.26 301.38 1076 300" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1071.77 338.77 C 1071.77 338.77 1071.77 338.77 1071.77 338.77 M 1071.77 338.77 C 1071.77 338.77 1071.77 338.77 1071.77 338.77 M 1078.84 334.53 C 1077.02 332.28 1075.55 330.9 1073.89 329.58 M 1078.84 334.53 C 1077.75 333.14 1076.11 331.81 1073.89 329.58 M 1090.15 334.53 C 1085.44 327.64 1076.8 321.97 1073.89 318.26 M 1090.15 334.53 C 1085.94 329.15 1079.8 323.96 1073.89 318.26 M 1101.47 334.53 C 1091.78 322.45 1081.8 314.3 1071.77 304.83 M 1101.47 334.53 C 1093.64 327.9 1086.26 319.87 1071.77 304.83 M 1112.78 334.53 C 1102.44 321.85 1090.11 312.29 1077.43 299.17 M 1112.78 334.53 C 1105.73 326.26 1097.81 319.42 1077.43 299.17 M 1124.09 334.53 C 1112.13 325.3 1104.39 315.44 1088.74 299.17 M 1124.09 334.53 C 1116.75 327.7 1109.64 320.58 1088.74 299.17 M 1135.41 334.53 C 1127.18 324.98 1120.52 315.91 1100.05 299.17 M 1135.41 334.53 C 1124.56 325.09 1115.77 315.16 1100.05 299.17 M 1146.72 334.53 C 1133.54 319.65 1118.88 307.47 1111.37 299.17 M 1146.72 334.53 C 1137.86 325.99 1127.73 315.15 1111.37 299.17 M 1158.04 334.53 C 1147.29 326.04 1138.53 312.78 1122.68 299.17 M 1158.04 334.53 C 1146.65 322.09 1134.35 311.57 1122.68 299.17 M 1169.35 334.53 C 1154.78 320.91 1142.49 310.33 1133.99 299.17 M 1169.35 334.53 C 1155.29 322.16 1143.16 307.73 1133.99 299.17 M 1180.66 334.53 C 1173.61 327.62 1165.55 316.11 1145.31 299.17 M 1180.66 334.53 C 1170.33 322.87 1158.04 311.89 1145.31 299.17 M 1191.98 334.53 C 1182.19 324.97 1172.97 317.37 1156.62 299.17 M 1191.98 334.53 C 1181.09 323.28 1169.86 313.76 1156.62 299.17 M 1203.29 334.53 C 1194.55 325.59 1188.04 319.89 1167.94 299.17 M 1203.29 334.53 C 1192.98 323.34 1181.94 313.2 1167.94 299.17 M 1214.6 334.53 C 1200.58 322.65 1186.54 308.88 1179.25 299.17 M 1214.6 334.53 C 1203.42 321.37 1190.87 310.6 1179.25 299.17 M 1229.45 338.06 C 1223.38 330.34 1214.23 321.55 1190.56 299.17 M 1229.45 338.06 C 1214.59 322.2 1199.05 306.72 1190.56 299.17 M 1234.4 331.7 C 1223.37 319.71 1207.49 307.55 1201.88 299.17 M 1234.4 331.7 C 1222.77 318.75 1209.93 306.27 1201.88 299.17 M 1234.4 320.38 C 1228.47 311.91 1221.56 308.23 1213.19 299.17 M 1234.4 320.38 C 1227.49 313.71 1219.07 305.49 1213.19 299.17 M 1230.87 305.53 C 1228.54 302.34 1225.35 300.07 1224.5 299.17 M 1230.87 305.53 C 1229.37 304.09 1228.14 302.83 1224.5 299.17" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1076 300 M 1076 300 C 1125.9 300.04 1175.7 300.93 1224 300 M 1076 300 C 1134.82 300.44 1192.42 300.64 1224 300 M 1224 300 C 1229.46 298.96 1228.47 300.45 1230 306 M 1224 300 C 1227.28 298.18 1230.72 299.82 1230 306 M 1230 306 C 1227.83 314.41 1228.72 320.7 1230 334 M 1230 306 C 1230.07 314.32 1229.3 325.18 1230 334 M 1230 334 C 1230.01 338.07 1226.26 339.38 1224 340 M 1230 334 C 1230.83 338.78 1228.06 340.92 1224 340 M 1224 340 C 1191.8 340.86 1157.58 338.13 1076 340 M 1224 340 C 1194.14 339.89 1165.07 339.48 1076 340 M 1076 340 C 1073.4 341.13 1068.6 338.24 1070 334 M 1076 340 C 1069.97 338.7 1070.33 336.1 1070 334 M 1070 334 C 1070.12 326.88 1071.2 318 1070 306 M 1070 334 C 1070.58 324.37 1070.49 314.32 1070 306 M 1070 306 C 1070.72 300.17 1071.4 299.56 1076 300 M 1070 306 C 1068.84 303.93 1074.26 301.38 1076 300" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1070" y="180" width="160" height="60" rx="9" ry="9" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1072.3 237.8 C 1072.3 237.8 1072.3 237.8 1072.3 237.8 M 1072.3 237.8 C 1072.3 237.8 1072.3 237.8 1072.3 237.8 M 1080.08 234.27 C 1077.27 232.1 1074.64 229.5 1073.72 227.9 M 1080.08 234.27 C 1078.47 232.57 1076.93 230.92 1073.72 227.9 M 1091.39 234.27 C 1086.26 228.36 1079.77 224.36 1073.72 216.59 M 1091.39 234.27 C 1085.03 227.89 1078.74 222.41 1073.72 216.59 M 1102.71 234.27 C 1093.7 224.18 1086.21 215.8 1073.72 205.27 M 1102.71 234.27 C 1091.62 223.39 1080.19 210.98 1073.72 205.27 M 1114.02 234.27 C 1097.18 218.86 1085.1 202.49 1073.72 193.96 M 1114.02 234.27 C 1100.76 221.05 1087.84 208.05 1073.72 193.96 M 1125.33 234.27 C 1105.58 213.98 1085.42 193.25 1073.01 181.94 M 1125.33 234.27 C 1105.13 215.58 1086.9 194.68 1073.01 181.94 M 1136.65 234.27 C 1119.54 215.89 1101.36 200.49 1080.79 178.4 M 1136.65 234.27 C 1122.31 219.35 1104.87 203.34 1080.79 178.4 M 1147.96 234.27 C 1127.56 213.17 1107.41 192.67 1092.1 178.4 M 1147.96 234.27 C 1134.77 220.44 1120.67 209 1092.1 178.4 M 1159.98 234.97 C 1139.99 215.68 1123.17 196.15 1103.41 178.4 M 1159.98 234.97 C 1146.43 220.29 1131.8 205.46 1103.41 178.4 M 1171.3 234.97 C 1154.49 219.13 1138.62 203.59 1114.73 178.4 M 1171.3 234.97 C 1148.99 213.12 1126.9 190.97 1114.73 178.4 M 1182.61 234.97 C 1168.16 220.91 1154.83 206.41 1126.04 178.4 M 1182.61 234.97 C 1165.23 217.54 1148.15 198.96 1126.04 178.4 M 1193.92 234.97 C 1169.31 213.83 1149.06 189.69 1137.36 178.4 M 1193.92 234.97 C 1176.36 218.99 1159.73 201.51 1137.36 178.4 M 1205.24 234.97 C 1191.53 222.02 1178.15 205.61 1148.67 178.4 M 1205.24 234.97 C 1184.59 215.01 1162.15 192.52 1148.67 178.4 M 1221.5 239.92 C 1204.79 221.91 1189.31 205.97 1159.98 178.4 M 1221.5 239.92 C 1199.26 215.81 1175.62 193.41 1159.98 178.4 M 1229.28 236.39 C 1217.18 221.02 1203.71 210.88 1171.3 178.4 M 1229.28 236.39 C 1214.27 221.49 1200.58 207.44 1171.3 178.4 M 1234.23 230.02 C 1218.07 217.37 1203.81 200.35 1182.61 178.4 M 1234.23 230.02 C 1218.99 213.74 1202.8 199.69 1182.61 178.4 M 1234.23 218.71 C 1222.78 208.79 1211.84 197.37 1193.92 178.4 M 1234.23 218.71 C 1221.22 204.35 1207.67 190.8 1193.92 178.4 M 1234.23 207.4 C 1223.16 198.13 1211.26 184.04 1205.94 179.11 M 1234.23 207.4 C 1225.9 198.77 1217.75 191.44 1205.94 179.11 M 1234.94 196.79 C 1226.47 190.2 1222.22 183.06 1217.26 179.11 M 1234.94 196.79 C 1227.72 191.41 1221.72 183.91 1217.26 179.11" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1079 180 M 1079 180 C 1118.55 179.57 1160.99 181.49 1221 180 M 1079 180 C 1111.83 179.2 1145.56 178.65 1221 180 M 1221 180 C 1227.74 181.59 1228.81 181.81 1230 189 M 1221 180 C 1228.84 181.44 1231.99 181.61 1230 189 M 1230 189 C 1229.39 205.21 1229.79 219.03 1230 231 M 1230 189 C 1230.09 200.56 1228.78 214.33 1230 231 M 1230 231 C 1230.74 236.1 1228.58 240.22 1221 240 M 1230 231 C 1230.04 236.26 1225.68 239.45 1221 240 M 1221 240 C 1184 239.79 1146.9 240.97 1079 240 M 1221 240 C 1173.75 238.29 1126.88 238.91 1079 240 M 1079 240 C 1074.22 240.64 1071.24 235.09 1070 231 M 1079 240 C 1072.14 241.52 1072.02 236.73 1070 231 M 1070 231 C 1071.69 215.76 1069.49 203.67 1070 189 M 1070 231 C 1070.9 220.97 1069.24 212.27 1070 189 M 1070 189 C 1068.9 181.3 1072.28 179.25 1079 180 M 1070 189 C 1067.71 184.31 1074.24 179.02 1079 180" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1072.31 237.81 C 1072.31 237.81 1072.31 237.81 1072.31 237.81 M 1072.31 237.81 C 1072.31 237.81 1072.31 237.81 1072.31 237.81 M 1080.09 234.28 C 1077.28 232.11 1074.65 229.51 1073.73 227.91 M 1080.09 234.28 C 1078.48 232.58 1076.94 230.94 1073.73 227.91 M 1091.41 234.28 C 1086.27 228.38 1079.78 224.37 1073.73 216.6 M 1091.41 234.28 C 1085.04 227.9 1078.75 222.43 1073.73 216.6 M 1102.72 234.28 C 1093.71 224.2 1086.22 215.82 1073.73 205.29 M 1102.72 234.28 C 1091.63 223.41 1080.2 210.99 1073.73 205.29 M 1114.03 234.28 C 1097.19 218.87 1085.11 202.5 1073.73 193.97 M 1114.03 234.28 C 1100.77 221.06 1087.85 208.06 1073.73 193.97 M 1125.35 234.28 C 1105.59 213.99 1085.43 193.26 1073.02 181.95 M 1125.35 234.28 C 1105.14 215.59 1086.91 194.69 1073.02 181.95 M 1136.66 234.28 C 1119.56 215.91 1101.37 200.5 1080.8 178.42 M 1136.66 234.28 C 1122.32 219.36 1104.88 203.35 1080.8 178.42 M 1147.97 234.28 C 1127.57 213.18 1107.42 192.68 1092.11 178.42 M 1147.97 234.28 C 1134.78 220.46 1120.68 209.01 1092.11 178.42 M 1160 234.99 C 1140 215.69 1123.19 196.16 1103.43 178.42 M 1160 234.99 C 1146.44 220.31 1131.81 205.47 1103.43 178.42 M 1171.31 234.99 C 1154.51 219.14 1138.63 203.6 1114.74 178.42 M 1171.31 234.99 C 1149 213.13 1126.91 190.99 1114.74 178.42 M 1182.62 234.99 C 1168.17 220.93 1154.85 206.42 1126.05 178.42 M 1182.62 234.99 C 1165.24 217.55 1148.17 198.97 1126.05 178.42 M 1193.94 234.99 C 1169.32 213.85 1149.07 189.7 1137.37 178.42 M 1193.94 234.99 C 1176.37 219 1159.74 201.52 1137.37 178.42 M 1205.25 234.99 C 1191.54 222.03 1178.16 205.62 1148.68 178.42 M 1205.25 234.99 C 1184.61 215.02 1162.16 192.53 1148.68 178.42 M 1221.51 239.94 C 1204.81 221.93 1189.32 205.98 1160 178.42 M 1221.51 239.94 C 1199.27 215.82 1175.64 193.42 1160 178.42 M 1229.29 236.4 C 1217.2 221.03 1203.72 210.89 1171.31 178.42 M 1229.29 236.4 C 1214.28 221.51 1200.59 207.45 1171.31 178.42 M 1234.24 230.04 C 1218.09 217.38 1203.82 200.37 1182.62 178.42 M 1234.24 230.04 C 1219 213.75 1202.81 199.7 1182.62 178.42 M 1234.24 218.72 C 1222.8 208.8 1211.86 197.38 1193.94 178.42 M 1234.24 218.72 C 1221.24 204.37 1207.68 190.81 1193.94 178.42 M 1234.24 207.41 C 1223.17 198.14 1211.28 184.05 1205.96 179.12 M 1234.24 207.41 C 1225.91 198.78 1217.76 191.46 1205.96 179.12 M 1234.95 196.8 C 1226.48 190.21 1222.23 183.07 1217.27 179.12 M 1234.95 196.8 C 1227.73 191.43 1221.73 183.92 1217.27 179.12" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1079 180 M 1079 180 C 1118.55 179.57 1160.99 181.49 1221 180 M 1079 180 C 1111.83 179.2 1145.56 178.65 1221 180 M 1221 180 C 1227.74 181.59 1228.81 181.81 1230 189 M 1221 180 C 1228.84 181.44 1231.99 181.61 1230 189 M 1230 189 C 1229.39 205.21 1229.79 219.03 1230 231 M 1230 189 C 1230.09 200.56 1228.78 214.33 1230 231 M 1230 231 C 1230.74 236.1 1228.58 240.22 1221 240 M 1230 231 C 1230.04 236.26 1225.68 239.45 1221 240 M 1221 240 C 1184 239.79 1146.9 240.97 1079 240 M 1221 240 C 1173.75 238.29 1126.88 238.91 1079 240 M 1079 240 C 1074.22 240.64 1071.24 235.09 1070 231 M 1079 240 C 1072.14 241.52 1072.02 236.73 1070 231 M 1070 231 C 1071.69 215.76 1069.49 203.67 1070 189 M 1070 231 C 1070.9 220.97 1069.24 212.27 1070 189 M 1070 189 C 1068.9 181.3 1072.28 179.25 1079 180 M 1070 189 C 1067.71 184.31 1074.24 179.02 1079 180" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1070" cy="200" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1050" y="180" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1067.66 202.85 C 1067.66 202.85 1067.66 202.85 1067.66 202.85 M 1067.66 202.85 C 1067.66 202.85 1067.66 202.85 1067.66 202.85 M 1074.73 198.61 C 1073.27 197.42 1073.08 196.87 1070.48 194.36 M 1074.73 198.61 C 1073.49 197.5 1073.07 196.54 1070.48 194.36" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1067.67 202.86 C 1067.67 202.86 1067.67 202.86 1067.67 202.86 M 1067.67 202.86 C 1067.67 202.86 1067.67 202.86 1067.67 202.86 M 1074.74 198.62 C 1073.28 197.43 1073.1 196.88 1070.5 194.38 M 1074.74 198.62 C 1073.5 197.51 1073.08 196.55 1070.5 194.38" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1060" cy="200" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1040" y="180" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1056.99 203.62 C 1056.99 203.62 1056.99 203.62 1056.99 203.62 M 1056.99 203.62 C 1056.99 203.62 1056.99 203.62 1056.99 203.62 M 1064.06 199.37 C 1063.33 198.29 1062.05 197.17 1059.82 195.13 M 1064.06 199.37 C 1062.78 198.23 1061.77 197.06 1059.82 195.13" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1057 203.63 C 1057 203.63 1057 203.63 1057 203.63 M 1057 203.63 C 1057 203.63 1057 203.63 1057 203.63 M 1064.07 199.39 C 1063.35 198.3 1062.06 197.18 1059.83 195.14 M 1064.07 199.39 C 1062.8 198.24 1061.79 197.07 1059.83 195.14" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="960" y="100" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 110px; margin-left: 1005px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1050 </div> </div> </div> </foreignObject> - <text x="1005" y="114" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1005" y="114" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1050 </text> </switch> </g> - <rect x="120" y="120" width="200" height="260" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="122" y="122" width="196" height="256" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <rect x="120" y="120" width="200" height="260" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="122" y="122" width="196" height="256" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="140" y="200" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 141.27 238.27 C 141.27 238.27 141.27 238.27 141.27 238.27 M 141.27 238.27 C 141.27 238.27 141.27 238.27 141.27 238.27 M 148.35 234.03 C 148 233.38 146.47 231.64 144.1 229.79 M 148.35 234.03 C 147.37 232.56 145.95 231.75 144.1 229.79 M 159.66 234.03 C 156.74 228.82 150.28 225.22 144.1 218.48 M 159.66 234.03 C 154.43 228.15 149.5 223.52 144.1 218.48 M 171.68 234.74 C 161.71 225.94 154.25 216.34 141.27 204.33 M 171.68 234.74 C 163.78 227.87 157.08 221.17 141.27 204.33 M 182.99 234.74 C 170.94 220.55 156.02 207.54 146.93 198.68 M 182.99 234.74 C 170.69 222.31 158.59 210.86 146.93 198.68 M 194.31 234.74 C 181.98 221.91 167.38 204.65 158.25 198.68 M 194.31 234.74 C 183.85 225.05 174.15 214.72 158.25 198.68 M 205.62 234.74 C 195.61 225.32 185.81 214.75 169.56 198.68 M 205.62 234.74 C 192.48 221.33 177.86 205.67 169.56 198.68 M 216.94 234.74 C 205.59 222.29 196.94 213.05 180.87 198.68 M 216.94 234.74 C 205.06 223.63 192.76 211.13 180.87 198.68 M 228.25 234.74 C 219.02 224.93 210.81 219.19 192.19 198.68 M 228.25 234.74 C 219.65 225.64 209.52 215.43 192.19 198.68 M 239.56 234.74 C 233.39 225.78 222.7 216.86 203.5 198.68 M 239.56 234.74 C 225.54 220.69 211.4 207.5 203.5 198.68 M 250.88 234.74 C 237.82 222.11 229.74 213.39 215.52 199.38 M 250.88 234.74 C 237.08 222.08 223.75 208.9 215.52 199.38 M 262.19 234.74 C 254.32 226.42 247.05 221.24 226.83 199.38 M 262.19 234.74 C 247.77 220.71 233.88 207.26 226.83 199.38 M 273.5 234.74 C 260.97 222.86 249.26 212.7 238.15 199.38 M 273.5 234.74 C 260.95 222.56 247.83 207.78 238.15 199.38 M 284.82 234.74 C 273.12 223.17 261.21 213.34 249.46 199.38 M 284.82 234.74 C 275.37 225.21 265.55 215.37 249.46 199.38 M 298.96 237.57 C 289.67 228.65 281.98 217.71 260.78 199.38 M 298.96 237.57 C 286.18 224.83 272.97 212.74 260.78 199.38 M 304.62 231.91 C 293.55 218.36 281.43 205.65 272.09 199.38 M 304.62 231.91 C 296.76 223.95 289.32 215.69 272.09 199.38 M 304.62 220.6 C 301.24 215.37 293.33 212.11 283.4 199.38 M 304.62 220.6 C 296.53 212.82 288.05 203.51 283.4 199.38 M 300.37 205.04 C 299.12 203.5 297.43 201.71 294.72 199.38 M 300.37 205.04 C 298.82 203.18 297.55 201.8 294.72 199.38" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 146 200 M 146 200 C 196.64 199.38 244.33 198.33 294 200 M 146 200 C 188.93 199.65 233.4 199.66 294 200 M 294 200 C 298.81 198.16 299.27 202.45 300 206 M 294 200 C 296.39 201.21 300.07 200.75 300 206 M 300 206 C 299.51 211.28 301.26 221.15 300 234 M 300 206 C 300.28 214.35 300.33 220.95 300 234 M 300 234 C 300.36 236.77 298.12 241.11 294 240 M 300 234 C 299.66 237.97 296.65 238.61 294 240 M 294 240 C 247.38 241.09 203.49 242.67 146 240 M 294 240 C 262.36 240.55 233.1 240.58 146 240 M 146 240 C 140.27 240.34 140.94 239.44 140 234 M 146 240 C 141.27 238.38 140.12 239.53 140 234 M 140 234 C 139.68 223.3 140.18 213.46 140 206 M 140 234 C 140.27 223.69 139.38 213.27 140 206 M 140 206 C 140.39 203.55 141.07 200.04 146 200 M 140 206 C 138.33 203.53 142.7 198.45 146 200" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 141.29 238.29 C 141.29 238.29 141.29 238.29 141.29 238.29 M 141.29 238.29 C 141.29 238.29 141.29 238.29 141.29 238.29 M 148.36 234.05 C 148.02 233.4 146.48 231.65 144.12 229.8 M 148.36 234.05 C 147.38 232.58 145.96 231.76 144.12 229.8 M 159.67 234.05 C 156.75 228.84 150.29 225.23 144.12 218.49 M 159.67 234.05 C 154.44 228.17 149.52 223.53 144.12 218.49 M 171.69 234.75 C 161.73 225.95 154.26 216.35 141.29 204.35 M 171.69 234.75 C 163.79 227.89 157.09 221.18 141.29 204.35 M 183.01 234.75 C 170.96 220.57 156.03 207.55 146.94 198.69 M 183.01 234.75 C 170.7 222.33 158.61 210.87 146.94 198.69 M 194.32 234.75 C 181.99 221.92 167.39 204.66 158.26 198.69 M 194.32 234.75 C 183.86 225.06 174.16 214.74 158.26 198.69 M 205.63 234.75 C 195.62 225.33 185.82 214.76 169.57 198.69 M 205.63 234.75 C 192.49 221.34 177.87 205.68 169.57 198.69 M 216.95 234.75 C 205.6 222.3 196.95 213.06 180.89 198.69 M 216.95 234.75 C 205.07 223.64 192.78 211.15 180.89 198.69 M 228.26 234.75 C 219.04 224.94 210.83 219.21 192.2 198.69 M 228.26 234.75 C 219.66 225.65 209.53 215.44 192.2 198.69 M 239.58 234.75 C 233.4 225.79 222.71 216.87 203.51 198.69 M 239.58 234.75 C 225.55 220.71 211.42 207.51 203.51 198.69 M 250.89 234.75 C 237.61 221.9 229.31 212.96 214.83 198.69 M 250.89 234.75 C 236.83 221.83 223.24 208.4 214.83 198.69 M 262.2 234.75 C 254.33 226.43 247.06 221.25 226.85 199.4 M 262.2 234.75 C 247.78 220.72 233.89 207.27 226.85 199.4 M 273.52 234.75 C 260.98 222.87 249.27 212.72 238.16 199.4 M 273.52 234.75 C 260.97 222.57 247.85 207.79 238.16 199.4 M 284.83 234.75 C 273.13 223.19 261.22 213.35 249.48 199.4 M 284.83 234.75 C 275.38 225.22 265.56 215.38 249.48 199.4 M 298.97 237.58 C 289.68 228.66 281.99 217.72 260.79 199.4 M 298.97 237.58 C 286.2 224.85 272.98 212.76 260.79 199.4 M 304.63 231.92 C 293.57 218.37 281.44 205.66 272.1 199.4 M 304.63 231.92 C 296.77 223.96 289.34 215.7 272.1 199.4 M 304.63 220.61 C 301.25 215.39 293.34 212.12 283.42 199.4 M 304.63 220.61 C 296.55 212.84 288.07 203.52 283.42 199.4 M 300.39 205.05 C 299.14 203.51 297.44 201.72 294.73 199.4 M 300.39 205.05 C 298.83 203.19 297.57 201.81 294.73 199.4" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 146 200 M 146 200 C 196.64 199.38 244.33 198.33 294 200 M 146 200 C 188.93 199.65 233.4 199.66 294 200 M 294 200 C 298.81 198.16 299.27 202.45 300 206 M 294 200 C 296.39 201.21 300.07 200.75 300 206 M 300 206 C 299.51 211.28 301.26 221.15 300 234 M 300 206 C 300.28 214.35 300.33 220.95 300 234 M 300 234 C 300.36 236.77 298.12 241.11 294 240 M 300 234 C 299.66 237.97 296.65 238.61 294 240 M 294 240 C 247.38 241.09 203.49 242.67 146 240 M 294 240 C 262.36 240.55 233.1 240.58 146 240 M 146 240 C 140.27 240.34 140.94 239.44 140 234 M 146 240 C 141.27 238.38 140.12 239.53 140 234 M 140 234 C 139.68 223.3 140.18 213.46 140 206 M 140 234 C 140.27 223.69 139.38 213.27 140 206 M 140 206 C 140.39 203.55 141.07 200.04 146 200 M 140 206 C 138.33 203.53 142.7 198.45 146 200" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="140" y="300" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 141.48 338.48 C 141.48 338.48 141.48 338.48 141.48 338.48 M 141.48 338.48 C 141.48 338.48 141.48 338.48 141.48 338.48 M 148.55 334.24 C 147.98 332.87 145.95 331.77 144.31 329.99 M 148.55 334.24 C 147.44 333.43 146.39 332.05 144.31 329.99 M 159.86 334.24 C 156.95 330.79 153.06 325.28 144.31 318.68 M 159.86 334.24 C 153.35 327.89 148.81 323.51 144.31 318.68 M 171.18 334.24 C 165.3 327.43 156.34 321.61 141.48 304.54 M 171.18 334.24 C 159.9 322.99 149.03 311.8 141.48 304.54 M 182.49 334.24 C 173.1 326.52 167.62 315.91 147.14 298.88 M 182.49 334.24 C 174.87 324.99 166.64 318.25 147.14 298.88 M 193.81 334.24 C 182.73 323.98 173.51 313.65 158.45 298.88 M 193.81 334.24 C 186.18 326.15 176.97 315.65 158.45 298.88 M 205.12 334.24 C 192.66 322.63 181.92 308.32 169.76 298.88 M 205.12 334.24 C 192.36 321.25 179.13 307.55 169.76 298.88 M 216.43 334.24 C 205.67 323.34 195.34 313.57 181.08 298.88 M 216.43 334.24 C 206.09 324.86 196.85 312.8 181.08 298.88 M 227.75 334.24 C 216.46 324.07 207.48 315.37 192.39 298.88 M 227.75 334.24 C 214.21 322.16 202.11 308 192.39 298.88 M 239.06 334.24 C 226.04 322.28 215.06 307.68 203.7 298.88 M 239.06 334.24 C 225.15 320.64 211.57 306.24 203.7 298.88 M 251.08 334.94 C 240.27 324.74 227.7 313.79 215.02 298.88 M 251.08 334.94 C 238.48 320.84 224.73 308.44 215.02 298.88 M 262.39 334.94 C 248.04 323.32 233.92 309.79 226.33 298.88 M 262.39 334.94 C 247.49 320.22 234.22 306.85 226.33 298.88 M 273.71 334.94 C 261.29 320.35 247.96 308.73 237.65 298.88 M 273.71 334.94 C 266.47 326.75 256.85 318.53 237.65 298.88 M 285.02 334.94 C 270.15 320.97 256.38 308.56 248.96 298.88 M 285.02 334.94 C 274.18 325.03 262.94 313.23 248.96 298.88 M 299.16 337.77 C 288.13 326.34 280.44 318.38 260.27 298.88 M 299.16 337.77 C 284.08 322.09 267.45 306.18 260.27 298.88 M 304.82 332.12 C 293.86 323.04 284.65 314.77 271.59 298.88 M 304.82 332.12 C 292.4 320.54 280.6 307.71 271.59 298.88 M 304.82 320.8 C 296.76 313.99 289.14 303.29 282.9 298.88 M 304.82 320.8 C 296.93 311.71 289.52 305.27 282.9 298.88 M 300.58 305.25 C 299.17 303.56 297.71 301.91 294.92 299.59 M 300.58 305.25 C 298.69 302.91 296.91 301.38 294.92 299.59" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 146 300 M 146 300 C 200.52 301.27 256.26 298.82 294 300 M 146 300 C 184.93 299.35 223.78 298.06 294 300 M 294 300 C 297.03 299.88 300.87 303.23 300 306 M 294 300 C 296.67 299.97 301.12 301.46 300 306 M 300 306 C 300.33 314.71 300.1 324.74 300 334 M 300 306 C 300.84 315.29 299.73 324.42 300 334 M 300 334 C 301.73 338.13 299.31 340.83 294 340 M 300 334 C 299.63 336.61 300.04 342.15 294 340 M 294 340 C 248.72 340.07 200.6 338.92 146 340 M 294 340 C 254.5 339.54 215.98 338.06 146 340 M 146 340 C 142.22 338.97 140.97 336.23 140 334 M 146 340 C 144.17 341.92 142.02 337.59 140 334 M 140 334 C 138.25 326.32 138.9 316.24 140 306 M 140 334 C 139.71 324.68 140.15 314.24 140 306 M 140 306 C 140.6 302.24 143.45 298.35 146 300 M 140 306 C 138.71 301.22 142.52 300.06 146 300" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 141.49 338.49 C 141.49 338.49 141.49 338.49 141.49 338.49 M 141.49 338.49 C 141.49 338.49 141.49 338.49 141.49 338.49 M 148.56 334.25 C 147.99 332.88 145.97 331.79 144.32 330.01 M 148.56 334.25 C 147.45 333.44 146.41 332.07 144.32 330.01 M 159.88 334.25 C 156.96 330.8 153.08 325.29 144.32 318.69 M 159.88 334.25 C 153.36 327.91 148.82 323.53 144.32 318.69 M 171.19 334.25 C 165.31 327.45 156.35 321.62 141.49 304.55 M 171.19 334.25 C 159.91 323.01 149.04 311.81 141.49 304.55 M 182.5 334.25 C 173.12 326.54 167.63 315.92 147.15 298.89 M 182.5 334.25 C 174.88 325.01 166.66 318.27 147.15 298.89 M 193.82 334.25 C 182.74 323.99 173.52 313.66 158.46 298.89 M 193.82 334.25 C 186.19 326.16 176.98 315.67 158.46 298.89 M 205.13 334.25 C 192.67 322.64 181.93 308.33 169.78 298.89 M 205.13 334.25 C 192.37 321.26 179.14 307.56 169.78 298.89 M 216.45 334.25 C 205.69 323.35 195.36 313.59 181.09 298.89 M 216.45 334.25 C 206.1 324.87 196.87 312.82 181.09 298.89 M 227.76 334.25 C 216.47 324.08 207.5 315.39 192.4 298.89 M 227.76 334.25 C 214.22 322.17 202.12 308.01 192.4 298.89 M 239.07 334.25 C 226.05 322.29 215.07 307.7 203.72 298.89 M 239.07 334.25 C 225.16 320.65 211.58 306.25 203.72 298.89 M 250.39 334.25 C 239.79 324.25 227.43 313.53 215.03 298.89 M 250.39 334.25 C 238.05 320.41 224.56 308.27 215.03 298.89 M 262.41 334.96 C 248.05 323.33 233.94 309.8 226.35 298.89 M 262.41 334.96 C 247.5 320.23 234.24 306.86 226.35 298.89 M 273.72 334.96 C 261.3 320.36 247.97 308.74 237.66 298.89 M 273.72 334.96 C 266.48 326.77 256.87 318.54 237.66 298.89 M 285.04 334.96 C 270.17 320.99 256.4 308.58 248.97 298.89 M 285.04 334.96 C 274.2 325.05 262.95 313.24 248.97 298.89 M 299.18 337.79 C 288.15 326.35 280.45 318.4 260.29 298.89 M 299.18 337.79 C 284.09 322.1 267.46 306.19 260.29 298.89 M 304.13 331.42 C 293.36 322.55 284.35 314.47 271.6 298.89 M 304.13 331.42 C 291.96 320.1 280.42 307.52 271.6 298.89 M 304.83 320.81 C 296.78 314 289.15 303.3 282.91 298.89 M 304.83 320.81 C 296.94 311.73 289.53 305.29 282.91 298.89 M 300.59 305.26 C 299.01 303.36 297.36 301.51 294.23 298.89 M 300.59 305.26 C 298.47 302.63 296.47 300.91 294.23 298.89" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 146 300 M 146 300 C 200.52 301.27 256.26 298.82 294 300 M 146 300 C 184.93 299.35 223.78 298.06 294 300 M 294 300 C 297.03 299.88 300.87 303.23 300 306 M 294 300 C 296.67 299.97 301.12 301.46 300 306 M 300 306 C 300.33 314.71 300.1 324.74 300 334 M 300 306 C 300.84 315.29 299.73 324.42 300 334 M 300 334 C 301.73 338.13 299.31 340.83 294 340 M 300 334 C 299.63 336.61 300.04 342.15 294 340 M 294 340 C 248.72 340.07 200.6 338.92 146 340 M 294 340 C 254.5 339.54 215.98 338.06 146 340 M 146 340 C 142.22 338.97 140.97 336.23 140 334 M 146 340 C 144.17 341.92 142.02 337.59 140 334 M 140 334 C 138.25 326.32 138.9 316.24 140 306 M 140 334 C 139.71 324.68 140.15 314.24 140 306 M 140 306 C 140.6 302.24 143.45 298.35 146 300 M 140 306 C 138.71 301.22 142.52 300.06 146 300" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1600" y="20" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="1602" y="22" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="1610" y="250" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1611.41 288.41 C 1611.41 288.41 1611.41 288.41 1611.41 288.41 M 1611.41 288.41 C 1611.41 288.41 1611.41 288.41 1611.41 288.41 M 1618.49 284.17 C 1617.02 283.51 1615.45 281.3 1614.24 279.93 M 1618.49 284.17 C 1617.1 283.15 1616.24 281.71 1614.24 279.93 M 1629.8 284.17 C 1626.23 279.92 1620.19 277.07 1614.24 268.62 M 1629.8 284.17 C 1625.44 280.51 1622.08 275.61 1614.24 268.62 M 1641.11 284.17 C 1629.8 274.47 1620.06 260.72 1611.41 254.47 M 1641.11 284.17 C 1634.19 277.21 1626.29 269.92 1611.41 254.47 M 1652.43 284.17 C 1645.23 274.57 1634.72 270.25 1617.07 248.82 M 1652.43 284.17 C 1641.38 274.34 1631.11 263.02 1617.07 248.82 M 1663.74 284.17 C 1653.03 273.55 1639.12 260.69 1628.39 248.82 M 1663.74 284.17 C 1656.68 276.71 1648.63 268.92 1628.39 248.82 M 1675.05 284.17 C 1665.23 275.3 1657.92 265.19 1639.7 248.82 M 1675.05 284.17 C 1661.65 271.85 1647.59 257.43 1639.7 248.82 M 1686.37 284.17 C 1672.98 272.07 1664.04 259.77 1651.01 248.82 M 1686.37 284.17 C 1677.76 274.76 1669.9 267.39 1651.01 248.82 M 1698.39 284.88 C 1687.48 276.75 1679.64 267.67 1662.33 248.82 M 1698.39 284.88 C 1684.78 272.11 1672.43 258.28 1662.33 248.82 M 1709.7 284.88 C 1698.91 274.75 1690.85 267.03 1673.64 248.82 M 1709.7 284.88 C 1694.84 270.57 1680.11 255.57 1673.64 248.82 M 1721.02 284.88 C 1710.3 274.01 1701.86 265.08 1684.95 248.82 M 1721.02 284.88 C 1710.98 275.25 1702.47 267.24 1684.95 248.82 M 1732.33 284.88 C 1718.3 268.94 1704.41 254.82 1696.27 248.82 M 1732.33 284.88 C 1721.71 275.65 1712.94 264.34 1696.27 248.82 M 1743.64 284.88 C 1736.25 277.32 1726.58 265.67 1707.58 248.82 M 1743.64 284.88 C 1733.51 275.42 1725.01 264.49 1707.58 248.82 M 1754.96 284.88 C 1746.44 275.82 1739.97 269.85 1718.89 248.82 M 1754.96 284.88 C 1745.37 276.62 1737.27 266.63 1718.89 248.82 M 1769.1 287.71 C 1754.58 271.91 1738.19 258.4 1730.21 248.82 M 1769.1 287.71 C 1758.91 277.8 1751.83 269.39 1730.21 248.82 M 1774.76 282.05 C 1768.66 273.6 1757.88 268.97 1742.23 249.52 M 1774.76 282.05 C 1767.41 274.65 1760.84 267.22 1742.23 249.52 M 1774.76 270.74 C 1771.14 265.68 1763.5 262.74 1753.54 249.52 M 1774.76 270.74 C 1766.17 262.83 1758.69 253.09 1753.54 249.52 M 1770.51 255.18 C 1768.53 252.28 1766 250.67 1764.86 249.52 M 1770.51 255.18 C 1768.67 253.65 1767.49 252.07 1764.86 249.52" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1616 250 M 1616 250 C 1656.25 251.31 1694.17 249.76 1764 250 M 1616 250 C 1668.79 250.76 1720.85 249.98 1764 250 M 1764 250 C 1766.68 249.81 1769.14 251.95 1770 256 M 1764 250 C 1767.17 248.56 1768.37 250.17 1770 256 M 1770 256 C 1770.26 262.52 1769.82 270.93 1770 284 M 1770 256 C 1770.55 264.83 1769.42 274.86 1770 284 M 1770 284 C 1771.43 288.88 1769.45 291.83 1764 290 M 1770 284 C 1769.82 289.75 1769.23 288.17 1764 290 M 1764 290 C 1712.07 289.17 1662.23 288.5 1616 290 M 1764 290 C 1709.6 290.74 1653.71 290.46 1616 290 M 1616 290 C 1613.97 289.98 1609.73 286.12 1610 284 M 1616 290 C 1613.89 290.46 1608.64 286.66 1610 284 M 1610 284 C 1610.86 275.09 1608.74 264.54 1610 256 M 1610 284 C 1610.68 277.17 1610.76 270.5 1610 256 M 1610 256 C 1609.78 251.02 1610.09 249.56 1616 250 M 1610 256 C 1612.24 251.33 1612.95 249.42 1616 250" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1611.43 288.43 C 1611.43 288.43 1611.43 288.43 1611.43 288.43 M 1611.43 288.43 C 1611.43 288.43 1611.43 288.43 1611.43 288.43 M 1618.5 284.18 C 1617.04 283.52 1615.46 281.31 1614.26 279.94 M 1618.5 284.18 C 1617.11 283.16 1616.25 281.72 1614.26 279.94 M 1629.81 284.18 C 1626.24 279.94 1620.21 277.08 1614.26 268.63 M 1629.81 284.18 C 1625.45 280.53 1622.09 275.63 1614.26 268.63 M 1641.13 284.18 C 1629.82 274.49 1620.07 260.73 1611.43 254.49 M 1641.13 284.18 C 1634.2 277.22 1626.31 269.93 1611.43 254.49 M 1652.44 284.18 C 1645.25 274.58 1634.73 270.26 1617.08 248.83 M 1652.44 284.18 C 1641.39 274.36 1631.13 263.03 1617.08 248.83 M 1663.75 284.18 C 1653.04 273.56 1639.13 260.7 1628.4 248.83 M 1663.75 284.18 C 1656.7 276.73 1648.64 268.93 1628.4 248.83 M 1675.07 284.18 C 1665.24 275.32 1657.94 265.2 1639.71 248.83 M 1675.07 284.18 C 1661.66 271.87 1647.6 257.45 1639.71 248.83 M 1686.38 284.18 C 1672.99 272.09 1664.05 259.78 1651.03 248.83 M 1686.38 284.18 C 1677.77 274.77 1669.91 267.4 1651.03 248.83 M 1698.4 284.89 C 1687.5 276.76 1679.65 267.68 1662.34 248.83 M 1698.4 284.89 C 1684.79 272.12 1672.44 258.29 1662.34 248.83 M 1709.72 284.89 C 1698.92 274.76 1690.86 267.05 1673.65 248.83 M 1709.72 284.89 C 1694.85 270.58 1680.12 255.59 1673.65 248.83 M 1721.03 284.89 C 1710.31 274.02 1701.87 265.09 1684.97 248.83 M 1721.03 284.89 C 1711 275.26 1702.49 267.26 1684.97 248.83 M 1732.34 284.89 C 1718.31 268.95 1704.42 254.83 1696.28 248.83 M 1732.34 284.89 C 1721.72 275.66 1712.95 264.36 1696.28 248.83 M 1743.66 284.89 C 1736.26 277.33 1726.59 265.68 1707.59 248.83 M 1743.66 284.89 C 1733.52 275.43 1725.03 264.5 1707.59 248.83 M 1754.97 284.89 C 1746.45 275.83 1739.98 269.87 1718.91 248.83 M 1754.97 284.89 C 1745.38 276.63 1737.28 266.64 1718.91 248.83 M 1769.11 287.72 C 1754.59 271.92 1738.2 258.41 1730.22 248.83 M 1769.11 287.72 C 1758.92 277.82 1751.84 269.41 1730.22 248.83 M 1774.77 282.06 C 1768.67 273.61 1757.89 268.98 1742.24 249.54 M 1774.77 282.06 C 1767.42 274.66 1760.85 267.23 1742.24 249.54 M 1774.77 270.75 C 1771.15 265.7 1763.52 262.75 1753.56 249.54 M 1774.77 270.75 C 1766.19 262.84 1758.7 253.1 1753.56 249.54 M 1770.53 255.19 C 1768.54 252.29 1766.02 250.68 1764.87 249.54 M 1770.53 255.19 C 1768.68 253.66 1767.5 252.08 1764.87 249.54" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1616 250 M 1616 250 C 1656.25 251.31 1694.17 249.76 1764 250 M 1616 250 C 1668.79 250.76 1720.85 249.98 1764 250 M 1764 250 C 1766.68 249.81 1769.14 251.95 1770 256 M 1764 250 C 1767.17 248.56 1768.37 250.17 1770 256 M 1770 256 C 1770.26 262.52 1769.82 270.93 1770 284 M 1770 256 C 1770.55 264.83 1769.42 274.86 1770 284 M 1770 284 C 1771.43 288.88 1769.45 291.83 1764 290 M 1770 284 C 1769.82 289.75 1769.23 288.17 1764 290 M 1764 290 C 1712.07 289.17 1662.23 288.5 1616 290 M 1764 290 C 1709.6 290.74 1653.71 290.46 1616 290 M 1616 290 C 1613.97 289.98 1609.73 286.12 1610 284 M 1616 290 C 1613.89 290.46 1608.64 286.66 1610 284 M 1610 284 C 1610.86 275.09 1608.74 264.54 1610 256 M 1610 284 C 1610.68 277.17 1610.76 270.5 1610 256 M 1610 256 C 1609.78 251.02 1610.09 249.56 1616 250 M 1610 256 C 1612.24 251.33 1612.95 249.42 1616 250" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1610" y="120" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1611.36 158.36 C 1611.36 158.36 1611.36 158.36 1611.36 158.36 M 1611.36 158.36 C 1611.36 158.36 1611.36 158.36 1611.36 158.36 M 1618.43 154.12 C 1616.65 152.73 1615.79 151.17 1614.19 149.88 M 1618.43 154.12 C 1617.51 153.15 1616.43 152.35 1614.19 149.88 M 1629.75 154.12 C 1626.18 151.32 1622.72 146.56 1614.19 138.56 M 1629.75 154.12 C 1624.1 149.99 1621.13 145.35 1614.19 138.56 M 1641.06 154.12 C 1629.63 146.2 1622.18 136.02 1611.36 124.42 M 1641.06 154.12 C 1628.59 142.62 1618.36 130.67 1611.36 124.42 M 1652.37 154.12 C 1640.51 143.66 1632.11 134.41 1617.02 118.76 M 1652.37 154.12 C 1638.71 140.88 1625 126.96 1617.02 118.76 M 1663.69 154.12 C 1654.67 145.79 1649.85 139.58 1628.33 118.76 M 1663.69 154.12 C 1650.19 140.99 1637.35 127.75 1628.33 118.76 M 1675.71 154.83 C 1663.01 143.34 1650.34 133.07 1639.65 118.76 M 1675.71 154.83 C 1661.44 142.39 1648.23 127.4 1639.65 118.76 M 1687.02 154.83 C 1673.77 143.13 1662.71 129.86 1650.96 118.76 M 1687.02 154.83 C 1678.85 146.77 1671.68 139.46 1650.96 118.76 M 1698.34 154.83 C 1688.44 142.14 1675.63 133.89 1662.27 118.76 M 1698.34 154.83 C 1688.74 145.31 1679.37 134.48 1662.27 118.76 M 1709.65 154.83 C 1695.76 141.44 1683.16 127.8 1673.59 118.76 M 1709.65 154.83 C 1701.12 146.61 1693.86 139.34 1673.59 118.76 M 1720.96 154.83 C 1712.71 145.88 1704 134.95 1684.9 118.76 M 1720.96 154.83 C 1712.39 146.02 1703.72 137.04 1684.9 118.76 M 1732.28 154.83 C 1719.12 143.66 1705.76 128.55 1696.21 118.76 M 1732.28 154.83 C 1722.16 145.19 1712.3 136.23 1696.21 118.76 M 1743.59 154.83 C 1731.83 144.78 1720.78 131.9 1707.53 118.76 M 1743.59 154.83 C 1731.09 142.4 1719.15 131.08 1707.53 118.76 M 1754.9 154.83 C 1743.63 144.5 1735.74 136.39 1719.55 119.47 M 1754.9 154.83 C 1744.32 143.87 1735.19 134.31 1719.55 119.47 M 1769.05 157.65 C 1760.87 150.66 1752.57 140.23 1730.86 119.47 M 1769.05 157.65 C 1757 146.02 1746.94 134.23 1730.86 119.47 M 1774.7 152 C 1762.39 141.72 1752.22 131.22 1742.18 119.47 M 1774.7 152 C 1763.7 140.58 1753.02 130.83 1742.18 119.47 M 1774.7 140.68 C 1766.24 134.73 1759.15 124.62 1753.49 119.47 M 1774.7 140.68 C 1766.57 132.15 1758.42 125.54 1753.49 119.47 M 1770.46 125.13 C 1768.32 123.68 1766.03 120.61 1764.8 119.47 M 1770.46 125.13 C 1768.28 123.13 1766.59 121.39 1764.8 119.47" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1616 120 M 1616 120 C 1660.13 119.21 1706.1 120.24 1764 120 M 1616 120 C 1664.79 118.45 1711.23 118.38 1764 120 M 1764 120 C 1768.9 121.54 1770.74 122.72 1770 126 M 1764 120 C 1767.44 121.92 1769.42 120.88 1770 126 M 1770 126 C 1771.64 135.95 1769.22 144.52 1770 154 M 1770 126 C 1769.67 135.76 1769.38 146.33 1770 154 M 1770 154 C 1768.81 156.23 1766.64 161.54 1764 160 M 1770 154 C 1769.79 158.39 1768.01 161.71 1764 160 M 1764 160 C 1713.41 161.11 1663.34 161.71 1616 160 M 1764 160 C 1731.34 159.73 1697.79 157.94 1616 160 M 1616 160 C 1611.92 158.61 1609.76 156.9 1610 154 M 1616 160 C 1612.19 159.39 1610.54 159.33 1610 154 M 1610 154 C 1609.43 148.11 1611.46 141.32 1610 126 M 1610 154 C 1610.11 148.17 1609.54 139.47 1610 126 M 1610 126 C 1609.99 123.71 1612.47 121.86 1616 120 M 1610 126 C 1608.02 123.62 1612.77 121.04 1616 120" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <rect x="1480" y="100" width="200" height="280" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="1482" y="102" width="196" height="276" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <path d="M 1611.37 158.37 C 1611.37 158.37 1611.37 158.37 1611.37 158.37 M 1611.37 158.37 C 1611.37 158.37 1611.37 158.37 1611.37 158.37 M 1618.44 154.13 C 1616.67 152.75 1615.8 151.19 1614.2 149.89 M 1618.44 154.13 C 1617.52 153.16 1616.44 152.37 1614.2 149.89 M 1629.76 154.13 C 1626.19 151.33 1622.73 146.57 1614.2 138.57 M 1629.76 154.13 C 1624.11 150.01 1621.14 145.36 1614.2 138.57 M 1641.07 154.13 C 1629.64 146.22 1622.19 136.03 1611.37 124.43 M 1641.07 154.13 C 1628.6 142.63 1618.38 130.68 1611.37 124.43 M 1652.39 154.13 C 1640.52 143.67 1632.12 134.42 1617.03 118.78 M 1652.39 154.13 C 1638.72 140.89 1625.01 126.97 1617.03 118.78 M 1663.7 154.13 C 1654.68 145.81 1649.86 139.59 1628.34 118.78 M 1663.7 154.13 C 1650.21 141 1637.36 127.76 1628.34 118.78 M 1675.01 154.13 C 1662.55 142.88 1650.1 132.83 1639.66 118.78 M 1675.01 154.13 C 1661.01 141.96 1648.06 127.22 1639.66 118.78 M 1687.03 154.84 C 1673.79 143.14 1662.73 129.87 1650.97 118.78 M 1687.03 154.84 C 1678.86 146.78 1671.69 139.47 1650.97 118.78 M 1698.35 154.84 C 1688.45 142.15 1675.65 133.9 1662.29 118.78 M 1698.35 154.84 C 1688.75 145.32 1679.38 134.49 1662.29 118.78 M 1709.66 154.84 C 1695.78 141.45 1683.17 127.82 1673.6 118.78 M 1709.66 154.84 C 1701.13 146.62 1693.88 139.35 1673.6 118.78 M 1720.98 154.84 C 1712.73 145.89 1704.02 134.96 1684.91 118.78 M 1720.98 154.84 C 1712.4 146.03 1703.73 137.05 1684.91 118.78 M 1732.29 154.84 C 1719.14 143.67 1705.77 128.57 1696.23 118.78 M 1732.29 154.84 C 1722.18 145.2 1712.32 136.25 1696.23 118.78 M 1743.6 154.84 C 1731.84 144.79 1720.79 131.92 1707.54 118.78 M 1743.6 154.84 C 1731.1 142.41 1719.16 131.09 1707.54 118.78 M 1754.92 154.84 C 1743.44 144.32 1735.34 136 1718.85 118.78 M 1754.92 154.84 C 1744.13 143.68 1734.8 133.92 1718.85 118.78 M 1769.06 157.67 C 1760.88 150.67 1752.59 140.24 1730.87 119.48 M 1769.06 157.67 C 1757.01 146.04 1746.96 134.24 1730.87 119.48 M 1774.72 152.01 C 1762.4 141.73 1752.23 131.23 1742.19 119.48 M 1774.72 152.01 C 1763.71 140.6 1753.04 130.84 1742.19 119.48 M 1774.72 140.7 C 1766.25 134.74 1759.16 124.63 1753.5 119.48 M 1774.72 140.7 C 1766.58 132.16 1758.43 125.55 1753.5 119.48 M 1770.47 125.14 C 1768.33 123.69 1766.04 120.62 1764.82 119.48 M 1770.47 125.14 C 1768.29 123.14 1766.61 121.4 1764.82 119.48" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1616 120 M 1616 120 C 1660.13 119.21 1706.1 120.24 1764 120 M 1616 120 C 1664.79 118.45 1711.23 118.38 1764 120 M 1764 120 C 1768.9 121.54 1770.74 122.72 1770 126 M 1764 120 C 1767.44 121.92 1769.42 120.88 1770 126 M 1770 126 C 1771.64 135.95 1769.22 144.52 1770 154 M 1770 126 C 1769.67 135.76 1769.38 146.33 1770 154 M 1770 154 C 1768.81 156.23 1766.64 161.54 1764 160 M 1770 154 C 1769.79 158.39 1768.01 161.71 1764 160 M 1764 160 C 1713.41 161.11 1663.34 161.71 1616 160 M 1764 160 C 1731.34 159.73 1697.79 157.94 1616 160 M 1616 160 C 1611.92 158.61 1609.76 156.9 1610 154 M 1616 160 C 1612.19 159.39 1610.54 159.33 1610 154 M 1610 154 C 1609.43 148.11 1611.46 141.32 1610 126 M 1610 154 C 1610.11 148.17 1609.54 139.47 1610 126 M 1610 126 C 1609.99 123.71 1612.47 121.86 1616 120 M 1610 126 C 1608.02 123.62 1612.77 121.04 1616 120" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <rect x="1480" y="100" width="200" height="280" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="1482" y="102" width="196" height="276" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="1480" y="70" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 80px; margin-left: 1540px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="1540" y="84" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1540" y="84" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> </g> <rect x="1500" y="300" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1501.72 338.72 C 1501.72 338.72 1501.72 338.72 1501.72 338.72 M 1501.72 338.72 C 1501.72 338.72 1501.72 338.72 1501.72 338.72 M 1508.79 334.47 C 1508.27 332.87 1506.3 332.58 1503.84 329.52 M 1508.79 334.47 C 1507.43 333.48 1506.4 332.12 1503.84 329.52 M 1520.1 334.47 C 1516.61 331.21 1509.78 323.13 1503.84 318.21 M 1520.1 334.47 C 1514.85 329.1 1508.88 324.05 1503.84 318.21 M 1531.41 334.47 C 1525.56 328.46 1517.83 321.93 1501.72 304.78 M 1531.41 334.47 C 1520.92 323.27 1509.21 311.7 1501.72 304.78 M 1542.73 334.47 C 1537 328.69 1528.26 318.91 1507.37 299.12 M 1542.73 334.47 C 1533.52 323.9 1523.75 315.04 1507.37 299.12 M 1554.04 334.47 C 1541.72 323.37 1526.26 309.27 1518.69 299.12 M 1554.04 334.47 C 1544.6 325.1 1534.66 314.31 1518.69 299.12 M 1565.36 334.47 C 1551.21 320.31 1542 311.5 1530 299.12 M 1565.36 334.47 C 1553.14 323.35 1541.05 311.71 1530 299.12 M 1576.67 334.47 C 1565.88 324.44 1555.87 313.12 1541.31 299.12 M 1576.67 334.47 C 1568.57 326.7 1560.19 318.43 1541.31 299.12 M 1587.98 334.47 C 1580.9 326.4 1570.67 317.64 1552.63 299.12 M 1587.98 334.47 C 1580.71 325.52 1572.7 318.59 1552.63 299.12 M 1599.3 334.47 C 1589.55 326.23 1581.97 315.25 1563.94 299.12 M 1599.3 334.47 C 1590.82 325.21 1582.06 316.52 1563.94 299.12 M 1610.61 334.47 C 1600.77 325.11 1590.24 313.15 1575.26 299.12 M 1610.61 334.47 C 1598.1 322.39 1585.74 309.41 1575.26 299.12 M 1621.92 334.47 C 1614.04 327.58 1605.82 315.85 1586.57 299.12 M 1621.92 334.47 C 1612.55 323.27 1602.33 314.13 1586.57 299.12 M 1633.24 334.47 C 1618.34 321.14 1605.15 306.07 1597.88 299.12 M 1633.24 334.47 C 1620.5 323.18 1609.5 311.07 1597.88 299.12 M 1644.55 334.47 C 1632.03 321.72 1620.22 311.7 1609.2 299.12 M 1644.55 334.47 C 1632.97 322.74 1621.97 311.93 1609.2 299.12 M 1659.4 338.01 C 1653.76 330.25 1644.76 321.74 1620.51 299.12 M 1659.4 338.01 C 1650.26 329.09 1640.6 319.55 1620.51 299.12 M 1664.35 331.65 C 1651.45 319.66 1641.01 311.09 1631.82 299.12 M 1664.35 331.65 C 1656.36 322.76 1646.23 314.09 1631.82 299.12 M 1664.35 320.33 C 1659.75 316.63 1654.37 311.4 1643.14 299.12 M 1664.35 320.33 C 1657.19 311.11 1647.57 304.14 1643.14 299.12 M 1660.82 305.48 C 1659.41 304.69 1658.12 301.67 1654.45 299.12 M 1660.82 305.48 C 1659.05 303.37 1656.9 301.17 1654.45 299.12" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1506 300 M 1506 300 C 1556.66 297.16 1609.53 299.01 1654 300 M 1506 300 C 1555.17 300.34 1605.45 299.71 1654 300 M 1654 300 C 1658.37 300.61 1660.64 302.04 1660 306 M 1654 300 C 1659.73 298.45 1657.91 300.17 1660 306 M 1660 306 C 1659.25 315.39 1659.34 325.59 1660 334 M 1660 306 C 1660.53 315.98 1659.18 324.66 1660 334 M 1660 334 C 1661.21 338.18 1658.32 338.31 1654 340 M 1660 334 C 1659.02 336.48 1659.74 338.23 1654 340 M 1654 340 C 1618.55 337.85 1584.3 338.3 1506 340 M 1654 340 C 1600.48 339.86 1547 340.28 1506 340 M 1506 340 C 1502.84 340.41 1500.62 336.51 1500 334 M 1506 340 C 1501.26 340.45 1502.05 336.96 1500 334 M 1500 334 C 1500.18 328.52 1501.85 320.41 1500 306 M 1500 334 C 1500.4 323.42 1499.29 312.65 1500 306 M 1500 306 C 1501.34 303.02 1502.08 299.43 1506 300 M 1500 306 C 1498.36 301.1 1502.89 299.97 1506 300" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1501.73 338.73 C 1501.73 338.73 1501.73 338.73 1501.73 338.73 M 1501.73 338.73 C 1501.73 338.73 1501.73 338.73 1501.73 338.73 M 1508.8 334.49 C 1508.29 332.88 1506.31 332.6 1503.85 329.54 M 1508.8 334.49 C 1507.44 333.49 1506.42 332.14 1503.85 329.54 M 1520.11 334.49 C 1516.62 331.23 1509.8 323.14 1503.85 318.22 M 1520.11 334.49 C 1514.87 329.11 1508.89 324.06 1503.85 318.22 M 1531.43 334.49 C 1525.57 328.47 1517.84 321.95 1501.73 304.79 M 1531.43 334.49 C 1520.93 323.28 1509.22 311.71 1501.73 304.79 M 1542.74 334.49 C 1537.01 328.7 1528.27 318.92 1507.39 299.13 M 1542.74 334.49 C 1533.53 323.91 1523.77 315.05 1507.39 299.13 M 1554.05 334.49 C 1541.74 323.39 1526.27 309.28 1518.7 299.13 M 1554.05 334.49 C 1544.62 325.12 1534.68 314.32 1518.7 299.13 M 1565.37 334.49 C 1551.22 320.33 1542.01 311.51 1530.01 299.13 M 1565.37 334.49 C 1553.15 323.37 1541.06 311.73 1530.01 299.13 M 1576.68 334.49 C 1565.89 324.45 1555.88 313.13 1541.33 299.13 M 1576.68 334.49 C 1568.58 326.71 1560.2 318.44 1541.33 299.13 M 1588 334.49 C 1580.91 326.42 1570.68 317.65 1552.64 299.13 M 1588 334.49 C 1580.73 325.53 1572.71 318.61 1552.64 299.13 M 1599.31 334.49 C 1589.57 326.24 1581.99 315.26 1563.95 299.13 M 1599.31 334.49 C 1590.83 325.23 1582.07 316.54 1563.95 299.13 M 1610.62 334.49 C 1600.78 325.12 1590.26 313.17 1575.27 299.13 M 1610.62 334.49 C 1598.12 322.4 1585.75 309.43 1575.27 299.13 M 1621.94 334.49 C 1614.05 327.6 1605.83 315.87 1586.58 299.13 M 1621.94 334.49 C 1612.57 323.29 1602.34 314.14 1586.58 299.13 M 1633.25 334.49 C 1618.35 321.15 1605.17 306.08 1597.9 299.13 M 1633.25 334.49 C 1620.51 323.2 1609.51 311.08 1597.9 299.13 M 1644.56 334.49 C 1632.04 321.74 1620.23 311.71 1609.21 299.13 M 1644.56 334.49 C 1632.99 322.75 1621.98 311.94 1609.21 299.13 M 1659.41 338.02 C 1653.77 330.26 1644.77 321.76 1620.52 299.13 M 1659.41 338.02 C 1650.27 329.1 1640.62 319.57 1620.52 299.13 M 1664.36 331.66 C 1651.46 319.67 1641.02 311.1 1631.84 299.13 M 1664.36 331.66 C 1656.37 322.78 1646.25 314.1 1631.84 299.13 M 1664.36 320.34 C 1659.76 316.64 1654.38 311.41 1643.15 299.13 M 1664.36 320.34 C 1657.2 311.12 1647.58 304.15 1643.15 299.13 M 1660.83 305.5 C 1659.43 304.7 1658.13 301.68 1654.46 299.13 M 1660.83 305.5 C 1659.06 303.38 1656.91 301.18 1654.46 299.13" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1506 300 M 1506 300 C 1556.66 297.16 1609.53 299.01 1654 300 M 1506 300 C 1555.17 300.34 1605.45 299.71 1654 300 M 1654 300 C 1658.37 300.61 1660.64 302.04 1660 306 M 1654 300 C 1659.73 298.45 1657.91 300.17 1660 306 M 1660 306 C 1659.25 315.39 1659.34 325.59 1660 334 M 1660 306 C 1660.53 315.98 1659.18 324.66 1660 334 M 1660 334 C 1661.21 338.18 1658.32 338.31 1654 340 M 1660 334 C 1659.02 336.48 1659.74 338.23 1654 340 M 1654 340 C 1618.55 337.85 1584.3 338.3 1506 340 M 1654 340 C 1600.48 339.86 1547 340.28 1506 340 M 1506 340 C 1502.84 340.41 1500.62 336.51 1500 334 M 1506 340 C 1501.26 340.45 1502.05 336.96 1500 334 M 1500 334 C 1500.18 328.52 1501.85 320.41 1500 306 M 1500 334 C 1500.4 323.42 1499.29 312.65 1500 306 M 1500 306 C 1501.34 303.02 1502.08 299.43 1506 300 M 1500 306 C 1498.36 301.1 1502.89 299.97 1506 300" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1500" y="180" width="160" height="60" rx="9" ry="9" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1502.26 237.76 C 1502.26 237.76 1502.26 237.76 1502.26 237.76 M 1502.26 237.76 C 1502.26 237.76 1502.26 237.76 1502.26 237.76 M 1510.04 234.23 C 1509.04 232.88 1507.56 231.69 1503.68 227.86 M 1510.04 234.23 C 1507.72 231.76 1504.79 228.8 1503.68 227.86 M 1521.35 234.23 C 1517.19 228.39 1512.61 226.07 1503.68 216.55 M 1521.35 234.23 C 1514.28 227.83 1508.14 220.47 1503.68 216.55 M 1532.67 234.23 C 1521.62 224.32 1510.51 211.7 1503.68 205.23 M 1532.67 234.23 C 1522.22 224.66 1512.36 214.61 1503.68 205.23 M 1543.98 234.23 C 1531.45 222.16 1519.44 210.06 1503.68 193.92 M 1543.98 234.23 C 1529.56 218.4 1514.52 205.11 1503.68 193.92 M 1555.29 234.23 C 1540.43 221.33 1529.83 209.65 1502.97 181.9 M 1555.29 234.23 C 1542.53 222.29 1530.87 209.12 1502.97 181.9 M 1566.61 234.23 C 1553.26 221.09 1541.46 210.89 1510.75 178.36 M 1566.61 234.23 C 1547.93 216.53 1530.32 197.94 1510.75 178.36 M 1578.63 234.93 C 1561.92 219.06 1543.73 200.71 1522.06 178.36 M 1578.63 234.93 C 1555.51 213 1532.46 189.42 1522.06 178.36 M 1589.94 234.93 C 1573.16 215.67 1555.35 201.13 1533.37 178.36 M 1589.94 234.93 C 1569.49 215.78 1552.16 197.56 1533.37 178.36 M 1601.26 234.93 C 1580.15 211.06 1555.79 189.92 1544.69 178.36 M 1601.26 234.93 C 1585.83 218.72 1569.42 202.62 1544.69 178.36 M 1612.57 234.93 C 1595.01 217.17 1577.86 200.85 1556 178.36 M 1612.57 234.93 C 1591.87 214.07 1571.61 194.38 1556 178.36 M 1623.88 234.93 C 1612.59 223.65 1600.58 210.62 1567.32 178.36 M 1623.88 234.93 C 1608.16 219.36 1590.87 202.6 1567.32 178.36 M 1635.2 234.93 C 1622.2 220.6 1610.03 210.69 1578.63 178.36 M 1635.2 234.93 C 1623.68 222.51 1611.99 210.75 1578.63 178.36 M 1651.46 239.88 C 1624.83 215.54 1601.08 192.86 1589.94 178.36 M 1651.46 239.88 C 1629.28 217.96 1607.89 196.22 1589.94 178.36 M 1659.24 236.35 C 1647.71 225.15 1634.53 211.45 1601.26 178.36 M 1659.24 236.35 C 1642.27 219.68 1623.59 200.7 1601.26 178.36 M 1664.19 229.98 C 1650.81 217.9 1638.77 205.26 1612.57 178.36 M 1664.19 229.98 C 1645.36 210.45 1625.82 190.14 1612.57 178.36 M 1664.19 218.67 C 1648.14 202.77 1636.59 187.65 1624.59 179.07 M 1664.19 218.67 C 1650.92 204.25 1636.02 189.81 1624.59 179.07 M 1664.9 208.06 C 1658.02 202.46 1652.3 192.67 1635.9 179.07 M 1664.9 208.06 C 1657.72 201.79 1651.21 196.05 1635.9 179.07 M 1664.9 196.75 C 1659.18 188.13 1651.72 181.7 1647.22 179.07 M 1664.9 196.75 C 1659.21 190.66 1653.19 185.32 1647.22 179.07" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1509 180 M 1509 180 C 1542.38 182.99 1575.7 180.34 1651 180 M 1509 180 C 1544.31 179.89 1581.21 178.95 1651 180 M 1651 180 C 1658.06 181.79 1658.09 181.27 1660 189 M 1651 180 C 1655.52 180.03 1661.96 183.75 1660 189 M 1660 189 C 1658.34 197.76 1661.82 208.72 1660 231 M 1660 189 C 1659.51 205.48 1659.81 219.76 1660 231 M 1660 231 C 1661.86 235.33 1658.77 238.03 1651 240 M 1660 231 C 1660.62 237.7 1655.12 238.2 1651 240 M 1651 240 C 1616.25 242.34 1582.39 239.9 1509 240 M 1651 240 C 1599.12 238.34 1546.64 239.24 1509 240 M 1509 240 C 1504.96 241.43 1499.73 236.23 1500 231 M 1509 240 C 1502.55 241.86 1500.06 237.97 1500 231 M 1500 231 C 1501.79 214.04 1501.27 199.89 1500 189 M 1500 231 C 1499.35 214.6 1500.54 200.56 1500 189 M 1500 189 C 1500.99 184.49 1502.44 179.16 1509 180 M 1500 189 C 1500.93 182.52 1501.56 180.02 1509 180" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1502.27 237.77 C 1502.27 237.77 1502.27 237.77 1502.27 237.77 M 1502.27 237.77 C 1502.27 237.77 1502.27 237.77 1502.27 237.77 M 1510.05 234.24 C 1509.05 232.9 1507.58 231.71 1503.69 227.87 M 1510.05 234.24 C 1507.73 231.78 1504.8 228.82 1503.69 227.87 M 1521.37 234.24 C 1517.21 228.4 1512.63 226.08 1503.69 216.56 M 1521.37 234.24 C 1514.29 227.84 1508.15 220.49 1503.69 216.56 M 1532.68 234.24 C 1521.63 224.34 1510.53 211.71 1503.69 205.25 M 1532.68 234.24 C 1522.23 224.68 1512.37 214.62 1503.69 205.25 M 1543.99 234.24 C 1531.46 222.17 1519.45 210.08 1503.69 193.93 M 1543.99 234.24 C 1529.57 218.41 1514.53 205.12 1503.69 193.93 M 1555.31 234.24 C 1540.44 221.35 1529.85 209.66 1502.98 181.91 M 1555.31 234.24 C 1542.54 222.3 1530.89 209.13 1502.98 181.91 M 1566.62 234.24 C 1553.27 221.11 1541.48 210.91 1510.76 178.38 M 1566.62 234.24 C 1547.94 216.54 1530.33 197.95 1510.76 178.38 M 1578.64 234.95 C 1561.93 219.08 1543.74 200.72 1522.07 178.38 M 1578.64 234.95 C 1555.53 213.02 1532.47 189.43 1522.07 178.38 M 1589.96 234.95 C 1573.17 215.69 1555.36 201.14 1533.39 178.38 M 1589.96 234.95 C 1569.5 215.79 1552.17 197.58 1533.39 178.38 M 1601.27 234.95 C 1580.17 211.07 1555.81 189.93 1544.7 178.38 M 1601.27 234.95 C 1585.84 218.73 1569.43 202.64 1544.7 178.38 M 1612.58 234.95 C 1595.03 217.18 1577.87 200.87 1556.01 178.38 M 1612.58 234.95 C 1591.88 214.09 1571.62 194.4 1556.01 178.38 M 1623.9 234.95 C 1612.61 223.66 1600.59 210.63 1567.33 178.38 M 1623.9 234.95 C 1608.17 219.38 1590.88 202.61 1567.33 178.38 M 1635.21 234.95 C 1622.22 220.61 1610.05 210.71 1578.64 178.38 M 1635.21 234.95 C 1623.69 222.53 1612 210.77 1578.64 178.38 M 1651.47 239.9 C 1624.84 215.55 1601.1 192.88 1589.96 178.38 M 1651.47 239.9 C 1629.29 217.97 1607.9 196.24 1589.96 178.38 M 1659.25 236.36 C 1647.72 225.16 1634.54 211.47 1601.27 178.38 M 1659.25 236.36 C 1642.29 219.69 1623.6 200.72 1601.27 178.38 M 1664.2 230 C 1650.83 217.91 1638.79 205.27 1612.58 178.38 M 1664.2 230 C 1645.37 210.47 1625.83 190.15 1612.58 178.38 M 1664.2 218.68 C 1648.15 202.78 1636.6 187.66 1624.6 179.08 M 1664.2 218.68 C 1650.93 204.26 1636.04 189.83 1624.6 179.08 M 1664.91 208.08 C 1658.03 202.47 1652.31 192.68 1635.92 179.08 M 1664.91 208.08 C 1657.73 201.8 1651.23 196.07 1635.92 179.08 M 1664.91 196.76 C 1659.19 188.14 1651.73 181.71 1647.23 179.08 M 1664.91 196.76 C 1659.23 190.67 1653.2 185.33 1647.23 179.08" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1509 180 M 1509 180 C 1542.38 182.99 1575.7 180.34 1651 180 M 1509 180 C 1544.31 179.89 1581.21 178.95 1651 180 M 1651 180 C 1658.06 181.79 1658.09 181.27 1660 189 M 1651 180 C 1655.52 180.03 1661.96 183.75 1660 189 M 1660 189 C 1658.34 197.76 1661.82 208.72 1660 231 M 1660 189 C 1659.51 205.48 1659.81 219.76 1660 231 M 1660 231 C 1661.86 235.33 1658.77 238.03 1651 240 M 1660 231 C 1660.62 237.7 1655.12 238.2 1651 240 M 1651 240 C 1616.25 242.34 1582.39 239.9 1509 240 M 1651 240 C 1599.12 238.34 1546.64 239.24 1509 240 M 1509 240 C 1504.96 241.43 1499.73 236.23 1500 231 M 1509 240 C 1502.55 241.86 1500.06 237.97 1500 231 M 1500 231 C 1501.79 214.04 1501.27 199.89 1500 189 M 1500 231 C 1499.35 214.6 1500.54 200.56 1500 189 M 1500 189 C 1500.99 184.49 1502.44 179.16 1509 180 M 1500 189 C 1500.93 182.52 1501.56 180.02 1509 180" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1500" cy="200" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1480" y="180" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1497.1 201.91 C 1497.1 201.91 1497.1 201.91 1497.1 201.91 M 1497.1 201.91 C 1497.1 201.91 1497.1 201.91 1497.1 201.91" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1497.11 201.92 C 1497.11 201.92 1497.11 201.92 1497.11 201.92 M 1497.11 201.92 C 1497.11 201.92 1497.11 201.92 1497.11 201.92" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1490" cy="200" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1470" y="180" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1487.3 203.23 C 1487.3 203.23 1487.3 203.23 1487.3 203.23 M 1487.3 203.23 C 1487.3 203.23 1487.3 203.23 1487.3 203.23" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1487.31 203.24 C 1487.31 203.24 1487.31 203.24 1487.31 203.24 M 1487.31 203.24 C 1487.31 203.24 1487.31 203.24 1487.31 203.24" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1390" y="100" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 110px; margin-left: 1435px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1050 </div> </div> </div> </foreignObject> - <text x="1435" y="114" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1435" y="114" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1050 </text> </switch> </g> - <path d="M 1340 244.71 L 1763.64 269.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 1768.88 269.93 L 1761.69 273.02 L 1763.64 269.63 L 1762.1 266.03 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1340 244.71 L 1763.64 269.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 1768.88 269.93 L 1761.69 273.02 L 1763.64 269.63 L 1762.1 266.03 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> <rect x="1370" y="230" width="70" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 240px; margin-left: 1405px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Adjust top </div> </div> </div> </foreignObject> - <text x="1405" y="244" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1405" y="244" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Adjust top </text> </switch> </g> - <path d="M 720 120 L 954.09 110.13" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 959.33 109.91 L 952.49 113.7 L 954.09 110.13 L 952.19 106.71 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 720 120 L 954.09 110.13" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 959.33 109.91 L 952.49 113.7 L 954.09 110.13 L 952.19 106.71 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> <rect x="850" y="98" width="100" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 108px; margin-left: 900px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> UpdateScrollTop </div> </div> </div> </foreignObject> - <text x="900" y="112" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="900" y="112" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> UpdateScrollTop </text> </switch> @@ -323,16 +323,16 @@ <rect x="640" y="20" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 30px; margin-left: 700px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -1000 </div> </div> </div> </foreignObject> - <text x="700" y="34" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="700" y="34" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -1000 </text> </switch> @@ -340,16 +340,16 @@ <rect x="1170" y="0" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 10px; margin-left: 1230px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -1000 </div> </div> </div> </foreignObject> - <text x="1230" y="14" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1230" y="14" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -1000 </text> </switch> @@ -357,16 +357,16 @@ <rect x="1600" y="0" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 10px; margin-left: 1660px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -1000 </div> </div> </div> </foreignObject> - <text x="1660" y="14" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1660" y="14" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -1000 </text> </switch> @@ -374,55 +374,55 @@ <rect x="1640" y="620" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="1642" y="622" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="1650" y="830" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1651.83 868.83 C 1651.83 868.83 1651.83 868.83 1651.83 868.83 M 1651.83 868.83 C 1651.83 868.83 1651.83 868.83 1651.83 868.83 M 1658.91 864.59 C 1657.53 862.43 1655.44 861.33 1653.96 859.64 M 1658.91 864.59 C 1658.01 863.29 1656.51 862.29 1653.96 859.64 M 1670.22 864.59 C 1667.92 861.45 1662.89 855.95 1653.96 848.33 M 1670.22 864.59 C 1664.71 859.03 1660.18 854.75 1653.96 848.33 M 1681.53 864.59 C 1672.46 858.88 1669.19 851.5 1651.13 834.19 M 1681.53 864.59 C 1673.05 856.55 1665.86 848.82 1651.13 834.19 M 1692.85 864.59 C 1683.91 857.16 1675.84 848.2 1656.78 828.53 M 1692.85 864.59 C 1680.13 851.97 1668.31 839.3 1656.78 828.53 M 1704.16 864.59 C 1691.85 850.99 1676.32 837.99 1668.81 829.24 M 1704.16 864.59 C 1690.12 851.15 1676.9 839.31 1668.81 829.24 M 1715.47 864.59 C 1704.18 851.79 1692.12 841.36 1680.12 829.24 M 1715.47 864.59 C 1707.62 857.75 1700.84 849.09 1680.12 829.24 M 1726.79 864.59 C 1712.29 851.9 1700.15 837.78 1691.43 829.24 M 1726.79 864.59 C 1713.93 853.91 1702.55 841.85 1691.43 829.24 M 1738.1 864.59 C 1731.3 856.94 1719.19 844.21 1702.75 829.24 M 1738.1 864.59 C 1728.57 854.19 1717.87 844.3 1702.75 829.24 M 1749.42 864.59 C 1741.12 857.6 1734.65 850.74 1714.06 829.24 M 1749.42 864.59 C 1735.59 850.84 1722.11 837.73 1714.06 829.24 M 1760.73 864.59 C 1748.23 852.19 1731.33 837.96 1725.37 829.24 M 1760.73 864.59 C 1752.13 856.24 1743.77 847.65 1725.37 829.24 M 1772.04 864.59 C 1763.57 856.23 1754.59 845.89 1736.69 829.24 M 1772.04 864.59 C 1763.63 854.94 1752.41 846.37 1736.69 829.24 M 1783.36 864.59 C 1768.2 848.87 1754.94 839.36 1748 829.24 M 1783.36 864.59 C 1771.24 853.83 1760.1 841.34 1748 829.24 M 1794.67 864.59 C 1783.97 850.8 1770.61 837.79 1759.31 829.24 M 1794.67 864.59 C 1782.39 852.69 1768 839.58 1759.31 829.24 M 1809.52 868.13 C 1800.13 861.41 1794.45 852.63 1770.63 829.24 M 1809.52 868.13 C 1796.59 856.76 1785.63 843.84 1770.63 829.24 M 1814.47 861.76 C 1805.79 854.43 1796.23 844.89 1781.94 829.24 M 1814.47 861.76 C 1808.17 854.68 1800.93 847.8 1781.94 829.24 M 1814.47 850.45 C 1808.35 843.99 1801.12 835.18 1793.26 829.24 M 1814.47 850.45 C 1808.01 844.18 1801.96 837.7 1793.26 829.24 M 1810.93 835.6 C 1809.59 834.26 1808.28 832.47 1804.57 829.24 M 1810.93 835.6 C 1808.56 832.81 1806.47 831.17 1804.57 829.24" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1656 830 M 1656 830 C 1696.07 827.7 1736.65 826.85 1804 830 M 1656 830 C 1711.88 830 1765.11 830.07 1804 830 M 1804 830 C 1808.19 831.11 1811.71 831.01 1810 836 M 1804 830 C 1808.07 830.68 1807.75 833.61 1810 836 M 1810 836 C 1808.95 845.24 1809.85 853.11 1810 864 M 1810 836 C 1810.31 843.94 1810.07 850.76 1810 864 M 1810 864 C 1809.05 869.55 1808.27 870.41 1804 870 M 1810 864 C 1809.41 868.59 1806.05 870.9 1804 870 M 1804 870 C 1768.42 869.13 1734.9 870.23 1656 870 M 1804 870 C 1766.21 869.16 1726.69 870.53 1656 870 M 1656 870 C 1651.69 870.09 1650.75 867.55 1650 864 M 1656 870 C 1649.86 871.59 1648.12 866.58 1650 864 M 1650 864 C 1648.83 853.47 1649.36 846.26 1650 836 M 1650 864 C 1649.34 853.53 1650.61 842.48 1650 836 M 1650 836 C 1651.09 831.98 1650.58 828.13 1656 830 M 1650 836 C 1650.73 833.86 1650.48 828.66 1656 830" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1651.85 868.85 C 1651.85 868.85 1651.85 868.85 1651.85 868.85 M 1651.85 868.85 C 1651.85 868.85 1651.85 868.85 1651.85 868.85 M 1658.92 864.6 C 1657.54 862.45 1655.46 861.34 1653.97 859.66 M 1658.92 864.6 C 1658.03 863.3 1656.52 862.3 1653.97 859.66 M 1670.23 864.6 C 1667.94 861.46 1662.91 855.96 1653.97 848.34 M 1670.23 864.6 C 1664.72 859.05 1660.19 854.77 1653.97 848.34 M 1681.55 864.6 C 1672.47 858.89 1669.21 851.52 1651.14 834.2 M 1681.55 864.6 C 1673.06 856.56 1665.87 848.83 1651.14 834.2 M 1692.86 864.6 C 1683.92 857.18 1675.86 848.21 1656.8 828.54 M 1692.86 864.6 C 1680.14 851.98 1668.33 839.31 1656.8 828.54 M 1704.17 864.6 C 1691.86 851.01 1676.33 838 1668.82 829.25 M 1704.17 864.6 C 1690.13 851.16 1676.91 839.32 1668.82 829.25 M 1715.49 864.6 C 1704.2 851.81 1692.13 841.37 1680.13 829.25 M 1715.49 864.6 C 1707.64 857.76 1700.85 849.1 1680.13 829.25 M 1726.8 864.6 C 1712.3 851.91 1700.17 837.79 1691.45 829.25 M 1726.8 864.6 C 1713.94 853.93 1702.56 841.86 1691.45 829.25 M 1738.11 864.6 C 1731.32 856.95 1719.2 844.23 1702.76 829.25 M 1738.11 864.6 C 1728.58 854.21 1717.89 844.31 1702.76 829.25 M 1749.43 864.6 C 1741.13 857.61 1734.66 850.76 1714.07 829.25 M 1749.43 864.6 C 1735.6 850.85 1722.12 837.74 1714.07 829.25 M 1760.74 864.6 C 1748.25 852.2 1731.34 837.97 1725.39 829.25 M 1760.74 864.6 C 1752.14 856.25 1743.78 847.66 1725.39 829.25 M 1772.06 864.6 C 1763.58 856.24 1754.6 845.9 1736.7 829.25 M 1772.06 864.6 C 1763.64 854.95 1752.42 846.39 1736.7 829.25 M 1783.37 864.6 C 1768.21 848.89 1754.95 839.38 1748.01 829.25 M 1783.37 864.6 C 1771.25 853.84 1760.11 841.35 1748.01 829.25 M 1794.68 864.6 C 1783.98 850.82 1770.62 837.8 1759.33 829.25 M 1794.68 864.6 C 1782.4 852.71 1768.01 839.6 1759.33 829.25 M 1809.53 868.14 C 1800.14 861.43 1794.46 852.64 1770.64 829.25 M 1809.53 868.14 C 1796.6 856.77 1785.64 843.85 1770.64 829.25 M 1814.48 861.78 C 1805.8 854.44 1796.24 844.9 1781.96 829.25 M 1814.48 861.78 C 1808.19 854.7 1800.94 847.81 1781.96 829.25 M 1814.48 850.46 C 1808.36 844 1801.14 835.2 1793.27 829.25 M 1814.48 850.46 C 1808.03 844.19 1801.97 837.71 1793.27 829.25 M 1810.95 835.61 C 1809.6 834.27 1808.29 832.48 1804.58 829.25 M 1810.95 835.61 C 1808.57 832.82 1806.48 831.18 1804.58 829.25" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1656 830 M 1656 830 C 1696.07 827.7 1736.65 826.85 1804 830 M 1656 830 C 1711.88 830 1765.11 830.07 1804 830 M 1804 830 C 1808.19 831.11 1811.71 831.01 1810 836 M 1804 830 C 1808.07 830.68 1807.75 833.61 1810 836 M 1810 836 C 1808.95 845.24 1809.85 853.11 1810 864 M 1810 836 C 1810.31 843.94 1810.07 850.76 1810 864 M 1810 864 C 1809.05 869.55 1808.27 870.41 1804 870 M 1810 864 C 1809.41 868.59 1806.05 870.9 1804 870 M 1804 870 C 1768.42 869.13 1734.9 870.23 1656 870 M 1804 870 C 1766.21 869.16 1726.69 870.53 1656 870 M 1656 870 C 1651.69 870.09 1650.75 867.55 1650 864 M 1656 870 C 1649.86 871.59 1648.12 866.58 1650 864 M 1650 864 C 1648.83 853.47 1649.36 846.26 1650 836 M 1650 864 C 1649.34 853.53 1650.61 842.48 1650 836 M 1650 836 C 1651.09 831.98 1650.58 828.13 1656 830 M 1650 836 C 1650.73 833.86 1650.48 828.66 1656 830" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1650" y="720" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1651.68 758.68 C 1651.68 758.68 1651.68 758.68 1651.68 758.68 M 1651.68 758.68 C 1651.68 758.68 1651.68 758.68 1651.68 758.68 M 1658.75 754.44 C 1657.55 752.63 1655.56 751.4 1654.51 750.2 M 1658.75 754.44 C 1657.46 753.35 1655.85 752.01 1654.51 750.2 M 1670.07 754.44 C 1667.31 753.06 1662.69 749.44 1654.51 738.88 M 1670.07 754.44 C 1667.56 751.48 1663.32 748.49 1654.51 738.88 M 1681.38 754.44 C 1673.21 745.43 1662.96 735.16 1651.68 724.74 M 1681.38 754.44 C 1675 748.61 1669.64 741.54 1651.68 724.74 M 1692.69 754.44 C 1682.64 744.27 1669.9 731.58 1657.34 719.08 M 1692.69 754.44 C 1681.67 742.94 1670.21 731.22 1657.34 719.08 M 1704.01 754.44 C 1693.24 744.39 1684.98 732.77 1668.65 719.08 M 1704.01 754.44 C 1690.82 740.57 1677.64 728.28 1668.65 719.08 M 1715.32 754.44 C 1703.2 742.8 1690.7 730.33 1679.96 719.08 M 1715.32 754.44 C 1700.58 739.86 1686.23 726.17 1679.96 719.08 M 1726.63 754.44 C 1713.95 743.13 1700.3 728.92 1691.28 719.08 M 1726.63 754.44 C 1718.3 745.73 1708.12 737 1691.28 719.08 M 1737.95 754.44 C 1729.36 744.24 1719.31 737.09 1702.59 719.08 M 1737.95 754.44 C 1727.77 743.75 1716.55 733.81 1702.59 719.08 M 1749.26 754.44 C 1741.32 744.55 1731.75 736.36 1713.91 719.08 M 1749.26 754.44 C 1737.21 742.8 1725.2 730.52 1713.91 719.08 M 1760.57 754.44 C 1750.7 745.32 1743.72 734.98 1725.22 719.08 M 1760.57 754.44 C 1748.91 742.17 1737.15 730.3 1725.22 719.08 M 1771.89 754.44 C 1760.46 744.6 1750.91 736.46 1736.53 719.08 M 1771.89 754.44 C 1761.23 743 1750.75 733.01 1736.53 719.08 M 1783.2 754.44 C 1772.28 742.59 1760.72 730.25 1747.85 719.08 M 1783.2 754.44 C 1771.76 742.96 1762.44 733.4 1747.85 719.08 M 1794.52 754.44 C 1780.21 740.82 1768.61 725.73 1759.16 719.08 M 1794.52 754.44 C 1782.75 743.68 1774.1 732.55 1759.16 719.08 M 1809.37 757.97 C 1794.09 743.47 1783.57 731.54 1770.47 719.08 M 1809.37 757.97 C 1799.21 746.79 1788.63 735.34 1770.47 719.08 M 1814.31 751.61 C 1803.97 739.69 1791.31 728.67 1781.79 719.08 M 1814.31 751.61 C 1805.66 743.44 1798.26 737.58 1781.79 719.08 M 1814.31 740.3 C 1809.68 735.15 1806.05 732.24 1793.1 719.08 M 1814.31 740.3 C 1809.29 735.89 1806.03 731.89 1793.1 719.08 M 1810.78 725.45 C 1807.92 724.28 1807.61 721.17 1804.42 719.08 M 1810.78 725.45 C 1809.21 723.88 1807.3 722.14 1804.42 719.08" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1656 720 M 1656 720 C 1686.97 718.84 1722.3 719.02 1804 720 M 1656 720 C 1696.66 720.88 1739 720.31 1804 720 M 1804 720 C 1809 719.01 1810.83 722.01 1810 726 M 1804 720 C 1809.53 720.94 1807.72 720.78 1810 726 M 1810 726 C 1811.53 733.97 1808.87 744.59 1810 754 M 1810 726 C 1809.48 732.95 1809.67 739.88 1810 754 M 1810 754 C 1811.32 757.42 1806.4 758.04 1804 760 M 1810 754 C 1808.73 756.18 1806.83 760.59 1804 760 M 1804 760 C 1757.94 759.98 1711.32 761.11 1656 760 M 1804 760 C 1768.92 760.39 1733.25 760.51 1656 760 M 1656 760 C 1650.74 761.99 1651.5 758.8 1650 754 M 1656 760 C 1654.01 761.23 1648.52 760.02 1650 754 M 1650 754 C 1649.89 746.01 1649.61 741.42 1650 726 M 1650 754 C 1649.89 745.4 1650.6 735.94 1650 726 M 1650 726 C 1651.79 721.21 1651.04 720.8 1656 720 M 1650 726 C 1649.93 723.66 1651.14 721.95 1656 720" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <rect x="1520" y="680" width="200" height="280" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="1522" y="682" width="196" height="276" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <path d="M 1651.69 758.69 C 1651.69 758.69 1651.69 758.69 1651.69 758.69 M 1651.69 758.69 C 1651.69 758.69 1651.69 758.69 1651.69 758.69 M 1658.76 754.45 C 1657.36 752.34 1655.04 750.9 1653.81 749.5 M 1658.76 754.45 C 1657.26 753.18 1655.38 751.61 1653.81 749.5 M 1670.08 754.45 C 1667.18 752.93 1662.42 749.17 1653.81 738.19 M 1670.08 754.45 C 1667.43 751.34 1663.04 748.21 1653.81 738.19 M 1681.39 754.45 C 1673.22 745.44 1662.97 735.18 1651.69 724.75 M 1681.39 754.45 C 1675.01 748.62 1669.65 741.55 1651.69 724.75 M 1692.71 754.45 C 1682.66 744.28 1669.91 731.59 1657.35 719.1 M 1692.71 754.45 C 1681.68 742.95 1670.22 731.23 1657.35 719.1 M 1704.02 754.45 C 1693.25 744.4 1685 732.78 1668.66 719.1 M 1704.02 754.45 C 1690.84 740.58 1677.65 728.29 1668.66 719.1 M 1715.33 754.45 C 1703.21 742.81 1690.72 730.35 1679.98 719.1 M 1715.33 754.45 C 1700.59 739.87 1686.24 726.18 1679.98 719.1 M 1726.65 754.45 C 1713.97 743.14 1700.31 728.93 1691.29 719.1 M 1726.65 754.45 C 1718.31 745.74 1708.14 737.02 1691.29 719.1 M 1737.96 754.45 C 1729.37 744.25 1719.32 737.1 1702.6 719.1 M 1737.96 754.45 C 1727.78 743.76 1716.56 733.83 1702.6 719.1 M 1749.27 754.45 C 1741.33 744.56 1731.76 736.37 1713.92 719.1 M 1749.27 754.45 C 1737.22 742.81 1725.22 730.53 1713.92 719.1 M 1760.59 754.45 C 1750.72 745.33 1743.73 734.99 1725.23 719.1 M 1760.59 754.45 C 1748.92 742.18 1737.16 730.32 1725.23 719.1 M 1771.9 754.45 C 1760.47 744.61 1750.92 736.47 1736.55 719.1 M 1771.9 754.45 C 1761.24 743.01 1750.76 733.02 1736.55 719.1 M 1783.21 754.45 C 1772.29 742.6 1760.74 730.26 1747.86 719.1 M 1783.21 754.45 C 1771.77 742.97 1762.46 733.41 1747.86 719.1 M 1794.53 754.45 C 1780.22 740.83 1768.63 725.74 1759.17 719.1 M 1794.53 754.45 C 1782.76 743.7 1774.12 732.56 1759.17 719.1 M 1809.38 757.99 C 1794.1 743.48 1783.59 731.55 1770.49 719.1 M 1809.38 757.99 C 1799.23 746.81 1788.65 735.35 1770.49 719.1 M 1814.33 751.62 C 1803.98 739.71 1791.32 728.68 1781.8 719.1 M 1814.33 751.62 C 1805.67 743.46 1798.27 737.6 1781.8 719.1 M 1814.33 740.31 C 1809.69 735.16 1806.06 732.26 1793.11 719.1 M 1814.33 740.31 C 1809.3 735.9 1806.04 731.9 1793.11 719.1 M 1810.79 725.46 C 1807.93 724.29 1807.63 721.18 1804.43 719.1 M 1810.79 725.46 C 1809.22 723.89 1807.32 722.15 1804.43 719.1" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1656 720 M 1656 720 C 1686.97 718.84 1722.3 719.02 1804 720 M 1656 720 C 1696.66 720.88 1739 720.31 1804 720 M 1804 720 C 1809 719.01 1810.83 722.01 1810 726 M 1804 720 C 1809.53 720.94 1807.72 720.78 1810 726 M 1810 726 C 1811.53 733.97 1808.87 744.59 1810 754 M 1810 726 C 1809.48 732.95 1809.67 739.88 1810 754 M 1810 754 C 1811.32 757.42 1806.4 758.04 1804 760 M 1810 754 C 1808.73 756.18 1806.83 760.59 1804 760 M 1804 760 C 1757.94 759.98 1711.32 761.11 1656 760 M 1804 760 C 1768.92 760.39 1733.25 760.51 1656 760 M 1656 760 C 1650.74 761.99 1651.5 758.8 1650 754 M 1656 760 C 1654.01 761.23 1648.52 760.02 1650 754 M 1650 754 C 1649.89 746.01 1649.61 741.42 1650 726 M 1650 754 C 1649.89 745.4 1650.6 735.94 1650 726 M 1650 726 C 1651.79 721.21 1651.04 720.8 1656 720 M 1650 726 C 1649.93 723.66 1651.14 721.95 1656 720" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <rect x="1520" y="680" width="200" height="280" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="1522" y="682" width="196" height="276" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="1520" y="650" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 660px; margin-left: 1580px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="1580" y="664" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1580" y="664" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> </g> <rect x="1540" y="880" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1541.43 918.43 C 1541.43 918.43 1541.43 918.43 1541.43 918.43 M 1541.43 918.43 C 1541.43 918.43 1541.43 918.43 1541.43 918.43 M 1548.5 914.19 C 1547.37 913.55 1547.16 912.72 1544.26 909.94 M 1548.5 914.19 C 1547.41 913.27 1546.32 912.05 1544.26 909.94 M 1559.81 914.19 C 1553.96 910.97 1549.96 906.53 1544.26 898.63 M 1559.81 914.19 C 1555.15 909.83 1550.06 903.6 1544.26 898.63 M 1571.13 914.19 C 1561.85 904.6 1548.54 895.1 1541.43 884.49 M 1571.13 914.19 C 1563.41 906.63 1556.92 899.46 1541.43 884.49 M 1582.44 914.19 C 1568.74 900.53 1557.42 888.12 1547.09 878.83 M 1582.44 914.19 C 1575.7 907.17 1566.07 897.81 1547.09 878.83 M 1593.75 914.19 C 1581.21 900.88 1570.11 891.06 1558.4 878.83 M 1593.75 914.19 C 1584.48 904.51 1576.15 895.1 1558.4 878.83 M 1605.07 914.19 C 1592.1 902.48 1579.26 889.28 1569.71 878.83 M 1605.07 914.19 C 1591.94 902.03 1578.94 889.4 1569.71 878.83 M 1616.38 914.19 C 1604.11 902.21 1588.8 889.8 1581.03 878.83 M 1616.38 914.19 C 1603.45 901.64 1590.71 888.46 1581.03 878.83 M 1628.4 914.89 C 1619.34 907.49 1613.43 901.89 1592.34 878.83 M 1628.4 914.89 C 1620.85 905.98 1613.15 897.63 1592.34 878.83 M 1639.72 914.89 C 1628.74 905.49 1619.76 897.76 1603.65 878.83 M 1639.72 914.89 C 1632.71 906.87 1624.47 899.09 1603.65 878.83 M 1651.03 914.89 C 1644.38 908.08 1632.39 895.55 1614.97 878.83 M 1651.03 914.89 C 1638.79 902.85 1626.31 889.84 1614.97 878.83 M 1662.34 914.89 C 1650.87 903.25 1639.47 888.73 1626.28 878.83 M 1662.34 914.89 C 1652.29 904 1642.3 894.86 1626.28 878.83 M 1673.66 914.89 C 1665.32 906.56 1652.6 897.53 1637.6 878.83 M 1673.66 914.89 C 1662.83 902.8 1650.17 891.04 1637.6 878.83 M 1684.97 914.89 C 1672.03 899.11 1654.48 887.9 1648.91 878.83 M 1684.97 914.89 C 1669.41 901.23 1656.86 886.58 1648.91 878.83 M 1699.11 917.72 C 1691.63 910.39 1681.39 899.69 1660.22 878.83 M 1699.11 917.72 C 1688.53 906.5 1678.17 898.05 1660.22 878.83 M 1704.77 912.07 C 1695.96 903.49 1685.93 895.69 1671.54 878.83 M 1704.77 912.07 C 1692.72 900.75 1681.27 888.19 1671.54 878.83 M 1704.77 900.75 C 1702.08 896.97 1696.57 893.04 1683.56 879.54 M 1704.77 900.75 C 1696.86 893.79 1691.34 886.95 1683.56 879.54 M 1700.53 885.2 C 1699.1 883.61 1697.94 881.28 1694.87 879.54 M 1700.53 885.2 C 1698.34 883.53 1696.26 881.04 1694.87 879.54" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1546 880 M 1546 880 C 1592.6 878.6 1640.08 878.57 1694 880 M 1546 880 C 1602.26 878.92 1659.33 878.44 1694 880 M 1694 880 C 1697.66 880.18 1701.62 880.33 1700 886 M 1694 880 C 1695.76 881.81 1700.85 882.9 1700 886 M 1700 886 C 1700.56 894.68 1699.96 904.17 1700 914 M 1700 886 C 1699.16 892.16 1699.87 899.09 1700 914 M 1700 914 C 1701.45 917.5 1699.96 921.17 1694 920 M 1700 914 C 1698.64 916.69 1697.77 922.02 1694 920 M 1694 920 C 1643.96 922.83 1596.66 919.79 1546 920 M 1694 920 C 1664.94 921.28 1635.09 920.87 1546 920 M 1546 920 C 1542.61 921.89 1541.6 917.16 1540 914 M 1546 920 C 1543.53 918.04 1539.62 918.81 1540 914 M 1540 914 C 1539.59 903.88 1539.75 895.36 1540 886 M 1540 914 C 1539.63 904.38 1540.36 894.86 1540 886 M 1540 886 C 1538.43 881.29 1540.19 879.7 1546 880 M 1540 886 C 1541.07 881.33 1540.6 882.19 1546 880" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1541.44 918.44 C 1541.44 918.44 1541.44 918.44 1541.44 918.44 M 1541.44 918.44 C 1541.44 918.44 1541.44 918.44 1541.44 918.44 M 1548.51 914.2 C 1547.39 913.56 1547.17 912.73 1544.27 909.96 M 1548.51 914.2 C 1547.42 913.29 1546.33 912.06 1544.27 909.96 M 1559.83 914.2 C 1553.98 910.98 1549.97 906.55 1544.27 898.64 M 1559.83 914.2 C 1555.16 909.84 1550.08 903.61 1544.27 898.64 M 1571.14 914.2 C 1561.87 904.61 1548.55 895.12 1541.44 884.5 M 1571.14 914.2 C 1563.42 906.64 1556.94 899.48 1541.44 884.5 M 1582.45 914.2 C 1568.75 900.54 1557.44 888.14 1547.1 878.84 M 1582.45 914.2 C 1575.72 907.19 1566.08 897.82 1547.1 878.84 M 1593.77 914.2 C 1581.23 900.89 1570.12 891.07 1558.41 878.84 M 1593.77 914.2 C 1584.49 904.52 1576.17 895.12 1558.41 878.84 M 1605.08 914.2 C 1592.11 902.49 1579.28 889.29 1569.73 878.84 M 1605.08 914.2 C 1591.95 902.05 1578.95 889.41 1569.73 878.84 M 1616.4 914.2 C 1604.12 902.22 1588.81 889.82 1581.04 878.84 M 1616.4 914.2 C 1603.46 901.65 1590.72 888.47 1581.04 878.84 M 1627.71 914.2 C 1618.79 906.94 1613.03 901.48 1592.35 878.84 M 1627.71 914.2 C 1620.31 905.45 1612.77 897.27 1592.35 878.84 M 1639.73 914.91 C 1628.76 905.51 1619.77 897.77 1603.67 878.84 M 1639.73 914.91 C 1632.72 906.88 1624.48 899.1 1603.67 878.84 M 1651.04 914.91 C 1644.39 908.1 1632.4 895.57 1614.98 878.84 M 1651.04 914.91 C 1638.8 902.86 1626.33 889.85 1614.98 878.84 M 1662.36 914.91 C 1650.88 903.26 1639.48 888.74 1626.29 878.84 M 1662.36 914.91 C 1652.3 904.02 1642.32 894.87 1626.29 878.84 M 1673.67 914.91 C 1665.33 906.57 1652.61 897.54 1637.61 878.84 M 1673.67 914.91 C 1662.84 902.81 1650.18 891.05 1637.61 878.84 M 1684.98 914.91 C 1672.04 899.12 1654.49 887.92 1648.92 878.84 M 1684.98 914.91 C 1669.42 901.24 1656.87 886.59 1648.92 878.84 M 1699.13 917.73 C 1691.64 910.4 1681.41 899.7 1660.24 878.84 M 1699.13 917.73 C 1688.54 906.51 1678.18 898.06 1660.24 878.84 M 1704.78 912.08 C 1695.97 903.5 1685.95 895.7 1671.55 878.84 M 1704.78 912.08 C 1692.74 900.76 1681.29 888.2 1671.55 878.84 M 1704.78 900.76 C 1702.1 896.98 1696.59 893.05 1683.57 879.55 M 1704.78 900.76 C 1696.87 893.8 1691.35 886.97 1683.57 879.55 M 1700.54 885.21 C 1699.12 883.62 1697.96 881.29 1694.88 879.55 M 1700.54 885.21 C 1698.35 883.54 1696.27 881.06 1694.88 879.55" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1546 880 M 1546 880 C 1592.6 878.6 1640.08 878.57 1694 880 M 1546 880 C 1602.26 878.92 1659.33 878.44 1694 880 M 1694 880 C 1697.66 880.18 1701.62 880.33 1700 886 M 1694 880 C 1695.76 881.81 1700.85 882.9 1700 886 M 1700 886 C 1700.56 894.68 1699.96 904.17 1700 914 M 1700 886 C 1699.16 892.16 1699.87 899.09 1700 914 M 1700 914 C 1701.45 917.5 1699.96 921.17 1694 920 M 1700 914 C 1698.64 916.69 1697.77 922.02 1694 920 M 1694 920 C 1643.96 922.83 1596.66 919.79 1546 920 M 1694 920 C 1664.94 921.28 1635.09 920.87 1546 920 M 1546 920 C 1542.61 921.89 1541.6 917.16 1540 914 M 1546 920 C 1543.53 918.04 1539.62 918.81 1540 914 M 1540 914 C 1539.59 903.88 1539.75 895.36 1540 886 M 1540 914 C 1539.63 904.38 1540.36 894.86 1540 886 M 1540 886 C 1538.43 881.29 1540.19 879.7 1546 880 M 1540 886 C 1541.07 881.33 1540.6 882.19 1546 880" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1540" y="760" width="160" height="60" rx="9" ry="9" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1541.97 817.47 C 1541.97 817.47 1541.97 817.47 1541.97 817.47 M 1541.97 817.47 C 1541.97 817.47 1541.97 817.47 1541.97 817.47 M 1550.46 814.65 C 1548.2 812.38 1547.02 810.08 1543.39 807.57 M 1550.46 814.65 C 1549.41 813.08 1547.23 811.1 1543.39 807.57 M 1561.77 814.65 C 1558.89 808.15 1552.75 805.1 1543.39 796.26 M 1561.77 814.65 C 1554.8 808.78 1549.05 801.75 1543.39 796.26 M 1573.09 814.65 C 1564.29 806.84 1557.27 796.92 1543.39 784.95 M 1573.09 814.65 C 1567.17 808.5 1560.29 802.61 1543.39 784.95 M 1584.4 814.65 C 1575.91 805.94 1568.55 798.45 1543.39 773.63 M 1584.4 814.65 C 1571.26 802.45 1558.38 788.69 1543.39 773.63 M 1595.71 814.65 C 1584.8 803.7 1570.76 792.49 1542.68 761.61 M 1595.71 814.65 C 1584.22 802.42 1572.16 790.62 1542.68 761.61 M 1607.03 814.65 C 1593.43 799.31 1581.39 788.11 1550.46 758.08 M 1607.03 814.65 C 1586.54 795.18 1567.07 774.64 1550.46 758.08 M 1618.34 814.65 C 1598.71 792.24 1577.75 771.35 1561.77 758.08 M 1618.34 814.65 C 1599.1 796.78 1582.21 776.82 1561.77 758.08 M 1629.66 814.65 C 1616.18 801.35 1600.04 787.31 1573.09 758.08 M 1629.66 814.65 C 1609.05 795.47 1590.16 775.96 1573.09 758.08 M 1640.97 814.65 C 1619.26 794.07 1597.91 768.61 1585.11 758.78 M 1640.97 814.65 C 1628.3 800.87 1613.51 788.77 1585.11 758.78 M 1652.28 814.65 C 1638.52 800.91 1625.53 785.65 1596.42 758.78 M 1652.28 814.65 C 1631.79 794.64 1612.29 775.78 1596.42 758.78 M 1663.6 814.65 C 1646.92 797.91 1630.08 780.43 1607.74 758.78 M 1663.6 814.65 C 1647.58 798.91 1630.93 782.54 1607.74 758.78 M 1674.91 814.65 C 1656.95 796.8 1640.74 780.43 1619.05 758.78 M 1674.91 814.65 C 1651.79 792.93 1629.86 770.96 1619.05 758.78 M 1691.17 819.6 C 1675.87 802.19 1657.24 785.18 1630.36 758.78 M 1691.17 819.6 C 1675.69 804.25 1663.36 791.28 1630.36 758.78 M 1698.95 816.06 C 1685.36 801.31 1670.95 789.42 1641.68 758.78 M 1698.95 816.06 C 1681.23 796.88 1661.7 778.86 1641.68 758.78 M 1704.61 810.4 C 1685.76 792.26 1665.36 771.6 1652.99 758.78 M 1704.61 810.4 C 1690.58 797.39 1676.66 782.14 1652.99 758.78 M 1704.61 799.09 C 1690.67 783.53 1679.35 770.08 1664.3 758.78 M 1704.61 799.09 C 1691.05 787.67 1678.94 774.04 1664.3 758.78 M 1704.61 787.78 C 1696.35 779.02 1689.67 769.17 1675.62 758.78 M 1704.61 787.78 C 1697.2 781.65 1690.03 774.36 1675.62 758.78 M 1704.61 776.46 C 1699.78 769.28 1692.05 765.51 1686.93 758.78 M 1704.61 776.46 C 1698.36 771.09 1691.22 763.06 1686.93 758.78" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1549 760 M 1549 760 C 1604 758.85 1661.3 762.2 1691 760 M 1549 760 C 1600.7 760.4 1654.21 759.11 1691 760 M 1691 760 C 1695.28 759.61 1701.33 763.32 1700 769 M 1691 760 C 1697.23 758.26 1699.18 764.97 1700 769 M 1700 769 C 1701.06 777.93 1701.85 788.02 1700 811 M 1700 769 C 1699.52 783.43 1699.48 798.44 1700 811 M 1700 811 C 1700.93 816.1 1696.43 819.41 1691 820 M 1700 811 C 1701.97 818.64 1695.88 821.81 1691 820 M 1691 820 C 1658.52 821.02 1627.54 822.49 1549 820 M 1691 820 C 1655.34 819.96 1619.48 818.11 1549 820 M 1549 820 C 1544.67 820.46 1539.44 817.23 1540 811 M 1549 820 C 1545.28 820.95 1537.83 816.8 1540 811 M 1540 811 C 1537.59 802.5 1541 790.11 1540 769 M 1540 811 C 1540.2 800.79 1538.83 787.74 1540 769 M 1540 769 C 1539.16 762.44 1544.27 761.27 1549 760 M 1540 769 C 1542.02 762.23 1542.63 758.48 1549 760" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1541.99 817.49 C 1541.99 817.49 1541.99 817.49 1541.99 817.49 M 1541.99 817.49 C 1541.99 817.49 1541.99 817.49 1541.99 817.49 M 1550.47 814.66 C 1548.21 812.39 1547.03 810.09 1543.4 807.59 M 1550.47 814.66 C 1549.43 813.09 1547.24 811.11 1543.4 807.59 M 1561.79 814.66 C 1558.9 808.16 1552.77 805.12 1543.4 796.27 M 1561.79 814.66 C 1554.81 808.79 1549.07 801.76 1543.4 796.27 M 1573.1 814.66 C 1564.3 806.86 1557.28 796.93 1543.4 784.96 M 1573.1 814.66 C 1567.18 808.51 1560.3 802.62 1543.4 784.96 M 1584.41 814.66 C 1575.92 805.95 1568.56 798.46 1543.4 773.65 M 1584.41 814.66 C 1571.28 802.47 1558.4 788.7 1543.4 773.65 M 1595.73 814.66 C 1584.81 803.71 1570.77 792.51 1542.69 761.63 M 1595.73 814.66 C 1584.23 802.43 1572.18 790.64 1542.69 761.63 M 1607.04 814.66 C 1593.44 799.32 1581.4 788.12 1550.47 758.09 M 1607.04 814.66 C 1586.55 795.19 1567.08 774.65 1550.47 758.09 M 1618.35 814.66 C 1598.72 792.25 1577.76 771.36 1561.79 758.09 M 1618.35 814.66 C 1599.11 796.79 1582.22 776.83 1561.79 758.09 M 1629.67 814.66 C 1616.19 801.37 1600.06 787.32 1573.1 758.09 M 1629.67 814.66 C 1609.06 795.48 1590.17 775.97 1573.1 758.09 M 1640.98 814.66 C 1619 793.8 1597.38 768.06 1584.41 758.09 M 1640.98 814.66 C 1628.14 800.71 1613.17 788.45 1584.41 758.09 M 1652.3 814.66 C 1638.53 800.92 1625.55 785.67 1596.43 758.8 M 1652.3 814.66 C 1631.81 794.65 1612.3 775.8 1596.43 758.8 M 1663.61 814.66 C 1646.93 797.92 1630.09 780.44 1607.75 758.8 M 1663.61 814.66 C 1647.6 798.92 1630.94 782.55 1607.75 758.8 M 1674.92 814.66 C 1656.97 796.81 1640.75 780.44 1619.06 758.8 M 1674.92 814.66 C 1651.81 792.94 1629.88 770.97 1619.06 758.8 M 1691.19 819.61 C 1675.89 802.21 1657.25 785.2 1630.38 758.8 M 1691.19 819.61 C 1675.7 804.26 1663.37 791.29 1630.38 758.8 M 1698.96 816.07 C 1685.38 801.32 1670.96 789.43 1641.69 758.8 M 1698.96 816.07 C 1681.24 796.89 1661.72 778.87 1641.69 758.8 M 1704.62 810.42 C 1685.77 792.27 1665.37 771.61 1653 758.8 M 1704.62 810.42 C 1690.59 797.4 1676.67 782.16 1653 758.8 M 1704.62 799.1 C 1690.68 783.55 1679.36 770.09 1664.32 758.8 M 1704.62 799.1 C 1691.07 787.69 1678.95 774.05 1664.32 758.8 M 1704.62 787.79 C 1696.36 779.03 1689.69 769.18 1675.63 758.8 M 1704.62 787.79 C 1697.21 781.66 1690.04 774.37 1675.63 758.8 M 1704.62 776.48 C 1699.79 769.29 1692.06 765.52 1686.94 758.8 M 1704.62 776.48 C 1698.37 771.11 1691.24 763.08 1686.94 758.8" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1549 760 M 1549 760 C 1604 758.85 1661.3 762.2 1691 760 M 1549 760 C 1600.7 760.4 1654.21 759.11 1691 760 M 1691 760 C 1695.28 759.61 1701.33 763.32 1700 769 M 1691 760 C 1697.23 758.26 1699.18 764.97 1700 769 M 1700 769 C 1701.06 777.93 1701.85 788.02 1700 811 M 1700 769 C 1699.52 783.43 1699.48 798.44 1700 811 M 1700 811 C 1700.93 816.1 1696.43 819.41 1691 820 M 1700 811 C 1701.97 818.64 1695.88 821.81 1691 820 M 1691 820 C 1658.52 821.02 1627.54 822.49 1549 820 M 1691 820 C 1655.34 819.96 1619.48 818.11 1549 820 M 1549 820 C 1544.67 820.46 1539.44 817.23 1540 811 M 1549 820 C 1545.28 820.95 1537.83 816.8 1540 811 M 1540 811 C 1537.59 802.5 1541 790.11 1540 769 M 1540 811 C 1540.2 800.79 1538.83 787.74 1540 769 M 1540 769 C 1539.16 762.44 1544.27 761.27 1549 760 M 1540 769 C 1542.02 762.23 1542.63 758.48 1549 760" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1540" cy="780" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1520" y="760" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1537.15 784.12 C 1537.15 784.12 1537.15 784.12 1537.15 784.12 M 1537.15 784.12 C 1537.15 784.12 1537.15 784.12 1537.15 784.12 M 1544.92 780.58 C 1543.61 777.87 1541.46 776.58 1539.27 774.93 M 1544.92 780.58 C 1542.44 778.5 1540.69 776.18 1539.27 774.93" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1537.16 784.13 C 1537.16 784.13 1537.16 784.13 1537.16 784.13 M 1537.16 784.13 C 1537.16 784.13 1537.16 784.13 1537.16 784.13 M 1544.94 780.6 C 1543.63 777.88 1541.48 776.59 1539.28 774.94 M 1544.94 780.6 C 1542.45 778.52 1540.7 776.19 1539.28 774.94" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1530" cy="780" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1510" y="760" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1528.02 783.35 C 1528.02 783.35 1528.02 783.35 1528.02 783.35 M 1528.02 783.35 C 1528.02 783.35 1528.02 783.35 1528.02 783.35" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1528.03 783.36 C 1528.03 783.36 1528.03 783.36 1528.03 783.36 M 1528.03 783.36 C 1528.03 783.36 1528.03 783.36 1528.03 783.36" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1430" y="680" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 690px; margin-left: 1475px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1050 </div> </div> </div> </foreignObject> - <text x="1475" y="694" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1475" y="694" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1050 </text> </switch> @@ -430,16 +430,16 @@ <rect x="1645" y="580" width="110" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 590px; margin-left: 1700px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -950 </div> </div> </div> </foreignObject> - <text x="1700" y="594" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1700" y="594" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -950 </text> </switch> @@ -447,55 +447,55 @@ <rect x="2080" y="620" width="180" height="400" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="2082" y="622" width="176" height="396" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <rect x="2090" y="830" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 2091.74 868.74 C 2091.74 868.74 2091.74 868.74 2091.74 868.74 M 2091.74 868.74 C 2091.74 868.74 2091.74 868.74 2091.74 868.74 M 2098.82 864.5 C 2097.08 863.65 2096.72 861.59 2093.87 859.55 M 2098.82 864.5 C 2097.21 862.67 2095.07 860.69 2093.87 859.55 M 2110.13 864.5 C 2105.84 859.52 2097.97 854.48 2093.87 848.24 M 2110.13 864.5 C 2104.28 858.46 2098.27 852.53 2093.87 848.24 M 2121.44 864.5 C 2114.9 856.26 2106.41 848.31 2091.74 834.8 M 2121.44 864.5 C 2110.88 852.88 2101.16 843.08 2091.74 834.8 M 2132.76 864.5 C 2123.93 855.27 2117.73 849.32 2097.4 829.15 M 2132.76 864.5 C 2121.86 853.47 2112.06 843.5 2097.4 829.15 M 2144.07 864.5 C 2133.09 851.32 2118.94 840.73 2108.72 829.15 M 2144.07 864.5 C 2130.57 849.91 2116.81 836.02 2108.72 829.15 M 2155.38 864.5 C 2143.31 852.49 2134.63 841.45 2120.03 829.15 M 2155.38 864.5 C 2146.27 856.82 2139.3 848.15 2120.03 829.15 M 2166.7 864.5 C 2154.25 853.29 2144.89 843.29 2131.34 829.15 M 2166.7 864.5 C 2157.19 854.09 2148.4 844.81 2131.34 829.15 M 2178.01 864.5 C 2167.94 852.74 2157.42 845.39 2142.66 829.15 M 2178.01 864.5 C 2167.47 854.42 2158.91 843.98 2142.66 829.15 M 2189.33 864.5 C 2182.86 856.43 2172.64 847.35 2153.97 829.15 M 2189.33 864.5 C 2178.21 854.05 2168.39 843.21 2153.97 829.15 M 2200.64 864.5 C 2190.89 854.63 2182.31 849.03 2165.28 829.15 M 2200.64 864.5 C 2191.32 854.54 2180.73 844.99 2165.28 829.15 M 2211.95 864.5 C 2206.23 855.55 2198.74 848.06 2176.6 829.15 M 2211.95 864.5 C 2203.56 856.48 2194.23 846.64 2176.6 829.15 M 2223.27 864.5 C 2208.68 853 2194.48 835.99 2187.91 829.15 M 2223.27 864.5 C 2216.18 857.08 2206.76 847.34 2187.91 829.15 M 2234.58 864.5 C 2221.77 852.42 2209.06 836.85 2199.23 829.15 M 2234.58 864.5 C 2221.44 851.15 2209.38 838.26 2199.23 829.15 M 2249.43 868.04 C 2238.88 858.15 2229.51 848.81 2210.54 829.15 M 2249.43 868.04 C 2240.15 858.89 2231.88 850.33 2210.54 829.15 M 2254.38 861.67 C 2245.62 852.51 2234.11 840.7 2221.85 829.15 M 2254.38 861.67 C 2248.06 855.3 2241.43 847.9 2221.85 829.15 M 2254.38 850.36 C 2248.32 843.78 2239.17 834.24 2233.17 829.15 M 2254.38 850.36 C 2247.7 842.91 2241.78 836.82 2233.17 829.15 M 2250.84 835.51 C 2248.97 833.34 2246.75 831.49 2244.48 829.15 M 2250.84 835.51 C 2248.2 832.68 2245.88 830.28 2244.48 829.15" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 2096 830 M 2096 830 C 2144.7 830.71 2188.41 829.41 2244 830 M 2096 830 C 2138.23 829.59 2180.52 829.54 2244 830 M 2244 830 C 2249.31 830.47 2251.48 833.37 2250 836 M 2244 830 C 2246.2 829.71 2250.58 830.06 2250 836 M 2250 836 C 2251.19 844.05 2249.31 850.39 2250 864 M 2250 836 C 2249.32 844.54 2249.35 853.71 2250 864 M 2250 864 C 2251.62 867.02 2247.52 869.04 2244 870 M 2250 864 C 2252.16 869.54 2246.5 871.74 2244 870 M 2244 870 C 2206.52 868.06 2168.72 869.62 2096 870 M 2244 870 C 2202.29 870.11 2162.7 868.81 2096 870 M 2096 870 C 2093.09 868 2088.8 866.6 2090 864 M 2096 870 C 2094.06 872.28 2091.73 870.1 2090 864 M 2090 864 C 2091.47 852.53 2088.72 840.25 2090 836 M 2090 864 C 2090.6 857.17 2090.18 851 2090 836 M 2090 836 C 2091.92 833.52 2093.65 830.3 2096 830 M 2090 836 C 2090.63 833.32 2093.53 828.86 2096 830" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 2091.76 868.76 C 2091.76 868.76 2091.76 868.76 2091.76 868.76 M 2091.76 868.76 C 2091.76 868.76 2091.76 868.76 2091.76 868.76 M 2098.83 864.52 C 2097.09 863.66 2096.73 861.6 2093.88 859.57 M 2098.83 864.52 C 2097.22 862.69 2095.08 860.71 2093.88 859.57 M 2110.14 864.52 C 2105.85 859.54 2097.99 854.5 2093.88 848.25 M 2110.14 864.52 C 2104.29 858.47 2098.28 852.55 2093.88 848.25 M 2121.46 864.52 C 2114.92 856.28 2106.42 848.32 2091.76 834.82 M 2121.46 864.52 C 2110.89 852.89 2101.17 843.09 2091.76 834.82 M 2132.77 864.52 C 2123.95 855.29 2117.75 849.34 2097.41 829.16 M 2132.77 864.52 C 2121.88 853.48 2112.08 843.51 2097.41 829.16 M 2144.08 864.52 C 2133.1 851.34 2118.95 840.74 2108.73 829.16 M 2144.08 864.52 C 2130.58 849.92 2116.82 836.03 2108.73 829.16 M 2155.4 864.52 C 2143.33 852.5 2134.64 841.46 2120.04 829.16 M 2155.4 864.52 C 2146.28 856.83 2139.32 848.16 2120.04 829.16 M 2166.71 864.52 C 2154.27 853.3 2144.9 843.3 2131.36 829.16 M 2166.71 864.52 C 2157.2 854.11 2148.41 844.82 2131.36 829.16 M 2178.02 864.52 C 2167.95 852.76 2157.43 845.4 2142.67 829.16 M 2178.02 864.52 C 2167.49 854.43 2158.92 844 2142.67 829.16 M 2189.34 864.52 C 2182.87 856.44 2172.65 847.36 2153.98 829.16 M 2189.34 864.52 C 2178.23 854.06 2168.4 843.22 2153.98 829.16 M 2200.65 864.52 C 2190.9 854.65 2182.32 849.04 2165.3 829.16 M 2200.65 864.52 C 2191.33 854.55 2180.75 845.01 2165.3 829.16 M 2211.97 864.52 C 2206.25 855.56 2198.75 848.07 2176.61 829.16 M 2211.97 864.52 C 2203.57 856.49 2194.25 846.65 2176.61 829.16 M 2223.28 864.52 C 2208.7 853.01 2194.49 836.01 2187.92 829.16 M 2223.28 864.52 C 2216.2 857.1 2206.77 847.35 2187.92 829.16 M 2234.59 864.52 C 2221.78 852.43 2209.07 836.86 2199.24 829.16 M 2234.59 864.52 C 2221.46 851.16 2209.39 838.27 2199.24 829.16 M 2249.44 868.05 C 2238.9 858.16 2229.53 848.82 2210.55 829.16 M 2249.44 868.05 C 2240.17 858.9 2231.9 850.35 2210.55 829.16 M 2254.39 861.69 C 2245.63 852.52 2234.12 840.71 2221.87 829.16 M 2254.39 861.69 C 2248.07 855.31 2241.45 847.91 2221.87 829.16 M 2254.39 850.37 C 2248.33 843.79 2239.19 834.25 2233.18 829.16 M 2254.39 850.37 C 2247.71 842.92 2241.79 836.83 2233.18 829.16 M 2250.86 835.52 C 2248.99 833.35 2246.76 831.5 2244.49 829.16 M 2250.86 835.52 C 2248.21 832.69 2245.9 830.29 2244.49 829.16" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 2096 830 M 2096 830 C 2144.7 830.71 2188.41 829.41 2244 830 M 2096 830 C 2138.23 829.59 2180.52 829.54 2244 830 M 2244 830 C 2249.31 830.47 2251.48 833.37 2250 836 M 2244 830 C 2246.2 829.71 2250.58 830.06 2250 836 M 2250 836 C 2251.19 844.05 2249.31 850.39 2250 864 M 2250 836 C 2249.32 844.54 2249.35 853.71 2250 864 M 2250 864 C 2251.62 867.02 2247.52 869.04 2244 870 M 2250 864 C 2252.16 869.54 2246.5 871.74 2244 870 M 2244 870 C 2206.52 868.06 2168.72 869.62 2096 870 M 2244 870 C 2202.29 870.11 2162.7 868.81 2096 870 M 2096 870 C 2093.09 868 2088.8 866.6 2090 864 M 2096 870 C 2094.06 872.28 2091.73 870.1 2090 864 M 2090 864 C 2091.47 852.53 2088.72 840.25 2090 836 M 2090 864 C 2090.6 857.17 2090.18 851 2090 836 M 2090 836 C 2091.92 833.52 2093.65 830.3 2096 830 M 2090 836 C 2090.63 833.32 2093.53 828.86 2096 830" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="2090" y="700" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 2091.69 738.69 C 2091.69 738.69 2091.69 738.69 2091.69 738.69 M 2091.69 738.69 C 2091.69 738.69 2091.69 738.69 2091.69 738.69 M 2098.76 734.45 C 2096.66 732.75 2095.73 731.46 2093.81 729.5 M 2098.76 734.45 C 2097 732.69 2095.29 730.75 2093.81 729.5 M 2110.08 734.45 C 2105.82 731.26 2100.56 724.34 2093.81 718.18 M 2110.08 734.45 C 2105.84 730.84 2103.44 728.39 2093.81 718.18 M 2121.39 734.45 C 2115.33 728 2109.13 723.61 2091.69 704.75 M 2121.39 734.45 C 2112.63 724.23 2102.51 715.71 2091.69 704.75 M 2132.7 734.45 C 2122.5 724.37 2110.42 713.49 2097.35 699.09 M 2132.7 734.45 C 2119.19 719.29 2105.95 706.73 2097.35 699.09 M 2144.02 734.45 C 2134.73 727.57 2125.68 719.62 2108.66 699.09 M 2144.02 734.45 C 2131.15 721.25 2119.68 708.99 2108.66 699.09 M 2155.33 734.45 C 2140.62 720.76 2126.8 705.78 2119.98 699.09 M 2155.33 734.45 C 2147.61 726.91 2139.76 717.92 2119.98 699.09 M 2166.64 734.45 C 2154.57 724.58 2143.32 709.85 2131.29 699.09 M 2166.64 734.45 C 2157.72 725.55 2149.77 716.47 2131.29 699.09 M 2177.96 734.45 C 2164.95 722.88 2153.5 712.4 2142.6 699.09 M 2177.96 734.45 C 2164.3 721.2 2151.58 706.63 2142.6 699.09 M 2189.27 734.45 C 2175.81 723.22 2165.13 708.3 2153.92 699.09 M 2189.27 734.45 C 2177.3 722.89 2165.75 710.58 2153.92 699.09 M 2200.59 734.45 C 2193.29 726.5 2184.44 718.89 2165.23 699.09 M 2200.59 734.45 C 2190.01 723.31 2179.27 712.79 2165.23 699.09 M 2211.9 734.45 C 2199.96 723.16 2185.89 707.58 2176.54 699.09 M 2211.9 734.45 C 2203.3 726.01 2194.88 718.51 2176.54 699.09 M 2223.21 734.45 C 2215.37 727.56 2206.88 720.43 2187.86 699.09 M 2223.21 734.45 C 2211.82 724.11 2201 714.02 2187.86 699.09 M 2234.53 734.45 C 2225.88 727.31 2218.66 716.51 2199.17 699.09 M 2234.53 734.45 C 2227.29 727.29 2221.09 719.73 2199.17 699.09 M 2249.38 737.98 C 2237.24 728.97 2228.04 718.78 2210.48 699.09 M 2249.38 737.98 C 2238.03 726.89 2226.58 714.75 2210.48 699.09 M 2254.33 731.62 C 2245.86 723.13 2241.46 715.96 2221.8 699.09 M 2254.33 731.62 C 2244.34 721.88 2233.62 712.16 2221.8 699.09 M 2254.33 720.31 C 2247.66 712.65 2239.3 708.18 2233.11 699.09 M 2254.33 720.31 C 2248.09 713.8 2241.51 706.85 2233.11 699.09 M 2250.79 705.46 C 2248.74 703.12 2246.78 701.44 2244.43 699.09 M 2250.79 705.46 C 2248.91 703.37 2247.3 702.07 2244.43 699.09" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 2096 700 M 2096 700 C 2148.58 698.6 2200.34 699.9 2244 700 M 2096 700 C 2134.23 700.24 2170.9 700.89 2244 700 M 2244 700 C 2247.53 698.2 2249.08 700.14 2250 706 M 2244 700 C 2246.47 698.46 2251.63 700.77 2250 706 M 2250 706 C 2248.01 717.48 2248.15 727.98 2250 734 M 2250 706 C 2249.89 717.48 2248.75 727.18 2250 734 M 2250 734 C 2249 738.38 2248.71 738.75 2244 740 M 2250 734 C 2252.13 738.17 2249.88 740.68 2244 740 M 2244 740 C 2207.86 740 2169.83 738.83 2096 740 M 2244 740 C 2194.43 740.07 2145.58 741.25 2096 740 M 2096 740 C 2091.05 740.64 2088.83 737.39 2090 734 M 2096 740 C 2092.36 741.22 2089.03 738.17 2090 734 M 2090 734 C 2090.04 725.56 2091.43 717.03 2090 706 M 2090 734 C 2090.04 728.17 2090.95 721.97 2090 706 M 2090 706 C 2088.13 702.22 2092.04 698.61 2096 700 M 2090 706 C 2091.01 701.01 2093.35 700.47 2096 700" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <rect x="1960" y="680" width="200" height="280" fill="#ffffff" stroke="#000000" pointer-events="all"/> - <rect x="1962" y="682" width="196" height="276" fill="#ffffff" stroke="#000000" pointer-events="all"/> + <path d="M 2091.7 738.7 C 2091.7 738.7 2091.7 738.7 2091.7 738.7 M 2091.7 738.7 C 2091.7 738.7 2091.7 738.7 2091.7 738.7 M 2098.77 734.46 C 2096.67 732.76 2095.74 731.47 2093.83 729.51 M 2098.77 734.46 C 2097.01 732.7 2095.3 730.77 2093.83 729.51 M 2110.09 734.46 C 2105.83 731.27 2100.57 724.35 2093.83 718.2 M 2110.09 734.46 C 2105.86 730.85 2103.46 728.4 2093.83 718.2 M 2121.4 734.46 C 2115.34 728.01 2109.14 723.62 2091.7 704.76 M 2121.4 734.46 C 2112.64 724.25 2102.52 715.72 2091.7 704.76 M 2132.72 734.46 C 2122.51 724.38 2110.43 713.5 2097.36 699.11 M 2132.72 734.46 C 2119.2 719.3 2105.97 706.74 2097.36 699.11 M 2144.03 734.46 C 2134.74 727.58 2125.69 719.63 2108.67 699.11 M 2144.03 734.46 C 2131.17 721.26 2119.69 709 2108.67 699.11 M 2155.34 734.46 C 2140.63 720.77 2126.81 705.8 2119.99 699.11 M 2155.34 734.46 C 2147.62 726.92 2139.78 717.93 2119.99 699.11 M 2166.66 734.46 C 2154.58 724.6 2143.33 709.87 2131.3 699.11 M 2166.66 734.46 C 2157.73 725.56 2149.78 716.48 2131.3 699.11 M 2177.97 734.46 C 2164.96 722.9 2153.51 712.41 2142.62 699.11 M 2177.97 734.46 C 2164.31 721.21 2151.59 706.65 2142.62 699.11 M 2189.28 734.46 C 2175.82 723.23 2165.14 708.32 2153.93 699.11 M 2189.28 734.46 C 2177.31 722.91 2165.77 710.59 2153.93 699.11 M 2200.6 734.46 C 2193.31 726.52 2184.46 718.91 2165.24 699.11 M 2200.6 734.46 C 2190.03 723.32 2179.28 712.81 2165.24 699.11 M 2211.91 734.46 C 2199.97 723.17 2185.9 707.59 2176.56 699.11 M 2211.91 734.46 C 2203.31 726.02 2194.89 718.53 2176.56 699.11 M 2223.23 734.46 C 2215.38 727.57 2206.9 720.45 2187.87 699.11 M 2223.23 734.46 C 2211.83 724.12 2201.01 714.03 2187.87 699.11 M 2234.54 734.46 C 2225.89 727.32 2218.67 716.52 2199.18 699.11 M 2234.54 734.46 C 2227.3 727.3 2221.11 719.74 2199.18 699.11 M 2249.39 738 C 2237.26 728.98 2228.05 718.79 2210.5 699.11 M 2249.39 738 C 2238.04 726.91 2226.59 714.76 2210.5 699.11 M 2254.34 731.63 C 2245.87 723.14 2241.47 715.97 2221.81 699.11 M 2254.34 731.63 C 2244.36 721.89 2233.63 712.17 2221.81 699.11 M 2254.34 720.32 C 2247.68 712.66 2239.32 708.19 2233.13 699.11 M 2254.34 720.32 C 2248.11 713.81 2241.52 706.86 2233.13 699.11 M 2250.8 705.47 C 2248.75 703.14 2246.8 701.45 2244.44 699.11 M 2250.8 705.47 C 2248.92 703.38 2247.31 702.08 2244.44 699.11" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 2096 700 M 2096 700 C 2148.58 698.6 2200.34 699.9 2244 700 M 2096 700 C 2134.23 700.24 2170.9 700.89 2244 700 M 2244 700 C 2247.53 698.2 2249.08 700.14 2250 706 M 2244 700 C 2246.47 698.46 2251.63 700.77 2250 706 M 2250 706 C 2248.01 717.48 2248.15 727.98 2250 734 M 2250 706 C 2249.89 717.48 2248.75 727.18 2250 734 M 2250 734 C 2249 738.38 2248.71 738.75 2244 740 M 2250 734 C 2252.13 738.17 2249.88 740.68 2244 740 M 2244 740 C 2207.86 740 2169.83 738.83 2096 740 M 2244 740 C 2194.43 740.07 2145.58 741.25 2096 740 M 2096 740 C 2091.05 740.64 2088.83 737.39 2090 734 M 2096 740 C 2092.36 741.22 2089.03 738.17 2090 734 M 2090 734 C 2090.04 725.56 2091.43 717.03 2090 706 M 2090 734 C 2090.04 728.17 2090.95 721.97 2090 706 M 2090 706 C 2088.13 702.22 2092.04 698.61 2096 700 M 2090 706 C 2091.01 701.01 2093.35 700.47 2096 700" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <rect x="1960" y="680" width="200" height="280" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> + <rect x="1962" y="682" width="196" height="276" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/> <rect x="1960" y="650" width="120" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 660px; margin-left: 2020px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Notebook List View </div> </div> </div> </foreignObject> - <text x="2020" y="664" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="2020" y="664" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Notebook List View </text> </switch> </g> <rect x="1980" y="880" width="160" height="40" rx="6" ry="6" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1981.34 918.34 C 1981.34 918.34 1981.34 918.34 1981.34 918.34 M 1981.34 918.34 C 1981.34 918.34 1981.34 918.34 1981.34 918.34 M 1988.41 914.1 C 1987.32 912.53 1985.34 911.23 1984.17 909.85 M 1988.41 914.1 C 1986.71 912.64 1985.67 911.18 1984.17 909.85 M 1999.72 914.1 C 1995.63 909.12 1988.85 901.2 1984.17 898.54 M 1999.72 914.1 C 1994.75 907.29 1988.23 901.46 1984.17 898.54 M 2011.04 914.1 C 2000.13 901.82 1989.42 891.58 1981.34 884.4 M 2011.04 914.1 C 2000.45 902.77 1991.24 893.35 1981.34 884.4 M 2022.35 914.1 C 2012.6 903.18 1998.98 893.63 1987 878.74 M 2022.35 914.1 C 2010.13 901.36 1995.21 887.38 1987 878.74 M 2034.37 914.8 C 2022.95 905.71 2013.01 894.09 1998.31 878.74 M 2034.37 914.8 C 2024.73 903.77 2013.66 894.11 1998.31 878.74 M 2045.69 914.8 C 2031.69 903.62 2021.98 889.57 2009.62 878.74 M 2045.69 914.8 C 2038.22 908.03 2031.97 900.31 2009.62 878.74 M 2057 914.8 C 2047.29 904.81 2034.53 892.33 2020.94 878.74 M 2057 914.8 C 2047.21 904.32 2036.85 893.71 2020.94 878.74 M 2068.31 914.8 C 2059.95 907.28 2051.62 899.02 2032.25 878.74 M 2068.31 914.8 C 2059.75 906.2 2052.18 897.32 2032.25 878.74 M 2079.63 914.8 C 2069.74 904.31 2056.99 894.32 2043.56 878.74 M 2079.63 914.8 C 2068.18 902.92 2056.44 890.26 2043.56 878.74 M 2090.94 914.8 C 2079.92 903.42 2069.14 892.4 2054.88 878.74 M 2090.94 914.8 C 2077.22 900.4 2062.48 886.39 2054.88 878.74 M 2102.25 914.8 C 2089.56 902.6 2079.68 890.95 2066.19 878.74 M 2102.25 914.8 C 2091.51 904.84 2083.45 896.44 2066.19 878.74 M 2113.57 914.8 C 2102 906.16 2092.52 893.83 2078.21 879.45 M 2113.57 914.8 C 2106 906.28 2097.28 899.49 2078.21 879.45 M 2124.88 914.8 C 2110.11 900.29 2097.49 886.81 2089.53 879.45 M 2124.88 914.8 C 2117.82 907.04 2110.96 899.97 2089.53 879.45 M 2139.02 917.63 C 2131.32 907.28 2121.55 900.19 2100.84 879.45 M 2139.02 917.63 C 2124.58 903.9 2109.41 888.3 2100.84 879.45 M 2144.68 911.98 C 2131.98 901.75 2124.19 891.87 2112.15 879.45 M 2144.68 911.98 C 2132.87 900.27 2122.29 889.45 2112.15 879.45 M 2144.68 900.66 C 2138.48 896.33 2135.05 891.67 2123.47 879.45 M 2144.68 900.66 C 2136.96 894.52 2129.59 886.07 2123.47 879.45 M 2140.44 885.11 C 2138.43 882.9 2136.46 880.51 2134.78 879.45 M 2140.44 885.11 C 2138.7 882.71 2136.41 881.15 2134.78 879.45" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1986 880 M 1986 880 C 2041.23 881.62 2095.85 881.13 2134 880 M 1986 880 C 2030.61 879.47 2074.74 880.87 2134 880 M 2134 880 C 2138.78 879.54 2141.39 882.69 2140 886 M 2134 880 C 2138.49 880.83 2139.08 883.95 2140 886 M 2140 886 C 2139.36 893.48 2139.99 901.46 2140 914 M 2140 886 C 2140.74 894.76 2139.71 902.04 2140 914 M 2140 914 C 2140.03 918.96 2139.21 919.81 2134 920 M 2140 914 C 2141.39 917.63 2138.22 918.26 2134 920 M 2134 920 C 2082.06 921.77 2030.48 919.17 1986 920 M 2134 920 C 2101.03 920.24 2069.11 921.15 1986 920 M 1986 920 C 1980 919.8 1979.65 916.21 1980 914 M 1986 920 C 1983.12 918.73 1978.64 917.74 1980 914 M 1980 914 C 1978.23 908.54 1979.11 900.55 1980 886 M 1980 914 C 1978.9 904.43 1979.93 894.18 1980 886 M 1980 886 C 1979.26 882.84 1983.26 881.87 1986 880 M 1980 886 C 1980.97 880.79 1983.65 877.8 1986 880" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1981.35 918.35 C 1981.35 918.35 1981.35 918.35 1981.35 918.35 M 1981.35 918.35 C 1981.35 918.35 1981.35 918.35 1981.35 918.35 M 1988.42 914.11 C 1987.34 912.54 1985.35 911.24 1984.18 909.87 M 1988.42 914.11 C 1986.72 912.66 1985.68 911.2 1984.18 909.87 M 1999.74 914.11 C 1995.64 909.13 1988.86 901.22 1984.18 898.55 M 1999.74 914.11 C 1994.76 907.3 1988.24 901.47 1984.18 898.55 M 2011.05 914.11 C 2000.14 901.83 1989.44 891.59 1981.35 884.41 M 2011.05 914.11 C 2000.46 902.79 1991.26 893.36 1981.35 884.41 M 2022.36 914.11 C 2012.61 903.19 1998.99 893.64 1987.01 878.75 M 2022.36 914.11 C 2010.14 901.37 1995.22 887.39 1987.01 878.75 M 2033.68 914.11 C 2022.47 905.23 2012.74 893.81 1998.32 878.75 M 2033.68 914.11 C 2024.24 903.28 2013.37 893.83 1998.32 878.75 M 2045.7 914.82 C 2031.7 903.64 2022 889.59 2009.64 878.75 M 2045.7 914.82 C 2038.23 908.05 2031.98 900.32 2009.64 878.75 M 2057.01 914.82 C 2047.3 904.83 2034.55 892.34 2020.95 878.75 M 2057.01 914.82 C 2047.22 904.33 2036.87 893.73 2020.95 878.75 M 2068.33 914.82 C 2059.96 907.29 2051.63 899.04 2032.26 878.75 M 2068.33 914.82 C 2059.77 906.22 2052.19 897.33 2032.26 878.75 M 2079.64 914.82 C 2069.75 904.32 2057 894.33 2043.58 878.75 M 2079.64 914.82 C 2068.19 902.93 2056.46 890.27 2043.58 878.75 M 2090.95 914.82 C 2079.93 903.43 2069.16 892.41 2054.89 878.75 M 2090.95 914.82 C 2077.24 900.41 2062.49 886.4 2054.89 878.75 M 2102.27 914.82 C 2089.57 902.61 2079.69 890.97 2066.2 878.75 M 2102.27 914.82 C 2091.53 904.86 2083.46 896.45 2066.2 878.75 M 2113.58 914.82 C 2101.81 905.99 2092.14 893.46 2077.52 878.75 M 2113.58 914.82 C 2105.86 906.13 2096.98 899.19 2077.52 878.75 M 2124.89 914.82 C 2110.12 900.3 2097.5 886.83 2089.54 879.46 M 2124.89 914.82 C 2117.83 907.05 2110.97 899.98 2089.54 879.46 M 2139.04 917.64 C 2131.33 907.3 2121.57 900.2 2100.85 879.46 M 2139.04 917.64 C 2124.6 903.91 2109.42 888.31 2100.85 879.46 M 2144.69 911.99 C 2131.99 901.76 2124.21 891.88 2112.17 879.46 M 2144.69 911.99 C 2132.88 900.29 2122.3 889.46 2112.17 879.46 M 2144.69 900.67 C 2138.49 896.35 2135.06 891.69 2123.48 879.46 M 2144.69 900.67 C 2136.98 894.53 2129.6 886.09 2123.48 879.46 M 2140.45 885.12 C 2138.44 882.91 2136.47 880.52 2134.79 879.46 M 2140.45 885.12 C 2138.71 882.72 2136.43 881.17 2134.79 879.46" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1986 880 M 1986 880 C 2041.23 881.62 2095.85 881.13 2134 880 M 1986 880 C 2030.61 879.47 2074.74 880.87 2134 880 M 2134 880 C 2138.78 879.54 2141.39 882.69 2140 886 M 2134 880 C 2138.49 880.83 2139.08 883.95 2140 886 M 2140 886 C 2139.36 893.48 2139.99 901.46 2140 914 M 2140 886 C 2140.74 894.76 2139.71 902.04 2140 914 M 2140 914 C 2140.03 918.96 2139.21 919.81 2134 920 M 2140 914 C 2141.39 917.63 2138.22 918.26 2134 920 M 2134 920 C 2082.06 921.77 2030.48 919.17 1986 920 M 2134 920 C 2101.03 920.24 2069.11 921.15 1986 920 M 1986 920 C 1980 919.8 1979.65 916.21 1980 914 M 1986 920 C 1983.12 918.73 1978.64 917.74 1980 914 M 1980 914 C 1978.23 908.54 1979.11 900.55 1980 886 M 1980 914 C 1978.9 904.43 1979.93 894.18 1980 886 M 1980 886 C 1979.26 882.84 1983.26 881.87 1986 880 M 1980 886 C 1980.97 880.79 1983.65 877.8 1986 880" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1980" y="760" width="160" height="60" rx="9" ry="9" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1982.59 818.09 C 1982.59 818.09 1982.59 818.09 1982.59 818.09 M 1982.59 818.09 C 1982.59 818.09 1982.59 818.09 1982.59 818.09 M 1990.37 814.56 C 1988.18 812.74 1986.05 809.66 1983.3 807.49 M 1990.37 814.56 C 1988.3 812.23 1985.21 809.86 1983.3 807.49 M 2001.68 814.56 C 1996.61 806.37 1987.45 803.59 1983.3 796.17 M 2001.68 814.56 C 1997.56 809.76 1993.9 806.66 1983.3 796.17 M 2013 814.56 C 2002.57 804.06 1994.15 793.39 1983.3 784.86 M 2013 814.56 C 2004.21 804.64 1994.61 796.49 1983.3 784.86 M 2024.31 814.56 C 2006.93 800.59 1993.2 783.88 1983.3 773.54 M 2024.31 814.56 C 2013 803.18 2002.16 792.13 1983.3 773.54 M 2035.62 814.56 C 2016.25 794.23 1993.77 775.61 1982.59 761.52 M 2035.62 814.56 C 2022.41 800.66 2009.35 788.36 1982.59 761.52 M 2046.94 814.56 C 2032.95 800.49 2020.68 789.07 1990.37 757.99 M 2046.94 814.56 C 2024.56 792.64 2004.21 769.38 1990.37 757.99 M 2058.25 814.56 C 2043.33 799.33 2026.93 780.36 2002.39 758.69 M 2058.25 814.56 C 2043.92 800.4 2029.24 784.83 2002.39 758.69 M 2069.57 814.56 C 2053.43 796.8 2038.44 783.67 2013.7 758.69 M 2069.57 814.56 C 2050.23 795.92 2031.71 776.12 2013.7 758.69 M 2080.88 814.56 C 2066.51 803.58 2055.96 790.42 2025.02 758.69 M 2080.88 814.56 C 2061.5 794.49 2040.89 775.2 2025.02 758.69 M 2092.19 814.56 C 2076.92 799.06 2059.98 780.15 2036.33 758.69 M 2092.19 814.56 C 2081.15 801.95 2069.42 792.14 2036.33 758.69 M 2103.51 814.56 C 2090.44 801.05 2075.91 783.26 2047.65 758.69 M 2103.51 814.56 C 2088.09 799.04 2073.81 785.87 2047.65 758.69 M 2114.82 814.56 C 2097.33 797.11 2080.06 781.15 2058.96 758.69 M 2114.82 814.56 C 2098.78 799.18 2080.62 782.01 2058.96 758.69 M 2131.08 819.51 C 2113.48 803.81 2099.39 788.15 2070.27 758.69 M 2131.08 819.51 C 2116.84 804.52 2102.67 789.61 2070.27 758.69 M 2138.86 815.97 C 2124.83 801.71 2110.44 788.97 2081.59 758.69 M 2138.86 815.97 C 2125.39 801.44 2110.05 789.27 2081.59 758.69 M 2144.52 810.31 C 2131.73 800.36 2118.49 786.55 2092.9 758.69 M 2144.52 810.31 C 2130.58 796.08 2117.43 782.48 2092.9 758.69 M 2144.52 799 C 2130.42 781.98 2116.34 766.96 2104.21 758.69 M 2144.52 799 C 2131.33 786.43 2119.4 775.24 2104.21 758.69 M 2144.52 787.69 C 2134.03 776.84 2124.68 766.21 2115.53 758.69 M 2144.52 787.69 C 2136.45 779.64 2130.57 772.47 2115.53 758.69 M 2144.52 776.37 C 2139.79 770.92 2138.78 769.39 2126.84 758.69 M 2144.52 776.37 C 2139 772.06 2135.43 767.45 2126.84 758.69" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> - <path d="M 1989 760 M 1989 760 C 2025.96 761.38 2059.64 760.83 2131 760 M 1989 760 C 2019.08 760.72 2050.5 760.04 2131 760 M 2131 760 C 2135.14 760.89 2139.71 762.36 2140 769 M 2131 760 C 2135.49 760.11 2138.05 763.48 2140 769 M 2140 769 C 2139.17 785.74 2138.14 799.23 2140 811 M 2140 769 C 2139.56 785.36 2141.05 801.1 2140 811 M 2140 811 C 2140.37 816.41 2137.37 818.74 2131 820 M 2140 811 C 2138.11 817.37 2137.02 818.98 2131 820 M 2131 820 C 2087.67 819.28 2048.33 820.24 1989 820 M 2131 820 C 2101.68 819.34 2073.3 819.86 1989 820 M 1989 820 C 1982.85 821.19 1980.41 816.56 1980 811 M 1989 820 C 1983.9 818.81 1981.76 815.34 1980 811 M 1980 811 C 1980.28 800.67 1981.04 789.27 1980 769 M 1980 811 C 1980.74 798.98 1979.12 788.42 1980 769 M 1980 769 C 1980.27 761.69 1982.2 759.96 1989 760 M 1980 769 C 1979.76 760.72 1982.95 760.91 1989 760" fill="none" stroke="#000000" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1981.9 817.4 C 1981.9 817.4 1981.9 817.4 1981.9 817.4 M 1981.9 817.4 C 1981.9 817.4 1981.9 817.4 1981.9 817.4 M 1990.38 814.57 C 1988.19 812.75 1986.06 809.68 1983.31 807.5 M 1990.38 814.57 C 1988.32 812.25 1985.22 809.87 1983.31 807.5 M 2001.7 814.57 C 1996.63 806.39 1987.47 803.61 1983.31 796.18 M 2001.7 814.57 C 1997.57 809.78 1993.92 806.67 1983.31 796.18 M 2013.01 814.57 C 2002.58 804.07 1994.16 793.41 1983.31 784.87 M 2013.01 814.57 C 2004.22 804.65 1994.63 796.51 1983.31 784.87 M 2024.32 814.57 C 2006.94 800.61 1993.21 783.89 1983.31 773.56 M 2024.32 814.57 C 2013.02 803.19 2002.17 792.14 1983.31 773.56 M 2035.64 814.57 C 2016.26 794.25 1993.78 775.63 1982.6 761.54 M 2035.64 814.57 C 2022.42 800.67 2009.36 788.37 1982.6 761.54 M 2046.95 814.57 C 2032.96 800.5 2020.69 789.08 1990.38 758 M 2046.95 814.57 C 2024.57 792.65 2004.22 769.39 1990.38 758 M 2058.27 814.57 C 2043.14 799.13 2026.54 779.95 2001.7 758 M 2058.27 814.57 C 2043.75 800.22 2028.88 784.48 2001.7 758 M 2069.58 814.57 C 2053.45 796.81 2038.45 783.68 2013.72 758.71 M 2069.58 814.57 C 2050.25 795.94 2031.73 776.13 2013.72 758.71 M 2080.89 814.57 C 2066.53 803.59 2055.98 790.43 2025.03 758.71 M 2080.89 814.57 C 2061.51 794.5 2040.91 775.22 2025.03 758.71 M 2092.21 814.57 C 2076.93 799.07 2060 780.17 2036.34 758.71 M 2092.21 814.57 C 2081.16 801.96 2069.43 792.15 2036.34 758.71 M 2103.52 814.57 C 2090.45 801.06 2075.93 783.27 2047.66 758.71 M 2103.52 814.57 C 2088.1 799.05 2073.83 785.88 2047.66 758.71 M 2114.83 814.57 C 2097.34 797.13 2080.08 781.17 2058.97 758.71 M 2114.83 814.57 C 2098.8 799.2 2080.63 782.02 2058.97 758.71 M 2131.1 819.52 C 2113.49 803.82 2099.41 788.16 2070.29 758.71 M 2131.1 819.52 C 2116.85 804.53 2102.68 789.62 2070.29 758.71 M 2138.88 815.98 C 2124.84 801.72 2110.45 788.98 2081.6 758.71 M 2138.88 815.98 C 2125.4 801.45 2110.06 789.28 2081.6 758.71 M 2144.53 810.33 C 2131.74 800.37 2118.5 786.56 2092.91 758.71 M 2144.53 810.33 C 2130.59 796.09 2117.45 782.49 2092.91 758.71 M 2144.53 799.01 C 2130.44 782 2116.35 766.97 2104.23 758.71 M 2144.53 799.01 C 2131.34 786.44 2119.41 775.25 2104.23 758.71 M 2144.53 787.7 C 2134.05 776.85 2124.69 766.22 2115.54 758.71 M 2144.53 787.7 C 2136.46 779.65 2130.58 772.48 2115.54 758.71 M 2144.53 776.39 C 2139.81 770.93 2138.8 769.4 2126.85 758.71 M 2144.53 776.39 C 2139.01 772.07 2135.44 767.46 2126.85 758.71" fill="none" stroke="#1ba1e2" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1989 760 M 1989 760 C 2025.96 761.38 2059.64 760.83 2131 760 M 1989 760 C 2019.08 760.72 2050.5 760.04 2131 760 M 2131 760 C 2135.14 760.89 2139.71 762.36 2140 769 M 2131 760 C 2135.49 760.11 2138.05 763.48 2140 769 M 2140 769 C 2139.17 785.74 2138.14 799.23 2140 811 M 2140 769 C 2139.56 785.36 2141.05 801.1 2140 811 M 2140 811 C 2140.37 816.41 2137.37 818.74 2131 820 M 2140 811 C 2138.11 817.37 2137.02 818.98 2131 820 M 2131 820 C 2087.67 819.28 2048.33 820.24 1989 820 M 2131 820 C 2101.68 819.34 2073.3 819.86 1989 820 M 1989 820 C 1982.85 821.19 1980.41 816.56 1980 811 M 1989 820 C 1983.9 818.81 1981.76 815.34 1980 811 M 1980 811 C 1980.28 800.67 1981.04 789.27 1980 769 M 1980 811 C 1980.74 798.98 1979.12 788.42 1980 769 M 1980 769 C 1980.27 761.69 1982.2 759.96 1989 760 M 1980 769 C 1979.76 760.72 1982.95 760.91 1989 760" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1980" cy="780" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1960" y="760" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1977.46 783.63 C 1977.46 783.63 1977.46 783.63 1977.46 783.63 M 1977.46 783.63 C 1977.46 783.63 1977.46 783.63 1977.46 783.63 M 1985.23 780.09 C 1984.25 778.3 1982.1 776.99 1981.7 776.56 M 1985.23 780.09 C 1984.2 779.1 1982.82 777.58 1981.7 776.56" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1977.47 783.64 C 1977.47 783.64 1977.47 783.64 1977.47 783.64 M 1977.47 783.64 C 1977.47 783.64 1977.47 783.64 1977.47 783.64 M 1985.25 780.11 C 1984.26 778.31 1982.11 777.01 1981.71 776.57 M 1985.25 780.11 C 1984.21 779.12 1982.84 777.59 1981.71 776.57" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <ellipse cx="1970" cy="780" rx="4" ry="4" fill="none" stroke="none" pointer-events="all"/> <rect x="1950" y="760" width="40" height="40" fill="none" stroke="none" pointer-events="all"/> - <path d="M 1967.32 783.87 C 1967.32 783.87 1967.32 783.87 1967.32 783.87 M 1967.32 783.87 C 1967.32 783.87 1967.32 783.87 1967.32 783.87 M 1974.39 779.62 C 1973.5 778.42 1973.08 778.33 1970.15 775.38 M 1974.39 779.62 C 1973.03 777.8 1971.39 776.35 1970.15 775.38" fill="none" stroke="#000000" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1967.33 783.88 C 1967.33 783.88 1967.33 783.88 1967.33 783.88 M 1967.33 783.88 C 1967.33 783.88 1967.33 783.88 1967.33 783.88 M 1974.4 779.64 C 1973.51 778.43 1973.09 778.34 1970.16 775.39 M 1974.4 779.64 C 1973.04 777.81 1971.4 776.37 1970.16 775.39" fill="none" stroke="rgb(0, 0, 0)" stroke-width="4" stroke-linejoin="round" stroke-linecap="round" stroke-miterlimit="10" pointer-events="all"/> <rect x="1870" y="680" width="90" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 690px; margin-left: 1915px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> scrollTop 1050 </div> </div> </div> </foreignObject> - <text x="1915" y="694" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1915" y="694" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> scrollTop 1050 </text> </switch> @@ -503,35 +503,35 @@ <rect x="2085" y="580" width="110" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 590px; margin-left: 2140px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Webview top -950 </div> </div> </div> </foreignObject> - <text x="2140" y="594" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="2140" y="594" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Webview top -950 </text> </switch> </g> - <path d="M 1810 740 L 2233.64 720.3" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/> - <path d="M 2238.88 720.05 L 2232.05 723.87 L 2233.64 720.3 L 2231.73 716.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/> + <path d="M 1810 740 L 2233.64 720.3" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/> + <path d="M 2238.88 720.05 L 2232.05 723.87 L 2233.64 720.3 L 2231.73 716.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/> <rect x="1850" y="710" width="70" height="20" fill="none" stroke="none" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 720px; margin-left: 1885px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;"> Adjust top </div> </div> </div> </foreignObject> - <text x="1885" y="724" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1885" y="724" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> Adjust top </text> </switch> @@ -543,16 +543,16 @@ <ellipse cx="50" cy="40" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 40px; margin-left: 41px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 1 </div> </div> </div> </foreignObject> - <text x="50" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="50" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 1 </text> </switch> @@ -560,16 +560,16 @@ <ellipse cx="530" cy="40" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 40px; margin-left: 521px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 2 </div> </div> </div> </foreignObject> - <text x="530" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="530" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 2 </text> </switch> @@ -577,16 +577,16 @@ <ellipse cx="1060" cy="40" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 40px; margin-left: 1051px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 3 </div> </div> </div> </foreignObject> - <text x="1060" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1060" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 3 </text> </switch> @@ -594,16 +594,16 @@ <ellipse cx="1490" cy="40" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 40px; margin-left: 1481px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 4 </div> </div> </div> </foreignObject> - <text x="1490" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1490" y="44" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 4 </text> </switch> @@ -611,16 +611,16 @@ <ellipse cx="1500" cy="630" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 630px; margin-left: 1491px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 4' </div> </div> </div> </foreignObject> - <text x="1500" y="634" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1500" y="634" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 4' </text> </switch> @@ -628,16 +628,16 @@ <ellipse cx="1940" cy="630" rx="10" ry="10" fill="#d5e8d4" stroke="#82b366" pointer-events="all"/> <g transform="translate(-0.5 -0.5)"> <switch> - <foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"> + <foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"> <div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 630px; margin-left: 1931px;"> - <div style="box-sizing: border-box; font-size: 0; text-align: center; "> - <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "> + <div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"> + <div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"> 5 </div> </div> </div> </foreignObject> - <text x="1940" y="634" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"> + <text x="1940" y="634" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle"> 5 </text> </switch> diff --git a/src/vs/workbench/contrib/notebook/browser/docs/notebook.layout.md b/src/vs/workbench/contrib/notebook/browser/docs/notebook.layout.md index b289f68fd34..eb757a5a366 100644 --- a/src/vs/workbench/contrib/notebook/browser/docs/notebook.layout.md +++ b/src/vs/workbench/contrib/notebook/browser/docs/notebook.layout.md @@ -8,7 +8,6 @@ The notebook editor is a virtualized list view rendered in two contexts (mainfra - [Optimizations](#optimizations) - [Avoid flickering on resize of cells above current viewport](#avoid-flickering-on-resize-of-cells-above-current-viewport) - [Executing code cell followed by markdown cells](#executing-code-cell-followed-by-markdown-cells) - - [What's the catch](#whats-the-catch) - [Re-executing code cell followed by markdown cells](#re-executing-code-cell-followed-by-markdown-cells) - [Scrolling](#scrolling) @@ -172,6 +171,6 @@ If the new output is rendered within 200ms, users won't see the UI movement. ## Scrolling -Code cell outputs and markdown cells are rendered in the webview, which are async in nature. In order to have the cell outputs and markdown previews rendered when users scroll to them, we send rendering requests of cells in the next viewport when it's idle. Thus scrolling downwards is smoother. +Code cell outputs and markdown cells are rendered in the webview, which are async in nature. In order to have the cell outputs and markdown previews rendered when users scroll to them, we send rendering requests of cells in the next and previous viewport when it's idle. Thus scrolling is smoother. -However, we **don't** warmup the previous viewport as the cell height change of previous viewport might trigger the flickering of markdown cells in current viewport. Before we optimize this, do not do any warmup of cells before current viewport. +We also warm up all rendered markdown in the document, from top to bottom, when the browser is idle. We don't warm up outputs like this, since they can be more expensive to render than markdown. But outputs do get rendered when the user starts a search in outputs. diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 56012a1a041..75452af0bde 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -442,7 +442,7 @@ export interface INotebookEditor { */ getLayoutInfo(): NotebookLayoutInfo; - getVisibleRangesPlusViewportBelow(): ICellRange[]; + getVisibleRangesPlusViewportAboveAndBelow(): ICellRange[]; /** * Focus the container of a cell (the monaco editor inside is not focused). diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 535e00b2aa6..8567bdded40 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -2088,8 +2088,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD return this._listViewInfoAccessor.setHiddenAreas(_ranges); } - getVisibleRangesPlusViewportBelow(): ICellRange[] { - return this._listViewInfoAccessor.getVisibleRangesPlusViewportBelow(); + getVisibleRangesPlusViewportAboveAndBelow(): ICellRange[] { + return this._listViewInfoAccessor.getVisibleRangesPlusViewportAboveAndBelow(); } setScrollTop(scrollTop: number) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 859e007d6c9..0318aa6a288 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -600,15 +600,16 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID return reduceCellRanges(ranges); } - getVisibleRangesPlusViewportBelow() { + getVisibleRangesPlusViewportAboveAndBelow() { if (this.view.length <= 0) { return []; } - const bottom = clamp(this.getViewScrollBottom() + this.renderHeight, 0, this.scrollHeight); - const topViewIndex = this.firstVisibleIndex; + const top = Math.max(this.getViewScrollTop() - this.renderHeight, 0); + const topViewIndex = this.view.indexAt(top); const topElement = this.view.element(topViewIndex); const topModelIndex = this._viewModel!.getCellIndex(topElement); + const bottom = clamp(this.getViewScrollBottom() + this.renderHeight, 0, this.scrollHeight); const bottomViewIndex = clamp(this.view.indexAt(bottom), 0, this.view.length - 1); const bottomElement = this.view.element(bottomViewIndex); const bottomModelIndex = this._viewModel!.getCellIndex(bottomElement); @@ -1584,8 +1585,8 @@ export class ListViewInfoAccessor extends Disposable { return this.list.setHiddenAreas(_ranges, true); } - getVisibleRangesPlusViewportBelow(): ICellRange[] { - return this.list?.getVisibleRangesPlusViewportBelow() ?? []; + getVisibleRangesPlusViewportAboveAndBelow(): ICellRange[] { + return this.list?.getVisibleRangesPlusViewportAboveAndBelow() ?? []; } triggerScroll(event: IMouseWheelEvent) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon.ts index 0eb419e6d32..0bdb4ff330f 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon.ts @@ -53,7 +53,7 @@ export interface INotebookCellList { getViewIndex2(modelIndex: number): number | undefined; getModelIndex(cell: CellViewModel): number | undefined; getModelIndex2(viewIndex: number): number | undefined; - getVisibleRangesPlusViewportBelow(): ICellRange[]; + getVisibleRangesPlusViewportAboveAndBelow(): ICellRange[]; focusElement(element: ICellViewModel): void; selectElements(elements: ICellViewModel[]): void; getFocusedElements(): ICellViewModel[]; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index cc2eb8bf93a..af4606ffee6 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -884,15 +884,20 @@ var requirejs = (function() { ...workspaceFolders, ...this.getBuiltinLocalResourceRoots(), ]; - const webview = webviewService.createWebviewElement(this.id, { - purpose: WebviewContentPurpose.NotebookRenderer, - enableFindWidget: false, - transformCssVariables: transformWebviewThemeVars, - }, { - allowMultipleAPIAcquire: true, - allowScripts: true, - localResourceRoots: this.localResourceRootsCache, - }, undefined); + const webview = webviewService.createWebviewElement({ + id: this.id, + options: { + purpose: WebviewContentPurpose.NotebookRenderer, + enableFindWidget: false, + transformCssVariables: transformWebviewThemeVars, + }, + contentOptions: { + allowMultipleAPIAcquire: true, + allowScripts: true, + localResourceRoots: this.localResourceRootsCache, + }, + extension: undefined + }); webview.html = content; return webview; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index b2f6eac0cdc..b16ea3ac942 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -18,8 +18,9 @@ import { FOLDER_SCOPES, WORKSPACE_SCOPES, REMOTE_MACHINE_SCOPES, LOCAL_MACHINE_S import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Disposable } from 'vs/base/common/lifecycle'; import { Emitter } from 'vs/base/common/event'; -import { ConfigurationScope, EditPresentationTypes } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, EditPresentationTypes, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { ILanguageService } from 'vs/editor/common/languages/language'; +import { Registry } from 'vs/platform/registry/common/platform'; export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices'; @@ -231,6 +232,12 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { displayValue = (isConfigured ? overrideValues[targetSelector] : overrideValues.defaultValue) ?? displayValue; this.scopeValue = isConfigured && overrideValues[targetSelector]; this.defaultValue = overrideValues.defaultValue ?? inspected.defaultValue; + + const registryValues = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationDefaultsOverrides(); + const overrideValueSource = registryValues.get(`[${languageSelector}]`)?.valuesSources?.get(this.setting.key); + if (overrideValueSource) { + this.setting.defaultValueSource = overrideValueSource; + } } else { this.scopeValue = isConfigured && inspected[targetSelector]; this.defaultValue = inspected.defaultValue; diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index a2d8b9671ae..7da92791ee6 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -243,20 +243,20 @@ class InitialRemoteConnectionHealthContribution implements IWorkbenchContributio await timeout(EXT_HOST_LATENCY_DELAY); } - type RemoteConnectionFailureClassification = { + type RemoteConnectionLatencyClassification = { owner: 'connor4312'; comment: 'The latency to the remote extension host'; web: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Whether this is running on web' }; remoteName: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Anonymized remote name' }; latencyMs: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Latency to the remote, in milliseconds'; isMeasurement: true }; }; - type RemoteConnectionFailureEvent = { + type RemoteConnectionLatencyEvent = { web: boolean; remoteName: string | undefined; latencyMs: number; }; - this._telemetryService.publicLog2<RemoteConnectionFailureEvent, RemoteConnectionFailureClassification>('remoteConnectionFailure', { + this._telemetryService.publicLog2<RemoteConnectionLatencyEvent, RemoteConnectionLatencyClassification>('remoteConnectionLatency', { web: isWeb, remoteName: getRemoteName(this._environmentService.remoteAuthority), latencyMs: bestLatency diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 509db6cc5a6..6849cc1ff84 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -27,7 +27,7 @@ import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeServic import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; -import { TERMINAL_FOREGROUND_COLOR, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, ansiColorIdentifiers, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_FIND_MATCH_FOREGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_CURSOR_FOREGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { TERMINAL_FOREGROUND_COLOR, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, ansiColorIdentifiers, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BACKGROUND_COLOR, TERMINAL_FIND_MATCH_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_FIND_MATCH_FOREGROUND_COLOR, TERMINAL_FIND_MATCH_HIGHLIGHT_BORDER_COLOR, TERMINAL_OVERVIEW_RULER_CURSOR_FOREGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { Color } from 'vs/base/common/color'; import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -566,14 +566,16 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal { } const cursorColor = theme.getColor(TERMINAL_CURSOR_FOREGROUND_COLOR) || foregroundColor; const cursorAccentColor = theme.getColor(TERMINAL_CURSOR_BACKGROUND_COLOR) || backgroundColor; - const selectionColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR); + const selectionBackgroundColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR); + const selectionForegroundColor = theme.getColor(TERMINAL_SELECTION_FOREGROUND_COLOR) || undefined; return { - background: backgroundColor ? backgroundColor.toString() : undefined, - foreground: foregroundColor ? foregroundColor.toString() : undefined, - cursor: cursorColor ? cursorColor.toString() : undefined, - cursorAccent: cursorAccentColor ? cursorAccentColor.toString() : undefined, - selection: selectionColor ? selectionColor.toString() : undefined, + background: backgroundColor?.toString(), + foreground: foregroundColor?.toString(), + cursor: cursorColor?.toString(), + cursorAccent: cursorAccentColor?.toString(), + selection: selectionBackgroundColor?.toString(), + selectionForeground: selectionForegroundColor?.toString(), black: theme.getColor(ansiColorIdentifiers[0])?.toString(), red: theme.getColor(ansiColorIdentifiers[1])?.toString(), green: theme.getColor(ansiColorIdentifiers[2])?.toString(), diff --git a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts index bdfbe2ad4d0..44061cca143 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts @@ -29,6 +29,12 @@ export const TERMINAL_SELECTION_BACKGROUND_COLOR = registerColor('terminal.selec hcDark: editorSelectionBackground, hcLight: editorSelectionBackground }, nls.localize('terminal.selectionBackground', 'The selection background color of the terminal.')); +export const TERMINAL_SELECTION_FOREGROUND_COLOR = registerColor('terminal.selectionForeground', { + light: null, + dark: null, + hcDark: '#000000', + hcLight: '#ffffff' +}, nls.localize('terminal.selectionForeground', 'The selection foreground color of the terminal. When this is null the selection foreground will be retained and have the minimum contrast ratio feature applied.')); export const TERMINAL_COMMAND_DECORATION_DEFAULT_BACKGROUND_COLOR = registerColor('terminalCommandDecoration.defaultBackground', { light: '#00000040', dark: '#ffffff40', diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index c9bbe8dedaf..eaec5127e56 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -16,7 +16,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IViewDescriptor, IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { Emitter } from 'vs/base/common/event'; -import { TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR, TERMINAL_SELECTION_FOREGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { WebglAddon } from 'xterm-addon-webgl'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; @@ -146,6 +146,7 @@ suite('XtermTerminal', () => { [TERMINAL_CURSOR_FOREGROUND_COLOR]: '#000300', [TERMINAL_CURSOR_BACKGROUND_COLOR]: '#000400', [TERMINAL_SELECTION_BACKGROUND_COLOR]: '#000500', + [TERMINAL_SELECTION_FOREGROUND_COLOR]: undefined, 'terminal.ansiBlack': '#010000', 'terminal.ansiRed': '#020000', 'terminal.ansiGreen': '#030000', @@ -170,6 +171,7 @@ suite('XtermTerminal', () => { cursor: '#000300', cursorAccent: '#000400', selection: '#000500', + selectionForeground: undefined, black: '#010000', green: '#030000', red: '#020000', @@ -193,6 +195,7 @@ suite('XtermTerminal', () => { [TERMINAL_CURSOR_FOREGROUND_COLOR]: '#00030f', [TERMINAL_CURSOR_BACKGROUND_COLOR]: '#00040f', [TERMINAL_SELECTION_BACKGROUND_COLOR]: '#00050f', + [TERMINAL_SELECTION_FOREGROUND_COLOR]: '#00060f', 'terminal.ansiBlack': '#01000f', 'terminal.ansiRed': '#02000f', 'terminal.ansiGreen': '#03000f', @@ -216,6 +219,7 @@ suite('XtermTerminal', () => { cursor: '#00030f', cursorAccent: '#00040f', selection: '#00050f', + selectionForeground: '#00060f', black: '#01000f', green: '#03000f', red: '#02000f', diff --git a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index df20df258da..9517be6e2e0 100644 --- a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -79,18 +79,20 @@ export class ReleaseNotesManager { this._webviewWorkbenchService.revealWebview(this._currentReleaseNotes, activeEditorPane ? activeEditorPane.group : this._editorGroupService.activeGroup, false); } else { this._currentReleaseNotes = this._webviewWorkbenchService.createWebview( - generateUuid(), - 'releaseNotes', - title, - { group: ACTIVE_GROUP, preserveFocus: false }, - { - tryRestoreScrollPosition: true, - enableFindWidget: true, - }, { - localResourceRoots: [] + id: generateUuid(), + options: { + tryRestoreScrollPosition: true, + enableFindWidget: true, + }, + contentOptions: { + localResourceRoots: [] + }, + extension: undefined }, - undefined); + 'releaseNotes', + title, + { group: ACTIVE_GROUP, preserveFocus: false }); this._currentReleaseNotes.webview.onDidClickLink(uri => this.onDidClickLink(URI.parse(uri))); this._currentReleaseNotes.onWillDispose(() => { this._currentReleaseNotes = undefined; }); diff --git a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts index 057e5e10d4d..8c6cc98b2f4 100644 --- a/src/vs/workbench/contrib/webview/browser/overlayWebview.ts +++ b/src/vs/workbench/contrib/webview/browser/overlayWebview.ts @@ -8,10 +8,12 @@ import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { IWebviewService, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_ENABLED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, IWebview, WebviewContentOptions, IWebviewElement, WebviewExtensionDescription, WebviewMessageReceivedEvent, WebviewOptions, IOverlayWebview } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; /** * Webview that is absolutely positioned over another element and that can creates and destroys an underlying webview as needed. @@ -41,20 +43,23 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { private _findWidgetVisible: IContextKey<boolean> | undefined; private _findWidgetEnabled: IContextKey<boolean> | undefined; + public readonly id: string; + public readonly origin: string; + public constructor( - public readonly id: string, - initialOptions: WebviewOptions, - initialContentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, + initInfo: WebviewInitInfo, @ILayoutService private readonly _layoutService: ILayoutService, @IWebviewService private readonly _webviewService: IWebviewService, @IContextKeyService private readonly _baseContextKeyService: IContextKeyService ) { super(); - this._extension = extension; - this._options = initialOptions; - this._contentOptions = initialContentOptions; + this.id = initInfo.id; + this.origin = initInfo.origin ?? generateUuid(); + + this._extension = initInfo.extension; + this._options = initInfo.options; + this._contentOptions = initInfo.contentOptions; } public get isFocused() { @@ -99,8 +104,8 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { // Webviews cannot be reparented in the dom as it will destroy their contents. // Mount them to a high level node to avoid this. this._layoutService.container.appendChild(this._container); - } + return this._container; } @@ -185,7 +190,13 @@ export class OverlayWebview extends Disposable implements IOverlayWebview { } if (!this._webview.value) { - const webview = this._webviewService.createWebviewElement(this.id, this._options, this._contentOptions, this.extension); + const webview = this._webviewService.createWebviewElement({ + id: this.id, + origin: this.origin, + options: this._options, + contentOptions: this._contentOptions, + extension: this.extension, + }); this._webview.value = webview; webview.state = this._state; diff --git a/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html b/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html index 6885c2488cd..625c46f3115 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index-no-csp.html @@ -12,7 +12,1136 @@ </head> <body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document"> - <script async type="module" src="main.js"></script> + <script async type="module"> + // @ts-check + /// <reference lib="dom" /> + + const isSafari = ( + navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && + navigator.userAgent && + navigator.userAgent.indexOf('CriOS') === -1 && + navigator.userAgent.indexOf('FxiOS') === -1 + ); + + const isFirefox = ( + navigator.userAgent && + navigator.userAgent.indexOf('Firefox') >= 0 + ); + + const searchParams = new URL(location.toString()).searchParams; + const ID = searchParams.get('id'); + const webviewOrigin = searchParams.get('origin'); + const onElectron = searchParams.get('platform') === 'electron'; + const expectedWorkerVersion = parseInt(searchParams.get('swVersion')); + + /** + * Use polling to track focus of main webview and iframes within the webview + * + * @param {Object} handlers + * @param {() => void} handlers.onFocus + * @param {() => void} handlers.onBlur + */ + const trackFocus = ({ onFocus, onBlur }) => { + const interval = 250; + let isFocused = document.hasFocus(); + setInterval(() => { + const isCurrentlyFocused = document.hasFocus(); + if (isCurrentlyFocused === isFocused) { + return; + } + isFocused = isCurrentlyFocused; + if (isCurrentlyFocused) { + onFocus(); + } else { + onBlur(); + } + }, interval); + }; + + const getActiveFrame = () => { + return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('active-frame')); + }; + + const getPendingFrame = () => { + return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('pending-frame')); + }; + + /** + * @template T + * @param {T | undefined | null} obj + * @return {T} + */ + function assertIsDefined(obj) { + if (typeof obj === 'undefined' || obj === null) { + throw new Error('Found unexpected null'); + } + return obj; + } + + const vscodePostMessageFuncName = '__vscode_post_message__'; + + const defaultStyles = document.createElement('style'); + defaultStyles.id = '_defaultStyles'; + defaultStyles.textContent = ` + html { + scrollbar-color: var(--vscode-scrollbarSlider-background) var(--vscode-editor-background); + } + + body { + background-color: transparent; + color: var(--vscode-editor-foreground); + font-family: var(--vscode-font-family); + font-weight: var(--vscode-font-weight); + font-size: var(--vscode-font-size); + margin: 0; + padding: 0 20px; + } + + img { + max-width: 100%; + max-height: 100%; + } + + a, a code { + color: var(--vscode-textLink-foreground); + } + + a:hover { + color: var(--vscode-textLink-activeForeground); + } + + a:focus, + input:focus, + select:focus, + textarea:focus { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: -1px; + } + + code { + color: var(--vscode-textPreformat-foreground); + } + + blockquote { + background: var(--vscode-textBlockQuote-background); + border-color: var(--vscode-textBlockQuote-border); + } + + kbd { + color: var(--vscode-editor-foreground); + border-radius: 3px; + vertical-align: middle; + padding: 1px 3px; + + background-color: hsla(0,0%,50%,.17); + border: 1px solid rgba(71,71,71,.4); + border-bottom-color: rgba(88,88,88,.4); + box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); + } + .vscode-light kbd { + background-color: hsla(0,0%,87%,.5); + border: 1px solid hsla(0,0%,80%,.7); + border-bottom-color: hsla(0,0%,73%,.7); + box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); + } + + ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + ::-webkit-scrollbar-corner { + background-color: var(--vscode-editor-background); + } + + ::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background); + } + ::-webkit-scrollbar-thumb:hover { + background-color: var(--vscode-scrollbarSlider-hoverBackground); + } + ::-webkit-scrollbar-thumb:active { + background-color: var(--vscode-scrollbarSlider-activeBackground); + } + ::highlight(find-highlight) { + background-color: var(--vscode-editor-findMatchHighlightBackground); + } + ::highlight(current-find-highlight) { + background-color: var(--vscode-editor-findMatchBackground); + }`; + + /** + * @param {boolean} allowMultipleAPIAcquire + * @param {*} [state] + * @return {string} + */ + function getVsCodeApiScript(allowMultipleAPIAcquire, state) { + const encodedState = state ? encodeURIComponent(state) : undefined; + return /* js */` + globalThis.acquireVsCodeApi = (function() { + const originalPostMessage = window.parent['${vscodePostMessageFuncName}'].bind(window.parent); + const doPostMessage = (channel, data, transfer) => { + originalPostMessage(channel, data, transfer); + }; + + let acquired = false; + + let state = ${state ? `JSON.parse(decodeURIComponent("${encodedState}"))` : undefined}; + + return () => { + if (acquired && !${allowMultipleAPIAcquire}) { + throw new Error('An instance of the VS Code API has already been acquired'); + } + acquired = true; + return Object.freeze({ + postMessage: function(message, transfer) { + doPostMessage('onmessage', { message, transfer }, transfer); + }, + setState: function(newState) { + state = newState; + doPostMessage('do-update-state', JSON.stringify(newState)); + return newState; + }, + getState: function() { + return state; + } + }); + }; + })(); + delete window.parent; + delete window.top; + delete window.frameElement; + `; + } + + /** @type {Promise<void>} */ + const workerReady = new Promise((resolve, reject) => { + if (!areServiceWorkersEnabled()) { + return reject(new Error('Service Workers are not enabled. Webviews will not work. Try disabling private/incognito mode.')); + } + + const swPath = `service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`; + navigator.serviceWorker.register(swPath) + .then(() => navigator.serviceWorker.ready) + .then(async registration => { + /** + * @param {MessageEvent} event + */ + const versionHandler = async (event) => { + if (event.data.channel !== 'version') { + return; + } + + navigator.serviceWorker.removeEventListener('message', versionHandler); + if (event.data.version === expectedWorkerVersion) { + return resolve(); + } else { + console.log(`Found unexpected service worker version. Found: ${event.data.version}. Expected: ${expectedWorkerVersion}`); + console.log(`Attempting to reload service worker`); + + // If we have the wrong version, try once (and only once) to unregister and re-register + // Note that `.update` doesn't seem to work desktop electron at the moment so we use + // `unregister` and `register` here. + return registration.unregister() + .then(() => navigator.serviceWorker.register(swPath)) + .then(() => navigator.serviceWorker.ready) + .finally(() => { resolve(); }); + } + }; + navigator.serviceWorker.addEventListener('message', versionHandler); + + const postVersionMessage = (/** @type {ServiceWorker} */ controller) => { + controller.postMessage({ channel: 'version' }); + }; + + // At this point, either the service worker is ready and + // became our controller, or we need to wait for it. + // Note that navigator.serviceWorker.controller could be a + // controller from a previously loaded service worker. + const currentController = navigator.serviceWorker.controller; + if (currentController?.scriptURL.endsWith(swPath)) { + // service worker already loaded & ready to receive messages + postVersionMessage(currentController); + } else { + // either there's no controlling service worker, or it's an old one: + // wait for it to change before posting the message + const onControllerChange = () => { + navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange); + postVersionMessage(navigator.serviceWorker.controller); + }; + navigator.serviceWorker.addEventListener('controllerchange', onControllerChange); + } + }).catch(error => { + reject(new Error(`Could not register service workers: ${error}.`)); + }); + }); + + const hostMessaging = new class HostMessaging { + + constructor() { + this.channel = new MessageChannel(); + + /** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */ + this.handlers = new Map(); + + this.channel.port1.onmessage = (e) => { + const channel = e.data.channel; + const handlers = this.handlers.get(channel); + if (handlers) { + for (const handler of handlers) { + handler(e, e.data.args); + } + } else { + console.log('no handler for ', e); + } + }; + } + + /** + * @param {string} channel + * @param {any} data + * @param {any} [transfer] + */ + postMessage(channel, data, transfer) { + this.channel.port1.postMessage({ channel, data }, transfer); + } + + /** + * @param {string} channel + * @param {(event: MessageEvent, data: any) => void} handler + */ + onMessage(channel, handler) { + let handlers = this.handlers.get(channel); + if (!handlers) { + handlers = []; + this.handlers.set(channel, handlers); + } + handlers.push(handler); + } + + async signalReady() { + const start = (/** @type {string} */ parentOrigin) => { + window.parent.postMessage({ target: ID, channel: 'webview-ready', data: {} }, parentOrigin, [this.channel.port2]); + }; + + const parentOrigin = searchParams.get('parentOrigin'); + + const hostname = location.hostname; + + if (!crypto.subtle) { + // cannot validate, not running in a secure context + throw new Error(`Cannot validate in current context!`); + } + + // Here the `parentOriginHash()` function from `src/vs/workbench/common/webview.ts` is inlined + // compute a sha-256 composed of `parentOrigin` and `salt` converted to base 32 + let parentOriginHash; + try { + const strData = JSON.stringify({ parentOrigin, salt: webviewOrigin }); + const encoder = new TextEncoder(); + const arrData = encoder.encode(strData); + const hash = await crypto.subtle.digest('sha-256', arrData); + const hashArray = Array.from(new Uint8Array(hash)); + const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); + // sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32 + parentOriginHash = BigInt(`0x${hashHex}`).toString(32).padStart(52, '0'); + } catch (err) { + throw err instanceof Error ? err : new Error(String(err)); + } + + if (hostname === parentOriginHash || hostname.startsWith(parentOriginHash + '.')) { + // validation succeeded! + return start(parentOrigin); + } + + throw new Error(`Expected '${parentOriginHash}' as hostname or subdomain!`); + } + }(); + + const unloadMonitor = new class { + + constructor() { + this.confirmBeforeClose = 'keyboardOnly'; + this.isModifierKeyDown = false; + + hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => { + this.confirmBeforeClose = data; + }); + + hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => { + this.confirmBeforeClose = data.confirmBeforeClose; + }); + + window.addEventListener('beforeunload', (event) => { + if (onElectron) { + return; + } + + switch (this.confirmBeforeClose) { + case 'always': { + event.preventDefault(); + event.returnValue = ''; + return ''; + } + case 'never': { + break; + } + case 'keyboardOnly': + default: { + if (this.isModifierKeyDown) { + event.preventDefault(); + event.returnValue = ''; + return ''; + } + break; + } + } + }); + } + + onIframeLoaded(/** @type {HTMLIFrameElement} */ frame) { + frame.contentWindow.addEventListener('keydown', e => { + this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey; + }); + + frame.contentWindow.addEventListener('keyup', () => { + this.isModifierKeyDown = false; + }); + } + }; + + // state + let firstLoad = true; + /** @type {any} */ + let loadTimeout; + let styleVersion = 0; + + /** @type {Array<{ readonly message: any, transfer?: ArrayBuffer[] }>} */ + let pendingMessages = []; + + const initData = { + /** @type {number | undefined} */ + initialScrollProgress: undefined, + + /** @type {{ [key: string]: string } | undefined} */ + styles: undefined, + + /** @type {string | undefined} */ + activeTheme: undefined, + + /** @type {string | undefined} */ + themeName: undefined, + + /** @type {boolean} */ + screenReader: false, + + /** @type {boolean} */ + reduceMotion: false, + }; + + hostMessaging.onMessage('did-load-resource', (_event, data) => { + navigator.serviceWorker.ready.then(registration => { + assertIsDefined(registration.active).postMessage({ channel: 'did-load-resource', data }, data.data?.buffer ? [data.data.buffer] : []); + }); + }); + + hostMessaging.onMessage('did-load-localhost', (_event, data) => { + navigator.serviceWorker.ready.then(registration => { + assertIsDefined(registration.active).postMessage({ channel: 'did-load-localhost', data }); + }); + }); + + navigator.serviceWorker.addEventListener('message', event => { + switch (event.data.channel) { + case 'load-resource': + case 'load-localhost': + hostMessaging.postMessage(event.data.channel, event.data); + return; + } + }); + /** + * @param {HTMLDocument?} document + * @param {HTMLElement?} body + */ + const applyStyles = (document, body) => { + if (!document) { + return; + } + + if (body) { + body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast', 'vscode-reduce-motion', 'vscode-using-screen-reader'); + if (initData.activeTheme) { + body.classList.add(initData.activeTheme); + } + + if (initData.reduceMotion) { + body.classList.add('vscode-reduce-motion'); + } + + if (initData.screenReader) { + body.classList.add('vscode-using-screen-reader'); + } + + body.dataset.vscodeThemeKind = initData.activeTheme; + body.dataset.vscodeThemeName = initData.themeName || ''; + } + + if (initData.styles) { + const documentStyle = document.documentElement.style; + + // Remove stale properties + for (let i = documentStyle.length - 1; i >= 0; i--) { + const property = documentStyle[i]; + + // Don't remove properties that the webview might have added separately + if (property && property.startsWith('--vscode-')) { + documentStyle.removeProperty(property); + } + } + + // Re-add new properties + for (const variable of Object.keys(initData.styles)) { + documentStyle.setProperty(`--${variable}`, initData.styles[variable]); + } + } + }; + + /** + * @param {MouseEvent} event + */ + const handleInnerClick = (event) => { + if (!event?.view?.document) { + return; + } + + const baseElement = event.view.document.querySelector('base'); + + for (const pathElement of event.composedPath()) { + /** @type {any} */ + const node = pathElement; + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + if (node.getAttribute('href') === '#') { + event.view.scrollTo(0, 0); + } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href === baseElement.href + node.hash))) { + const fragment = node.hash.slice(1); + const scrollTarget = event.view.document.getElementById(fragment) ?? event.view.document.getElementById(decodeURIComponent(fragment)); + scrollTarget?.scrollIntoView(); + } else { + hostMessaging.postMessage('did-click-link', node.href.baseVal || node.href); + } + event.preventDefault(); + return; + } + } + }; + + /** + * @param {MouseEvent} event + */ + const handleAuxClick = (event) => { + // Prevent middle clicks opening a broken link in the browser + if (!event?.view?.document) { + return; + } + + if (event.button === 1) { + for (const pathElement of event.composedPath()) { + /** @type {any} */ + const node = pathElement; + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + event.preventDefault(); + return; + } + } + } + }; + + /** + * @param {KeyboardEvent} e + */ + const handleInnerKeydown = (e) => { + // If the keypress would trigger a browser event, such as copy or paste, + // make sure we block the browser from dispatching it. Instead VS Code + // handles these events and will dispatch a copy/paste back to the webview + // if needed + if (isUndoRedo(e) || isPrint(e) || isFindEvent(e)) { + e.preventDefault(); + } else if (isCopyPasteOrCut(e)) { + if (onElectron) { + e.preventDefault(); + } else { + return; // let the browser handle this + } + } + + hostMessaging.postMessage('did-keydown', { + key: e.key, + keyCode: e.keyCode, + code: e.code, + shiftKey: e.shiftKey, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + repeat: e.repeat + }); + }; + /** + * @param {KeyboardEvent} e + */ + const handleInnerUp = (e) => { + hostMessaging.postMessage('did-keyup', { + key: e.key, + keyCode: e.keyCode, + code: e.code, + shiftKey: e.shiftKey, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + repeat: e.repeat + }); + }; + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isCopyPasteOrCut(e) { + const hasMeta = e.ctrlKey || e.metaKey; + const shiftInsert = e.shiftKey && e.key.toLowerCase() === 'insert'; + return (hasMeta && ['c', 'v', 'x'].includes(e.key.toLowerCase())) || shiftInsert; + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isUndoRedo(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && ['z', 'y'].includes(e.key.toLowerCase()); + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isPrint(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && e.key.toLowerCase() === 'p'; + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isFindEvent(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && e.key.toLowerCase() === 'f'; + } + + let isHandlingScroll = false; + + /** + * @param {WheelEvent} event + */ + const handleWheel = (event) => { + if (isHandlingScroll) { + return; + } + + hostMessaging.postMessage('did-scroll-wheel', { + deltaMode: event.deltaMode, + deltaX: event.deltaX, + deltaY: event.deltaY, + deltaZ: event.deltaZ, + detail: event.detail, + type: event.type + }); + }; + + /** + * @param {Event} event + */ + const handleInnerScroll = (event) => { + if (isHandlingScroll) { + return; + } + + const target = /** @type {HTMLDocument | null} */ (event.target); + const currentTarget = /** @type {Window | null} */ (event.currentTarget); + if (!currentTarget || !target?.body) { + return; + } + + const progress = currentTarget.scrollY / target.body.clientHeight; + if (isNaN(progress)) { + return; + } + + isHandlingScroll = true; + window.requestAnimationFrame(() => { + try { + hostMessaging.postMessage('did-scroll', progress); + } catch (e) { + // noop + } + isHandlingScroll = false; + }); + }; + + function handleInnerDragStartEvent(/** @type {DragEvent} */ e) { + if (e.defaultPrevented) { + // Extension code has already handled this event + return; + } + + if (!e.dataTransfer || e.shiftKey) { + return; + } + + // Only handle drags from outside editor for now + if (e.dataTransfer.items.length && Array.prototype.every.call(e.dataTransfer.items, item => item.kind === 'file')) { + hostMessaging.postMessage('drag-start'); + } + } + + /** + * @param {() => void} callback + */ + function onDomReady(callback) { + if (document.readyState === 'interactive' || document.readyState === 'complete') { + callback(); + } else { + document.addEventListener('DOMContentLoaded', callback); + } + } + + function areServiceWorkersEnabled() { + try { + return !!navigator.serviceWorker; + } catch (e) { + return false; + } + } + + /** + * @typedef {{ + * contents: string; + * options: { + * readonly allowScripts: boolean; + * readonly allowForms: boolean; + * readonly allowMultipleAPIAcquire: boolean; + * } + * state: any; + * cspSource: string; + * }} ContentUpdateData + */ + + /** + * @param {ContentUpdateData} data + * @return {string} + */ + function toContentHtml(data) { + const options = data.options; + const text = data.contents; + const newDocument = new DOMParser().parseFromString(text, 'text/html'); + + newDocument.querySelectorAll('a').forEach(a => { + if (!a.title) { + const href = a.getAttribute('href'); + if (typeof href === 'string') { + a.title = href; + } + } + }); + + // Set default aria role + if (!newDocument.body.hasAttribute('role')) { + newDocument.body.setAttribute('role', 'document'); + } + + // Inject default script + if (options.allowScripts) { + const defaultScript = newDocument.createElement('script'); + defaultScript.id = '_vscodeApiScript'; + defaultScript.textContent = getVsCodeApiScript(options.allowMultipleAPIAcquire, data.state); + newDocument.head.prepend(defaultScript); + } + + // Inject default styles + newDocument.head.prepend(defaultStyles.cloneNode(true)); + + applyStyles(newDocument, newDocument.body); + + // Strip out unsupported http-equiv tags + for (const metaElement of Array.from(newDocument.querySelectorAll('meta'))) { + const httpEquiv = metaElement.getAttribute('http-equiv'); + if (httpEquiv && !/^(content-security-policy|default-style|content-type)$/i.test(httpEquiv)) { + console.warn(`Removing unsupported meta http-equiv: ${httpEquiv}`); + metaElement.remove(); + } + } + + // Check for CSP + const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]'); + if (!csp) { + hostMessaging.postMessage('no-csp-found'); + } else { + try { + // Attempt to rewrite CSPs that hardcode old-style resource endpoint + const cspContent = csp.getAttribute('content'); + if (cspContent) { + const newCsp = cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, data.cspSource); + csp.setAttribute('content', newCsp); + } + } catch (e) { + console.error(`Could not rewrite csp: ${e}`); + } + } + + // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off + // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden + return '<!DOCTYPE html>\n' + newDocument.documentElement.outerHTML; + } + + onDomReady(() => { + if (!document.body) { + return; + } + + hostMessaging.onMessage('styles', (_event, data) => { + ++styleVersion; + + initData.styles = data.styles; + initData.activeTheme = data.activeTheme; + initData.themeName = data.themeName; + initData.reduceMotion = data.reduceMotion; + initData.screenReader = data.screenReader; + + const target = getActiveFrame(); + if (!target) { + return; + } + + if (target.contentDocument) { + applyStyles(target.contentDocument, target.contentDocument.body); + } + }); + + // propagate focus + hostMessaging.onMessage('focus', () => { + const activeFrame = getActiveFrame(); + if (!activeFrame || !activeFrame.contentWindow) { + // Focus the top level webview instead + window.focus(); + return; + } + + if (document.activeElement === activeFrame) { + // We are already focused on the iframe (or one of its children) so no need + // to refocus. + return; + } + + activeFrame.contentWindow.focus(); + }); + + // update iframe-contents + let updateId = 0; + hostMessaging.onMessage('content', async (_event, /** @type {ContentUpdateData} */ data) => { + const currentUpdateId = ++updateId; + try { + await workerReady; + } catch (e) { + console.error(`Webview fatal error: ${e}`); + hostMessaging.postMessage('fatal-error', { message: e + '' }); + return; + } + + if (currentUpdateId !== updateId) { + return; + } + + const options = data.options; + const newDocument = toContentHtml(data); + + const initialStyleVersion = styleVersion; + + const frame = getActiveFrame(); + const wasFirstLoad = firstLoad; + // keep current scrollY around and use later + /** @type {(body: HTMLElement, window: Window) => void} */ + let setInitialScrollPosition; + if (firstLoad) { + firstLoad = false; + setInitialScrollPosition = (body, window) => { + if (typeof initData.initialScrollProgress === 'number' && !isNaN(initData.initialScrollProgress)) { + if (window.scrollY === 0) { + window.scroll(0, body.clientHeight * initData.initialScrollProgress); + } + } + }; + } else { + const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? assertIsDefined(frame.contentWindow).scrollY : 0; + setInitialScrollPosition = (body, window) => { + if (window.scrollY === 0) { + window.scroll(0, scrollY); + } + }; + } + + // Clean up old pending frames and set current one as new one + const previousPendingFrame = getPendingFrame(); + if (previousPendingFrame) { + previousPendingFrame.setAttribute('id', ''); + document.body.removeChild(previousPendingFrame); + } + if (!wasFirstLoad) { + pendingMessages = []; + } + + const newFrame = document.createElement('iframe'); + newFrame.setAttribute('id', 'pending-frame'); + newFrame.setAttribute('frameborder', '0'); + + const sandboxRules = new Set(['allow-same-origin', 'allow-pointer-lock']); + if (options.allowScripts) { + sandboxRules.add('allow-scripts'); + sandboxRules.add('allow-downloads'); + } + if (options.allowForms) { + sandboxRules.add('allow-forms'); + } + newFrame.setAttribute('sandbox', Array.from(sandboxRules).join(' ')); + if (!isFirefox) { + newFrame.setAttribute('allow', options.allowScripts ? 'clipboard-read; clipboard-write;' : ''); + } + // We should just be able to use srcdoc, but I wasn't + // seeing the service worker applying properly. + // Fake load an empty on the correct origin and then write real html + // into it to get around this. + newFrame.src = `./fake.html?id=${ID}`; + + newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; + document.body.appendChild(newFrame); + + /** + * @param {Document} contentDocument + */ + function onFrameLoaded(contentDocument) { + // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=978325 + setTimeout(() => { + contentDocument.open(); + contentDocument.write(newDocument); + contentDocument.close(); + hookupOnLoadHandlers(newFrame); + + if (initialStyleVersion !== styleVersion) { + applyStyles(contentDocument, contentDocument.body); + } + }, 0); + } + + if (!options.allowScripts && isSafari) { + // On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired: https://bugs.webkit.org/show_bug.cgi?id=33604 + // Use polling instead. + const interval = setInterval(() => { + // If the frame is no longer mounted, loading has stopped + if (!newFrame.parentElement) { + clearInterval(interval); + return; + } + + const contentDocument = assertIsDefined(newFrame.contentDocument); + if (contentDocument.location.pathname.endsWith('/fake.html') && contentDocument.readyState !== 'loading') { + clearInterval(interval); + onFrameLoaded(contentDocument); + } + }, 10); + } else { + assertIsDefined(newFrame.contentWindow).addEventListener('DOMContentLoaded', e => { + const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined; + onFrameLoaded(assertIsDefined(contentDocument)); + }); + } + + /** + * @param {Document} contentDocument + * @param {Window} contentWindow + */ + const onLoad = (contentDocument, contentWindow) => { + if (contentDocument && contentDocument.body) { + // Workaround for https://github.com/microsoft/vscode/issues/12865 + // check new scrollY and reset if necessary + setInitialScrollPosition(contentDocument.body, contentWindow); + } + + const newFrame = getPendingFrame(); + if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) { + const wasFocused = document.hasFocus(); + const oldActiveFrame = getActiveFrame(); + if (oldActiveFrame) { + document.body.removeChild(oldActiveFrame); + } + // Styles may have changed since we created the element. Make sure we re-style + if (initialStyleVersion !== styleVersion) { + applyStyles(newFrame.contentDocument, newFrame.contentDocument.body); + } + newFrame.setAttribute('id', 'active-frame'); + newFrame.style.visibility = 'visible'; + + contentWindow.addEventListener('scroll', handleInnerScroll); + contentWindow.addEventListener('wheel', handleWheel); + + if (wasFocused) { + contentWindow.focus(); + } + + pendingMessages.forEach((message) => { + contentWindow.postMessage(message.message, window.origin, message.transfer); + }); + pendingMessages = []; + } + }; + + /** + * @param {HTMLIFrameElement} newFrame + */ + function hookupOnLoadHandlers(newFrame) { + clearTimeout(loadTimeout); + loadTimeout = undefined; + loadTimeout = setTimeout(() => { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(assertIsDefined(newFrame.contentDocument), assertIsDefined(newFrame.contentWindow)); + }, 200); + + const contentWindow = assertIsDefined(newFrame.contentWindow); + + contentWindow.addEventListener('load', function (e) { + const contentDocument = /** @type {Document} */ (e.target); + + if (loadTimeout) { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(contentDocument, this); + } + }); + + // Bubble out various events + contentWindow.addEventListener('click', handleInnerClick); + contentWindow.addEventListener('auxclick', handleAuxClick); + contentWindow.addEventListener('keydown', handleInnerKeydown); + contentWindow.addEventListener('keyup', handleInnerUp); + contentWindow.addEventListener('contextmenu', e => { + if (e.defaultPrevented) { + // Extension code has already handled this event + return; + } + + e.preventDefault(); + hostMessaging.postMessage('did-context-menu', { + clientX: e.clientX, + clientY: e.clientY, + }); + }); + + contentWindow.addEventListener('dragenter', handleInnerDragStartEvent); + contentWindow.addEventListener('dragover', handleInnerDragStartEvent); + + unloadMonitor.onIframeLoaded(newFrame); + } + }); + + // Forward message to the embedded iframe + hostMessaging.onMessage('message', (_event, /** @type {{message: any, transfer?: ArrayBuffer[] }} */ data) => { + const pending = getPendingFrame(); + if (!pending) { + const target = getActiveFrame(); + if (target) { + assertIsDefined(target.contentWindow).postMessage(data.message, window.origin, data.transfer); + return; + } + } + pendingMessages.push(data); + }); + + hostMessaging.onMessage('initial-scroll-position', (_event, progress) => { + initData.initialScrollProgress = progress; + }); + + hostMessaging.onMessage('execCommand', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + assertIsDefined(target.contentDocument).execCommand(data); + }); + + /** @type {string | undefined} */ + let lastFindValue = undefined; + + hostMessaging.onMessage('find', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + + if (!data.previous && lastFindValue !== data.value) { + // Reset selection so we start search at the head of the last search + const selection = target.contentWindow.getSelection(); + selection.collapse(selection.anchorNode); + } + lastFindValue = data.value; + + const didFind = (/** @type {any} */ (target.contentWindow)).find( + data.value, + /* caseSensitive*/ false, + /* backwards*/ data.previous, + /* wrapAround*/ true, + /* wholeWord */ false, + /* searchInFrames*/ false, + false); + hostMessaging.postMessage('did-find', didFind); + }); + + hostMessaging.onMessage('find-stop', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + + lastFindValue = undefined; + + if (!data.clearSelection) { + const selection = target.contentWindow.getSelection(); + for (let i = 0; i < selection.rangeCount; i++) { + selection.removeRange(selection.getRangeAt(i)); + } + } + }); + + trackFocus({ + onFocus: () => hostMessaging.postMessage('did-focus'), + onBlur: () => hostMessaging.postMessage('did-blur') + }); + + (/** @type {any} */ (window))[vscodePostMessageFuncName] = (/** @type {string} */ command, /** @type {any} */ data) => { + switch (command) { + case 'onmessage': + case 'do-update-state': + hostMessaging.postMessage(command, data); + break; + } + }; + + // Also forward events before the contents of the webview have loaded + window.addEventListener('keydown', handleInnerKeydown); + window.addEventListener('dragenter', handleInnerDragStartEvent); + window.addEventListener('dragover', handleInnerDragStartEvent); + + hostMessaging.signalReady(); + }); + </script> </body> </html> diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index 3f2ade8478f..457447af38e 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -4,7 +4,8 @@ <head> <meta charset="UTF-8"> - <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; frame-src 'self'; style-src 'unsafe-inline';"> + <meta http-equiv="Content-Security-Policy" + content="default-src 'none'; script-src 'sha256-xgIcbQmGjpT42GEj54VFSNh6MI15PZ2D1+DdVehfYBI=' 'self'; frame-src 'self'; style-src 'unsafe-inline';"> <!-- Disable pinch zooming --> <meta name="viewport" @@ -14,7 +15,1136 @@ </head> <body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document"> - <script async type="module" src="main.js"></script> + <script async type="module"> + // @ts-check + /// <reference lib="dom" /> + + const isSafari = ( + navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && + navigator.userAgent && + navigator.userAgent.indexOf('CriOS') === -1 && + navigator.userAgent.indexOf('FxiOS') === -1 + ); + + const isFirefox = ( + navigator.userAgent && + navigator.userAgent.indexOf('Firefox') >= 0 + ); + + const searchParams = new URL(location.toString()).searchParams; + const ID = searchParams.get('id'); + const webviewOrigin = searchParams.get('origin'); + const onElectron = searchParams.get('platform') === 'electron'; + const expectedWorkerVersion = parseInt(searchParams.get('swVersion')); + + /** + * Use polling to track focus of main webview and iframes within the webview + * + * @param {Object} handlers + * @param {() => void} handlers.onFocus + * @param {() => void} handlers.onBlur + */ + const trackFocus = ({ onFocus, onBlur }) => { + const interval = 250; + let isFocused = document.hasFocus(); + setInterval(() => { + const isCurrentlyFocused = document.hasFocus(); + if (isCurrentlyFocused === isFocused) { + return; + } + isFocused = isCurrentlyFocused; + if (isCurrentlyFocused) { + onFocus(); + } else { + onBlur(); + } + }, interval); + }; + + const getActiveFrame = () => { + return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('active-frame')); + }; + + const getPendingFrame = () => { + return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('pending-frame')); + }; + + /** + * @template T + * @param {T | undefined | null} obj + * @return {T} + */ + function assertIsDefined(obj) { + if (typeof obj === 'undefined' || obj === null) { + throw new Error('Found unexpected null'); + } + return obj; + } + + const vscodePostMessageFuncName = '__vscode_post_message__'; + + const defaultStyles = document.createElement('style'); + defaultStyles.id = '_defaultStyles'; + defaultStyles.textContent = ` + html { + scrollbar-color: var(--vscode-scrollbarSlider-background) var(--vscode-editor-background); + } + + body { + background-color: transparent; + color: var(--vscode-editor-foreground); + font-family: var(--vscode-font-family); + font-weight: var(--vscode-font-weight); + font-size: var(--vscode-font-size); + margin: 0; + padding: 0 20px; + } + + img { + max-width: 100%; + max-height: 100%; + } + + a, a code { + color: var(--vscode-textLink-foreground); + } + + a:hover { + color: var(--vscode-textLink-activeForeground); + } + + a:focus, + input:focus, + select:focus, + textarea:focus { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: -1px; + } + + code { + color: var(--vscode-textPreformat-foreground); + } + + blockquote { + background: var(--vscode-textBlockQuote-background); + border-color: var(--vscode-textBlockQuote-border); + } + + kbd { + color: var(--vscode-editor-foreground); + border-radius: 3px; + vertical-align: middle; + padding: 1px 3px; + + background-color: hsla(0,0%,50%,.17); + border: 1px solid rgba(71,71,71,.4); + border-bottom-color: rgba(88,88,88,.4); + box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); + } + .vscode-light kbd { + background-color: hsla(0,0%,87%,.5); + border: 1px solid hsla(0,0%,80%,.7); + border-bottom-color: hsla(0,0%,73%,.7); + box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); + } + + ::-webkit-scrollbar { + width: 10px; + height: 10px; + } + + ::-webkit-scrollbar-corner { + background-color: var(--vscode-editor-background); + } + + ::-webkit-scrollbar-thumb { + background-color: var(--vscode-scrollbarSlider-background); + } + ::-webkit-scrollbar-thumb:hover { + background-color: var(--vscode-scrollbarSlider-hoverBackground); + } + ::-webkit-scrollbar-thumb:active { + background-color: var(--vscode-scrollbarSlider-activeBackground); + } + ::highlight(find-highlight) { + background-color: var(--vscode-editor-findMatchHighlightBackground); + } + ::highlight(current-find-highlight) { + background-color: var(--vscode-editor-findMatchBackground); + }`; + + /** + * @param {boolean} allowMultipleAPIAcquire + * @param {*} [state] + * @return {string} + */ + function getVsCodeApiScript(allowMultipleAPIAcquire, state) { + const encodedState = state ? encodeURIComponent(state) : undefined; + return /* js */` + globalThis.acquireVsCodeApi = (function() { + const originalPostMessage = window.parent['${vscodePostMessageFuncName}'].bind(window.parent); + const doPostMessage = (channel, data, transfer) => { + originalPostMessage(channel, data, transfer); + }; + + let acquired = false; + + let state = ${state ? `JSON.parse(decodeURIComponent("${encodedState}"))` : undefined}; + + return () => { + if (acquired && !${allowMultipleAPIAcquire}) { + throw new Error('An instance of the VS Code API has already been acquired'); + } + acquired = true; + return Object.freeze({ + postMessage: function(message, transfer) { + doPostMessage('onmessage', { message, transfer }, transfer); + }, + setState: function(newState) { + state = newState; + doPostMessage('do-update-state', JSON.stringify(newState)); + return newState; + }, + getState: function() { + return state; + } + }); + }; + })(); + delete window.parent; + delete window.top; + delete window.frameElement; + `; + } + + /** @type {Promise<void>} */ + const workerReady = new Promise((resolve, reject) => { + if (!areServiceWorkersEnabled()) { + return reject(new Error('Service Workers are not enabled. Webviews will not work. Try disabling private/incognito mode.')); + } + + const swPath = `service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`; + navigator.serviceWorker.register(swPath) + .then(() => navigator.serviceWorker.ready) + .then(async registration => { + /** + * @param {MessageEvent} event + */ + const versionHandler = async (event) => { + if (event.data.channel !== 'version') { + return; + } + + navigator.serviceWorker.removeEventListener('message', versionHandler); + if (event.data.version === expectedWorkerVersion) { + return resolve(); + } else { + console.log(`Found unexpected service worker version. Found: ${event.data.version}. Expected: ${expectedWorkerVersion}`); + console.log(`Attempting to reload service worker`); + + // If we have the wrong version, try once (and only once) to unregister and re-register + // Note that `.update` doesn't seem to work desktop electron at the moment so we use + // `unregister` and `register` here. + return registration.unregister() + .then(() => navigator.serviceWorker.register(swPath)) + .then(() => navigator.serviceWorker.ready) + .finally(() => { resolve(); }); + } + }; + navigator.serviceWorker.addEventListener('message', versionHandler); + + const postVersionMessage = (/** @type {ServiceWorker} */ controller) => { + controller.postMessage({ channel: 'version' }); + }; + + // At this point, either the service worker is ready and + // became our controller, or we need to wait for it. + // Note that navigator.serviceWorker.controller could be a + // controller from a previously loaded service worker. + const currentController = navigator.serviceWorker.controller; + if (currentController?.scriptURL.endsWith(swPath)) { + // service worker already loaded & ready to receive messages + postVersionMessage(currentController); + } else { + // either there's no controlling service worker, or it's an old one: + // wait for it to change before posting the message + const onControllerChange = () => { + navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange); + postVersionMessage(navigator.serviceWorker.controller); + }; + navigator.serviceWorker.addEventListener('controllerchange', onControllerChange); + } + }).catch(error => { + reject(new Error(`Could not register service workers: ${error}.`)); + }); + }); + + const hostMessaging = new class HostMessaging { + + constructor() { + this.channel = new MessageChannel(); + + /** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */ + this.handlers = new Map(); + + this.channel.port1.onmessage = (e) => { + const channel = e.data.channel; + const handlers = this.handlers.get(channel); + if (handlers) { + for (const handler of handlers) { + handler(e, e.data.args); + } + } else { + console.log('no handler for ', e); + } + }; + } + + /** + * @param {string} channel + * @param {any} data + * @param {any} [transfer] + */ + postMessage(channel, data, transfer) { + this.channel.port1.postMessage({ channel, data }, transfer); + } + + /** + * @param {string} channel + * @param {(event: MessageEvent, data: any) => void} handler + */ + onMessage(channel, handler) { + let handlers = this.handlers.get(channel); + if (!handlers) { + handlers = []; + this.handlers.set(channel, handlers); + } + handlers.push(handler); + } + + async signalReady() { + const start = (/** @type {string} */ parentOrigin) => { + window.parent.postMessage({ target: ID, channel: 'webview-ready', data: {} }, parentOrigin, [this.channel.port2]); + }; + + const parentOrigin = searchParams.get('parentOrigin'); + + const hostname = location.hostname; + + if (!crypto.subtle) { + // cannot validate, not running in a secure context + throw new Error(`Cannot validate in current context!`); + } + + // Here the `parentOriginHash()` function from `src/vs/workbench/common/webview.ts` is inlined + // compute a sha-256 composed of `parentOrigin` and `salt` converted to base 32 + let parentOriginHash; + try { + const strData = JSON.stringify({ parentOrigin, salt: webviewOrigin }); + const encoder = new TextEncoder(); + const arrData = encoder.encode(strData); + const hash = await crypto.subtle.digest('sha-256', arrData); + const hashArray = Array.from(new Uint8Array(hash)); + const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); + // sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32 + parentOriginHash = BigInt(`0x${hashHex}`).toString(32).padStart(52, '0'); + } catch (err) { + throw err instanceof Error ? err : new Error(String(err)); + } + + if (hostname === parentOriginHash || hostname.startsWith(parentOriginHash + '.')) { + // validation succeeded! + return start(parentOrigin); + } + + throw new Error(`Expected '${parentOriginHash}' as hostname or subdomain!`); + } + }(); + + const unloadMonitor = new class { + + constructor() { + this.confirmBeforeClose = 'keyboardOnly'; + this.isModifierKeyDown = false; + + hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => { + this.confirmBeforeClose = data; + }); + + hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => { + this.confirmBeforeClose = data.confirmBeforeClose; + }); + + window.addEventListener('beforeunload', (event) => { + if (onElectron) { + return; + } + + switch (this.confirmBeforeClose) { + case 'always': { + event.preventDefault(); + event.returnValue = ''; + return ''; + } + case 'never': { + break; + } + case 'keyboardOnly': + default: { + if (this.isModifierKeyDown) { + event.preventDefault(); + event.returnValue = ''; + return ''; + } + break; + } + } + }); + } + + onIframeLoaded(/** @type {HTMLIFrameElement} */ frame) { + frame.contentWindow.addEventListener('keydown', e => { + this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey; + }); + + frame.contentWindow.addEventListener('keyup', () => { + this.isModifierKeyDown = false; + }); + } + }; + + // state + let firstLoad = true; + /** @type {any} */ + let loadTimeout; + let styleVersion = 0; + + /** @type {Array<{ readonly message: any, transfer?: ArrayBuffer[] }>} */ + let pendingMessages = []; + + const initData = { + /** @type {number | undefined} */ + initialScrollProgress: undefined, + + /** @type {{ [key: string]: string } | undefined} */ + styles: undefined, + + /** @type {string | undefined} */ + activeTheme: undefined, + + /** @type {string | undefined} */ + themeName: undefined, + + /** @type {boolean} */ + screenReader: false, + + /** @type {boolean} */ + reduceMotion: false, + }; + + hostMessaging.onMessage('did-load-resource', (_event, data) => { + navigator.serviceWorker.ready.then(registration => { + assertIsDefined(registration.active).postMessage({ channel: 'did-load-resource', data }, data.data?.buffer ? [data.data.buffer] : []); + }); + }); + + hostMessaging.onMessage('did-load-localhost', (_event, data) => { + navigator.serviceWorker.ready.then(registration => { + assertIsDefined(registration.active).postMessage({ channel: 'did-load-localhost', data }); + }); + }); + + navigator.serviceWorker.addEventListener('message', event => { + switch (event.data.channel) { + case 'load-resource': + case 'load-localhost': + hostMessaging.postMessage(event.data.channel, event.data); + return; + } + }); + /** + * @param {HTMLDocument?} document + * @param {HTMLElement?} body + */ + const applyStyles = (document, body) => { + if (!document) { + return; + } + + if (body) { + body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast', 'vscode-reduce-motion', 'vscode-using-screen-reader'); + if (initData.activeTheme) { + body.classList.add(initData.activeTheme); + } + + if (initData.reduceMotion) { + body.classList.add('vscode-reduce-motion'); + } + + if (initData.screenReader) { + body.classList.add('vscode-using-screen-reader'); + } + + body.dataset.vscodeThemeKind = initData.activeTheme; + body.dataset.vscodeThemeName = initData.themeName || ''; + } + + if (initData.styles) { + const documentStyle = document.documentElement.style; + + // Remove stale properties + for (let i = documentStyle.length - 1; i >= 0; i--) { + const property = documentStyle[i]; + + // Don't remove properties that the webview might have added separately + if (property && property.startsWith('--vscode-')) { + documentStyle.removeProperty(property); + } + } + + // Re-add new properties + for (const variable of Object.keys(initData.styles)) { + documentStyle.setProperty(`--${variable}`, initData.styles[variable]); + } + } + }; + + /** + * @param {MouseEvent} event + */ + const handleInnerClick = (event) => { + if (!event?.view?.document) { + return; + } + + const baseElement = event.view.document.querySelector('base'); + + for (const pathElement of event.composedPath()) { + /** @type {any} */ + const node = pathElement; + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + if (node.getAttribute('href') === '#') { + event.view.scrollTo(0, 0); + } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href === baseElement.href + node.hash))) { + const fragment = node.hash.slice(1); + const scrollTarget = event.view.document.getElementById(fragment) ?? event.view.document.getElementById(decodeURIComponent(fragment)); + scrollTarget?.scrollIntoView(); + } else { + hostMessaging.postMessage('did-click-link', node.href.baseVal || node.href); + } + event.preventDefault(); + return; + } + } + }; + + /** + * @param {MouseEvent} event + */ + const handleAuxClick = (event) => { + // Prevent middle clicks opening a broken link in the browser + if (!event?.view?.document) { + return; + } + + if (event.button === 1) { + for (const pathElement of event.composedPath()) { + /** @type {any} */ + const node = pathElement; + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + event.preventDefault(); + return; + } + } + } + }; + + /** + * @param {KeyboardEvent} e + */ + const handleInnerKeydown = (e) => { + // If the keypress would trigger a browser event, such as copy or paste, + // make sure we block the browser from dispatching it. Instead VS Code + // handles these events and will dispatch a copy/paste back to the webview + // if needed + if (isUndoRedo(e) || isPrint(e) || isFindEvent(e)) { + e.preventDefault(); + } else if (isCopyPasteOrCut(e)) { + if (onElectron) { + e.preventDefault(); + } else { + return; // let the browser handle this + } + } + + hostMessaging.postMessage('did-keydown', { + key: e.key, + keyCode: e.keyCode, + code: e.code, + shiftKey: e.shiftKey, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + repeat: e.repeat + }); + }; + /** + * @param {KeyboardEvent} e + */ + const handleInnerUp = (e) => { + hostMessaging.postMessage('did-keyup', { + key: e.key, + keyCode: e.keyCode, + code: e.code, + shiftKey: e.shiftKey, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + repeat: e.repeat + }); + }; + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isCopyPasteOrCut(e) { + const hasMeta = e.ctrlKey || e.metaKey; + const shiftInsert = e.shiftKey && e.key.toLowerCase() === 'insert'; + return (hasMeta && ['c', 'v', 'x'].includes(e.key.toLowerCase())) || shiftInsert; + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isUndoRedo(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && ['z', 'y'].includes(e.key.toLowerCase()); + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isPrint(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && e.key.toLowerCase() === 'p'; + } + + /** + * @param {KeyboardEvent} e + * @return {boolean} + */ + function isFindEvent(e) { + const hasMeta = e.ctrlKey || e.metaKey; + return hasMeta && e.key.toLowerCase() === 'f'; + } + + let isHandlingScroll = false; + + /** + * @param {WheelEvent} event + */ + const handleWheel = (event) => { + if (isHandlingScroll) { + return; + } + + hostMessaging.postMessage('did-scroll-wheel', { + deltaMode: event.deltaMode, + deltaX: event.deltaX, + deltaY: event.deltaY, + deltaZ: event.deltaZ, + detail: event.detail, + type: event.type + }); + }; + + /** + * @param {Event} event + */ + const handleInnerScroll = (event) => { + if (isHandlingScroll) { + return; + } + + const target = /** @type {HTMLDocument | null} */ (event.target); + const currentTarget = /** @type {Window | null} */ (event.currentTarget); + if (!currentTarget || !target?.body) { + return; + } + + const progress = currentTarget.scrollY / target.body.clientHeight; + if (isNaN(progress)) { + return; + } + + isHandlingScroll = true; + window.requestAnimationFrame(() => { + try { + hostMessaging.postMessage('did-scroll', progress); + } catch (e) { + // noop + } + isHandlingScroll = false; + }); + }; + + function handleInnerDragStartEvent(/** @type {DragEvent} */ e) { + if (e.defaultPrevented) { + // Extension code has already handled this event + return; + } + + if (!e.dataTransfer || e.shiftKey) { + return; + } + + // Only handle drags from outside editor for now + if (e.dataTransfer.items.length && Array.prototype.every.call(e.dataTransfer.items, item => item.kind === 'file')) { + hostMessaging.postMessage('drag-start'); + } + } + + /** + * @param {() => void} callback + */ + function onDomReady(callback) { + if (document.readyState === 'interactive' || document.readyState === 'complete') { + callback(); + } else { + document.addEventListener('DOMContentLoaded', callback); + } + } + + function areServiceWorkersEnabled() { + try { + return !!navigator.serviceWorker; + } catch (e) { + return false; + } + } + + /** + * @typedef {{ + * contents: string; + * options: { + * readonly allowScripts: boolean; + * readonly allowForms: boolean; + * readonly allowMultipleAPIAcquire: boolean; + * } + * state: any; + * cspSource: string; + * }} ContentUpdateData + */ + + /** + * @param {ContentUpdateData} data + * @return {string} + */ + function toContentHtml(data) { + const options = data.options; + const text = data.contents; + const newDocument = new DOMParser().parseFromString(text, 'text/html'); + + newDocument.querySelectorAll('a').forEach(a => { + if (!a.title) { + const href = a.getAttribute('href'); + if (typeof href === 'string') { + a.title = href; + } + } + }); + + // Set default aria role + if (!newDocument.body.hasAttribute('role')) { + newDocument.body.setAttribute('role', 'document'); + } + + // Inject default script + if (options.allowScripts) { + const defaultScript = newDocument.createElement('script'); + defaultScript.id = '_vscodeApiScript'; + defaultScript.textContent = getVsCodeApiScript(options.allowMultipleAPIAcquire, data.state); + newDocument.head.prepend(defaultScript); + } + + // Inject default styles + newDocument.head.prepend(defaultStyles.cloneNode(true)); + + applyStyles(newDocument, newDocument.body); + + // Strip out unsupported http-equiv tags + for (const metaElement of Array.from(newDocument.querySelectorAll('meta'))) { + const httpEquiv = metaElement.getAttribute('http-equiv'); + if (httpEquiv && !/^(content-security-policy|default-style|content-type)$/i.test(httpEquiv)) { + console.warn(`Removing unsupported meta http-equiv: ${httpEquiv}`); + metaElement.remove(); + } + } + + // Check for CSP + const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]'); + if (!csp) { + hostMessaging.postMessage('no-csp-found'); + } else { + try { + // Attempt to rewrite CSPs that hardcode old-style resource endpoint + const cspContent = csp.getAttribute('content'); + if (cspContent) { + const newCsp = cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, data.cspSource); + csp.setAttribute('content', newCsp); + } + } catch (e) { + console.error(`Could not rewrite csp: ${e}`); + } + } + + // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off + // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden + return '<!DOCTYPE html>\n' + newDocument.documentElement.outerHTML; + } + + onDomReady(() => { + if (!document.body) { + return; + } + + hostMessaging.onMessage('styles', (_event, data) => { + ++styleVersion; + + initData.styles = data.styles; + initData.activeTheme = data.activeTheme; + initData.themeName = data.themeName; + initData.reduceMotion = data.reduceMotion; + initData.screenReader = data.screenReader; + + const target = getActiveFrame(); + if (!target) { + return; + } + + if (target.contentDocument) { + applyStyles(target.contentDocument, target.contentDocument.body); + } + }); + + // propagate focus + hostMessaging.onMessage('focus', () => { + const activeFrame = getActiveFrame(); + if (!activeFrame || !activeFrame.contentWindow) { + // Focus the top level webview instead + window.focus(); + return; + } + + if (document.activeElement === activeFrame) { + // We are already focused on the iframe (or one of its children) so no need + // to refocus. + return; + } + + activeFrame.contentWindow.focus(); + }); + + // update iframe-contents + let updateId = 0; + hostMessaging.onMessage('content', async (_event, /** @type {ContentUpdateData} */ data) => { + const currentUpdateId = ++updateId; + try { + await workerReady; + } catch (e) { + console.error(`Webview fatal error: ${e}`); + hostMessaging.postMessage('fatal-error', { message: e + '' }); + return; + } + + if (currentUpdateId !== updateId) { + return; + } + + const options = data.options; + const newDocument = toContentHtml(data); + + const initialStyleVersion = styleVersion; + + const frame = getActiveFrame(); + const wasFirstLoad = firstLoad; + // keep current scrollY around and use later + /** @type {(body: HTMLElement, window: Window) => void} */ + let setInitialScrollPosition; + if (firstLoad) { + firstLoad = false; + setInitialScrollPosition = (body, window) => { + if (typeof initData.initialScrollProgress === 'number' && !isNaN(initData.initialScrollProgress)) { + if (window.scrollY === 0) { + window.scroll(0, body.clientHeight * initData.initialScrollProgress); + } + } + }; + } else { + const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? assertIsDefined(frame.contentWindow).scrollY : 0; + setInitialScrollPosition = (body, window) => { + if (window.scrollY === 0) { + window.scroll(0, scrollY); + } + }; + } + + // Clean up old pending frames and set current one as new one + const previousPendingFrame = getPendingFrame(); + if (previousPendingFrame) { + previousPendingFrame.setAttribute('id', ''); + document.body.removeChild(previousPendingFrame); + } + if (!wasFirstLoad) { + pendingMessages = []; + } + + const newFrame = document.createElement('iframe'); + newFrame.setAttribute('id', 'pending-frame'); + newFrame.setAttribute('frameborder', '0'); + + const sandboxRules = new Set(['allow-same-origin', 'allow-pointer-lock']); + if (options.allowScripts) { + sandboxRules.add('allow-scripts'); + sandboxRules.add('allow-downloads'); + } + if (options.allowForms) { + sandboxRules.add('allow-forms'); + } + newFrame.setAttribute('sandbox', Array.from(sandboxRules).join(' ')); + if (!isFirefox) { + newFrame.setAttribute('allow', options.allowScripts ? 'clipboard-read; clipboard-write;' : ''); + } + // We should just be able to use srcdoc, but I wasn't + // seeing the service worker applying properly. + // Fake load an empty on the correct origin and then write real html + // into it to get around this. + newFrame.src = `./fake.html?id=${ID}`; + + newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; + document.body.appendChild(newFrame); + + /** + * @param {Document} contentDocument + */ + function onFrameLoaded(contentDocument) { + // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=978325 + setTimeout(() => { + contentDocument.open(); + contentDocument.write(newDocument); + contentDocument.close(); + hookupOnLoadHandlers(newFrame); + + if (initialStyleVersion !== styleVersion) { + applyStyles(contentDocument, contentDocument.body); + } + }, 0); + } + + if (!options.allowScripts && isSafari) { + // On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired: https://bugs.webkit.org/show_bug.cgi?id=33604 + // Use polling instead. + const interval = setInterval(() => { + // If the frame is no longer mounted, loading has stopped + if (!newFrame.parentElement) { + clearInterval(interval); + return; + } + + const contentDocument = assertIsDefined(newFrame.contentDocument); + if (contentDocument.location.pathname.endsWith('/fake.html') && contentDocument.readyState !== 'loading') { + clearInterval(interval); + onFrameLoaded(contentDocument); + } + }, 10); + } else { + assertIsDefined(newFrame.contentWindow).addEventListener('DOMContentLoaded', e => { + const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined; + onFrameLoaded(assertIsDefined(contentDocument)); + }); + } + + /** + * @param {Document} contentDocument + * @param {Window} contentWindow + */ + const onLoad = (contentDocument, contentWindow) => { + if (contentDocument && contentDocument.body) { + // Workaround for https://github.com/microsoft/vscode/issues/12865 + // check new scrollY and reset if necessary + setInitialScrollPosition(contentDocument.body, contentWindow); + } + + const newFrame = getPendingFrame(); + if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) { + const wasFocused = document.hasFocus(); + const oldActiveFrame = getActiveFrame(); + if (oldActiveFrame) { + document.body.removeChild(oldActiveFrame); + } + // Styles may have changed since we created the element. Make sure we re-style + if (initialStyleVersion !== styleVersion) { + applyStyles(newFrame.contentDocument, newFrame.contentDocument.body); + } + newFrame.setAttribute('id', 'active-frame'); + newFrame.style.visibility = 'visible'; + + contentWindow.addEventListener('scroll', handleInnerScroll); + contentWindow.addEventListener('wheel', handleWheel); + + if (wasFocused) { + contentWindow.focus(); + } + + pendingMessages.forEach((message) => { + contentWindow.postMessage(message.message, window.origin, message.transfer); + }); + pendingMessages = []; + } + }; + + /** + * @param {HTMLIFrameElement} newFrame + */ + function hookupOnLoadHandlers(newFrame) { + clearTimeout(loadTimeout); + loadTimeout = undefined; + loadTimeout = setTimeout(() => { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(assertIsDefined(newFrame.contentDocument), assertIsDefined(newFrame.contentWindow)); + }, 200); + + const contentWindow = assertIsDefined(newFrame.contentWindow); + + contentWindow.addEventListener('load', function (e) { + const contentDocument = /** @type {Document} */ (e.target); + + if (loadTimeout) { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(contentDocument, this); + } + }); + + // Bubble out various events + contentWindow.addEventListener('click', handleInnerClick); + contentWindow.addEventListener('auxclick', handleAuxClick); + contentWindow.addEventListener('keydown', handleInnerKeydown); + contentWindow.addEventListener('keyup', handleInnerUp); + contentWindow.addEventListener('contextmenu', e => { + if (e.defaultPrevented) { + // Extension code has already handled this event + return; + } + + e.preventDefault(); + hostMessaging.postMessage('did-context-menu', { + clientX: e.clientX, + clientY: e.clientY, + }); + }); + + contentWindow.addEventListener('dragenter', handleInnerDragStartEvent); + contentWindow.addEventListener('dragover', handleInnerDragStartEvent); + + unloadMonitor.onIframeLoaded(newFrame); + } + }); + + // Forward message to the embedded iframe + hostMessaging.onMessage('message', (_event, /** @type {{message: any, transfer?: ArrayBuffer[] }} */ data) => { + const pending = getPendingFrame(); + if (!pending) { + const target = getActiveFrame(); + if (target) { + assertIsDefined(target.contentWindow).postMessage(data.message, window.origin, data.transfer); + return; + } + } + pendingMessages.push(data); + }); + + hostMessaging.onMessage('initial-scroll-position', (_event, progress) => { + initData.initialScrollProgress = progress; + }); + + hostMessaging.onMessage('execCommand', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + assertIsDefined(target.contentDocument).execCommand(data); + }); + + /** @type {string | undefined} */ + let lastFindValue = undefined; + + hostMessaging.onMessage('find', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + + if (!data.previous && lastFindValue !== data.value) { + // Reset selection so we start search at the head of the last search + const selection = target.contentWindow.getSelection(); + selection.collapse(selection.anchorNode); + } + lastFindValue = data.value; + + const didFind = (/** @type {any} */ (target.contentWindow)).find( + data.value, + /* caseSensitive*/ false, + /* backwards*/ data.previous, + /* wrapAround*/ true, + /* wholeWord */ false, + /* searchInFrames*/ false, + false); + hostMessaging.postMessage('did-find', didFind); + }); + + hostMessaging.onMessage('find-stop', (_event, data) => { + const target = getActiveFrame(); + if (!target) { + return; + } + + lastFindValue = undefined; + + if (!data.clearSelection) { + const selection = target.contentWindow.getSelection(); + for (let i = 0; i < selection.rangeCount; i++) { + selection.removeRange(selection.getRangeAt(i)); + } + } + }); + + trackFocus({ + onFocus: () => hostMessaging.postMessage('did-focus'), + onBlur: () => hostMessaging.postMessage('did-blur') + }); + + (/** @type {any} */ (window))[vscodePostMessageFuncName] = (/** @type {string} */ command, /** @type {any} */ data) => { + switch (command) { + case 'onmessage': + case 'do-update-state': + hostMessaging.postMessage(command, data); + break; + } + }; + + // Also forward events before the contents of the webview have loaded + window.addEventListener('keydown', handleInnerKeydown); + window.addEventListener('dragenter', handleInnerDragStartEvent); + window.addEventListener('dragover', handleInnerDragStartEvent); + + hostMessaging.signalReady(); + }); + </script> </body> </html> diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js deleted file mode 100644 index d2c57f4aa10..00000000000 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ /dev/null @@ -1,1133 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -// @ts-check - -/// <reference lib="dom" /> - -const isSafari = ( - navigator.vendor && navigator.vendor.indexOf('Apple') > -1 && - navigator.userAgent && - navigator.userAgent.indexOf('CriOS') === -1 && - navigator.userAgent.indexOf('FxiOS') === -1 -); - -const isFirefox = ( - navigator.userAgent && - navigator.userAgent.indexOf('Firefox') >= 0 -); - -const searchParams = new URL(location.toString()).searchParams; -const ID = searchParams.get('id'); -const onElectron = searchParams.get('platform') === 'electron'; -const expectedWorkerVersion = parseInt(searchParams.get('swVersion')); - -/** - * Use polling to track focus of main webview and iframes within the webview - * - * @param {Object} handlers - * @param {() => void} handlers.onFocus - * @param {() => void} handlers.onBlur - */ -const trackFocus = ({ onFocus, onBlur }) => { - const interval = 250; - let isFocused = document.hasFocus(); - setInterval(() => { - const isCurrentlyFocused = document.hasFocus(); - if (isCurrentlyFocused === isFocused) { - return; - } - isFocused = isCurrentlyFocused; - if (isCurrentlyFocused) { - onFocus(); - } else { - onBlur(); - } - }, interval); -}; - -const getActiveFrame = () => { - return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('active-frame')); -}; - -const getPendingFrame = () => { - return /** @type {HTMLIFrameElement | undefined} */ (document.getElementById('pending-frame')); -}; - -/** - * @template T - * @param {T | undefined | null} obj - * @return {T} - */ -function assertIsDefined(obj) { - if (typeof obj === 'undefined' || obj === null) { - throw new Error('Found unexpected null'); - } - return obj; -} - -const vscodePostMessageFuncName = '__vscode_post_message__'; - -const defaultStyles = document.createElement('style'); -defaultStyles.id = '_defaultStyles'; -defaultStyles.textContent = ` - html { - scrollbar-color: var(--vscode-scrollbarSlider-background) var(--vscode-editor-background); - } - - body { - background-color: transparent; - color: var(--vscode-editor-foreground); - font-family: var(--vscode-font-family); - font-weight: var(--vscode-font-weight); - font-size: var(--vscode-font-size); - margin: 0; - padding: 0 20px; - } - - img { - max-width: 100%; - max-height: 100%; - } - - a, a code { - color: var(--vscode-textLink-foreground); - } - - a:hover { - color: var(--vscode-textLink-activeForeground); - } - - a:focus, - input:focus, - select:focus, - textarea:focus { - outline: 1px solid -webkit-focus-ring-color; - outline-offset: -1px; - } - - code { - color: var(--vscode-textPreformat-foreground); - } - - blockquote { - background: var(--vscode-textBlockQuote-background); - border-color: var(--vscode-textBlockQuote-border); - } - - kbd { - color: var(--vscode-editor-foreground); - border-radius: 3px; - vertical-align: middle; - padding: 1px 3px; - - background-color: hsla(0,0%,50%,.17); - border: 1px solid rgba(71,71,71,.4); - border-bottom-color: rgba(88,88,88,.4); - box-shadow: inset 0 -1px 0 rgba(88,88,88,.4); - } - .vscode-light kbd { - background-color: hsla(0,0%,87%,.5); - border: 1px solid hsla(0,0%,80%,.7); - border-bottom-color: hsla(0,0%,73%,.7); - box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7); - } - - ::-webkit-scrollbar { - width: 10px; - height: 10px; - } - - ::-webkit-scrollbar-corner { - background-color: var(--vscode-editor-background); - } - - ::-webkit-scrollbar-thumb { - background-color: var(--vscode-scrollbarSlider-background); - } - ::-webkit-scrollbar-thumb:hover { - background-color: var(--vscode-scrollbarSlider-hoverBackground); - } - ::-webkit-scrollbar-thumb:active { - background-color: var(--vscode-scrollbarSlider-activeBackground); - } - ::highlight(find-highlight) { - background-color: var(--vscode-editor-findMatchHighlightBackground); - } - ::highlight(current-find-highlight) { - background-color: var(--vscode-editor-findMatchBackground); - }`; - -/** - * @param {boolean} allowMultipleAPIAcquire - * @param {*} [state] - * @return {string} - */ -function getVsCodeApiScript(allowMultipleAPIAcquire, state) { - const encodedState = state ? encodeURIComponent(state) : undefined; - return /* js */` - globalThis.acquireVsCodeApi = (function() { - const originalPostMessage = window.parent['${vscodePostMessageFuncName}'].bind(window.parent); - const doPostMessage = (channel, data, transfer) => { - originalPostMessage(channel, data, transfer); - }; - - let acquired = false; - - let state = ${state ? `JSON.parse(decodeURIComponent("${encodedState}"))` : undefined}; - - return () => { - if (acquired && !${allowMultipleAPIAcquire}) { - throw new Error('An instance of the VS Code API has already been acquired'); - } - acquired = true; - return Object.freeze({ - postMessage: function(message, transfer) { - doPostMessage('onmessage', { message, transfer }, transfer); - }, - setState: function(newState) { - state = newState; - doPostMessage('do-update-state', JSON.stringify(newState)); - return newState; - }, - getState: function() { - return state; - } - }); - }; - })(); - delete window.parent; - delete window.top; - delete window.frameElement; - `; -} - -/** @type {Promise<void>} */ -const workerReady = new Promise((resolve, reject) => { - if (!areServiceWorkersEnabled()) { - return reject(new Error('Service Workers are not enabled. Webviews will not work. Try disabling private/incognito mode.')); - } - - const swPath = `service-worker.js?v=${expectedWorkerVersion}&vscode-resource-base-authority=${searchParams.get('vscode-resource-base-authority')}&remoteAuthority=${searchParams.get('remoteAuthority') ?? ''}`; - navigator.serviceWorker.register(swPath) - .then(() => navigator.serviceWorker.ready) - .then(async registration => { - /** - * @param {MessageEvent} event - */ - const versionHandler = async (event) => { - if (event.data.channel !== 'version') { - return; - } - - navigator.serviceWorker.removeEventListener('message', versionHandler); - if (event.data.version === expectedWorkerVersion) { - return resolve(); - } else { - console.log(`Found unexpected service worker version. Found: ${event.data.version}. Expected: ${expectedWorkerVersion}`); - console.log(`Attempting to reload service worker`); - - // If we have the wrong version, try once (and only once) to unregister and re-register - // Note that `.update` doesn't seem to work desktop electron at the moment so we use - // `unregister` and `register` here. - return registration.unregister() - .then(() => navigator.serviceWorker.register(swPath)) - .then(() => navigator.serviceWorker.ready) - .finally(() => { resolve(); }); - } - }; - navigator.serviceWorker.addEventListener('message', versionHandler); - - const postVersionMessage = (/** @type {ServiceWorker} */ controller) => { - controller.postMessage({ channel: 'version' }); - }; - - // At this point, either the service worker is ready and - // became our controller, or we need to wait for it. - // Note that navigator.serviceWorker.controller could be a - // controller from a previously loaded service worker. - const currentController = navigator.serviceWorker.controller; - if (currentController?.scriptURL.endsWith(swPath)) { - // service worker already loaded & ready to receive messages - postVersionMessage(currentController); - } else { - // either there's no controlling service worker, or it's an old one: - // wait for it to change before posting the message - const onControllerChange = () => { - navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange); - postVersionMessage(navigator.serviceWorker.controller); - }; - navigator.serviceWorker.addEventListener('controllerchange', onControllerChange); - } - }).catch(error => { - reject(new Error(`Could not register service workers: ${error}.`)); - }); -}); - -const hostMessaging = new class HostMessaging { - - constructor() { - this.channel = new MessageChannel(); - - /** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */ - this.handlers = new Map(); - - this.channel.port1.onmessage = (e) => { - const channel = e.data.channel; - const handlers = this.handlers.get(channel); - if (handlers) { - for (const handler of handlers) { - handler(e, e.data.args); - } - } else { - console.log('no handler for ', e); - } - }; - } - - /** - * @param {string} channel - * @param {any} data - * @param {any} [transfer] - */ - postMessage(channel, data, transfer) { - this.channel.port1.postMessage({ channel, data }, transfer); - } - - /** - * @param {string} channel - * @param {(event: MessageEvent, data: any) => void} handler - */ - onMessage(channel, handler) { - let handlers = this.handlers.get(channel); - if (!handlers) { - handlers = []; - this.handlers.set(channel, handlers); - } - handlers.push(handler); - } - - async signalReady() { - const start = (/** @type {string} */ parentOrigin) => { - window.parent.postMessage({ target: ID, channel: 'webview-ready', data: {} }, parentOrigin, [this.channel.port2]); - }; - - const parentOrigin = searchParams.get('parentOrigin'); - const id = searchParams.get('id'); - - const hostname = location.hostname; - - if (!crypto.subtle) { - // cannot validate, not running in a secure context - throw new Error(`Cannot validate in current context!`); - } - - // Here the `parentOriginHash()` function from `src/vs/workbench/common/webview.ts` is inlined - // compute a sha-256 composed of `parentOrigin` and `salt` converted to base 32 - let parentOriginHash; - try { - const strData = JSON.stringify({ parentOrigin, salt: id }); - const encoder = new TextEncoder(); - const arrData = encoder.encode(strData); - const hash = await crypto.subtle.digest('sha-256', arrData); - const hashArray = Array.from(new Uint8Array(hash)); - const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); - // sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32 - parentOriginHash = BigInt(`0x${hashHex}`).toString(32).padStart(52, '0'); - } catch (err) { - throw err instanceof Error ? err : new Error(String(err)); - } - - if (hostname === parentOriginHash || hostname.startsWith(parentOriginHash + '.')) { - // validation succeeded! - return start(parentOrigin); - } - - throw new Error(`Expected '${parentOriginHash}' as hostname or subdomain!`); - } -}(); - -const unloadMonitor = new class { - - constructor() { - this.confirmBeforeClose = 'keyboardOnly'; - this.isModifierKeyDown = false; - - hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => { - this.confirmBeforeClose = data; - }); - - hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => { - this.confirmBeforeClose = data.confirmBeforeClose; - }); - - window.addEventListener('beforeunload', (event) => { - if (onElectron) { - return; - } - - switch (this.confirmBeforeClose) { - case 'always': { - event.preventDefault(); - event.returnValue = ''; - return ''; - } - case 'never': { - break; - } - case 'keyboardOnly': - default: { - if (this.isModifierKeyDown) { - event.preventDefault(); - event.returnValue = ''; - return ''; - } - break; - } - } - }); - } - - onIframeLoaded(/** @type {HTMLIFrameElement} */ frame) { - frame.contentWindow.addEventListener('keydown', e => { - this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey; - }); - - frame.contentWindow.addEventListener('keyup', () => { - this.isModifierKeyDown = false; - }); - } -}; - -// state -let firstLoad = true; -/** @type {any} */ -let loadTimeout; -let styleVersion = 0; - -/** @type {Array<{ readonly message: any, transfer?: ArrayBuffer[] }>} */ -let pendingMessages = []; - -const initData = { - /** @type {number | undefined} */ - initialScrollProgress: undefined, - - /** @type {{ [key: string]: string } | undefined} */ - styles: undefined, - - /** @type {string | undefined} */ - activeTheme: undefined, - - /** @type {string | undefined} */ - themeName: undefined, - - /** @type {boolean} */ - screenReader: false, - - /** @type {boolean} */ - reduceMotion: false, -}; - -hostMessaging.onMessage('did-load-resource', (_event, data) => { - navigator.serviceWorker.ready.then(registration => { - assertIsDefined(registration.active).postMessage({ channel: 'did-load-resource', data }, data.data?.buffer ? [data.data.buffer] : []); - }); -}); - -hostMessaging.onMessage('did-load-localhost', (_event, data) => { - navigator.serviceWorker.ready.then(registration => { - assertIsDefined(registration.active).postMessage({ channel: 'did-load-localhost', data }); - }); -}); - -navigator.serviceWorker.addEventListener('message', event => { - switch (event.data.channel) { - case 'load-resource': - case 'load-localhost': - hostMessaging.postMessage(event.data.channel, event.data); - return; - } -}); -/** - * @param {HTMLDocument?} document - * @param {HTMLElement?} body - */ -const applyStyles = (document, body) => { - if (!document) { - return; - } - - if (body) { - body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast', 'vscode-reduce-motion', 'vscode-using-screen-reader'); - if (initData.activeTheme) { - body.classList.add(initData.activeTheme); - } - - if (initData.reduceMotion) { - body.classList.add('vscode-reduce-motion'); - } - - if (initData.screenReader) { - body.classList.add('vscode-using-screen-reader'); - } - - body.dataset.vscodeThemeKind = initData.activeTheme; - body.dataset.vscodeThemeName = initData.themeName || ''; - } - - if (initData.styles) { - const documentStyle = document.documentElement.style; - - // Remove stale properties - for (let i = documentStyle.length - 1; i >= 0; i--) { - const property = documentStyle[i]; - - // Don't remove properties that the webview might have added separately - if (property && property.startsWith('--vscode-')) { - documentStyle.removeProperty(property); - } - } - - // Re-add new properties - for (const variable of Object.keys(initData.styles)) { - documentStyle.setProperty(`--${variable}`, initData.styles[variable]); - } - } -}; - -/** - * @param {MouseEvent} event - */ -const handleInnerClick = (event) => { - if (!event?.view?.document) { - return; - } - - const baseElement = event.view.document.querySelector('base'); - - for (const pathElement of event.composedPath()) { - /** @type {any} */ - const node = pathElement; - if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { - if (node.getAttribute('href') === '#') { - event.view.scrollTo(0, 0); - } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href === baseElement.href + node.hash))) { - const fragment = node.hash.slice(1); - const scrollTarget = event.view.document.getElementById(fragment) ?? event.view.document.getElementById(decodeURIComponent(fragment)); - scrollTarget?.scrollIntoView(); - } else { - hostMessaging.postMessage('did-click-link', node.href.baseVal || node.href); - } - event.preventDefault(); - return; - } - } -}; - -/** - * @param {MouseEvent} event - */ -const handleAuxClick = (event) => { - // Prevent middle clicks opening a broken link in the browser - if (!event?.view?.document) { - return; - } - - if (event.button === 1) { - for (const pathElement of event.composedPath()) { - /** @type {any} */ - const node = pathElement; - if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { - event.preventDefault(); - return; - } - } - } -}; - -/** - * @param {KeyboardEvent} e - */ -const handleInnerKeydown = (e) => { - // If the keypress would trigger a browser event, such as copy or paste, - // make sure we block the browser from dispatching it. Instead VS Code - // handles these events and will dispatch a copy/paste back to the webview - // if needed - if (isUndoRedo(e) || isPrint(e) || isFindEvent(e)) { - e.preventDefault(); - } else if (isCopyPasteOrCut(e)) { - if (onElectron) { - e.preventDefault(); - } else { - return; // let the browser handle this - } - } - - hostMessaging.postMessage('did-keydown', { - key: e.key, - keyCode: e.keyCode, - code: e.code, - shiftKey: e.shiftKey, - altKey: e.altKey, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - repeat: e.repeat - }); -}; -/** - * @param {KeyboardEvent} e - */ -const handleInnerUp = (e) => { - hostMessaging.postMessage('did-keyup', { - key: e.key, - keyCode: e.keyCode, - code: e.code, - shiftKey: e.shiftKey, - altKey: e.altKey, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - repeat: e.repeat - }); -}; - -/** - * @param {KeyboardEvent} e - * @return {boolean} - */ -function isCopyPasteOrCut(e) { - const hasMeta = e.ctrlKey || e.metaKey; - const shiftInsert = e.shiftKey && e.key.toLowerCase() === 'insert'; - return (hasMeta && ['c', 'v', 'x'].includes(e.key.toLowerCase())) || shiftInsert; -} - -/** - * @param {KeyboardEvent} e - * @return {boolean} - */ -function isUndoRedo(e) { - const hasMeta = e.ctrlKey || e.metaKey; - return hasMeta && ['z', 'y'].includes(e.key.toLowerCase()); -} - -/** - * @param {KeyboardEvent} e - * @return {boolean} - */ -function isPrint(e) { - const hasMeta = e.ctrlKey || e.metaKey; - return hasMeta && e.key.toLowerCase() === 'p'; -} - -/** - * @param {KeyboardEvent} e - * @return {boolean} - */ -function isFindEvent(e) { - const hasMeta = e.ctrlKey || e.metaKey; - return hasMeta && e.key.toLowerCase() === 'f'; -} - -let isHandlingScroll = false; - -/** - * @param {WheelEvent} event - */ -const handleWheel = (event) => { - if (isHandlingScroll) { - return; - } - - hostMessaging.postMessage('did-scroll-wheel', { - deltaMode: event.deltaMode, - deltaX: event.deltaX, - deltaY: event.deltaY, - deltaZ: event.deltaZ, - detail: event.detail, - type: event.type - }); -}; - -/** - * @param {Event} event - */ -const handleInnerScroll = (event) => { - if (isHandlingScroll) { - return; - } - - const target = /** @type {HTMLDocument | null} */ (event.target); - const currentTarget = /** @type {Window | null} */ (event.currentTarget); - if (!currentTarget || !target?.body) { - return; - } - - const progress = currentTarget.scrollY / target.body.clientHeight; - if (isNaN(progress)) { - return; - } - - isHandlingScroll = true; - window.requestAnimationFrame(() => { - try { - hostMessaging.postMessage('did-scroll', progress); - } catch (e) { - // noop - } - isHandlingScroll = false; - }); -}; - -function handleInnerDragStartEvent(/** @type {DragEvent} */ e) { - if (e.defaultPrevented) { - // Extension code has already handled this event - return; - } - - if (!e.dataTransfer || e.shiftKey) { - return; - } - - // Only handle drags from outside editor for now - if (e.dataTransfer.items.length && Array.prototype.every.call(e.dataTransfer.items, item => item.kind === 'file')) { - hostMessaging.postMessage('drag-start'); - } -} - -/** - * @param {() => void} callback - */ -function onDomReady(callback) { - if (document.readyState === 'interactive' || document.readyState === 'complete') { - callback(); - } else { - document.addEventListener('DOMContentLoaded', callback); - } -} - -function areServiceWorkersEnabled() { - try { - return !!navigator.serviceWorker; - } catch (e) { - return false; - } -} - -/** - * @typedef {{ - * contents: string; - * options: { - * readonly allowScripts: boolean; - * readonly allowForms: boolean; - * readonly allowMultipleAPIAcquire: boolean; - * } - * state: any; - * cspSource: string; - * }} ContentUpdateData - */ - -/** - * @param {ContentUpdateData} data - * @return {string} - */ -function toContentHtml(data) { - const options = data.options; - const text = data.contents; - const newDocument = new DOMParser().parseFromString(text, 'text/html'); - - newDocument.querySelectorAll('a').forEach(a => { - if (!a.title) { - const href = a.getAttribute('href'); - if (typeof href === 'string') { - a.title = href; - } - } - }); - - // Set default aria role - if (!newDocument.body.hasAttribute('role')) { - newDocument.body.setAttribute('role', 'document'); - } - - // Inject default script - if (options.allowScripts) { - const defaultScript = newDocument.createElement('script'); - defaultScript.id = '_vscodeApiScript'; - defaultScript.textContent = getVsCodeApiScript(options.allowMultipleAPIAcquire, data.state); - newDocument.head.prepend(defaultScript); - } - - // Inject default styles - newDocument.head.prepend(defaultStyles.cloneNode(true)); - - applyStyles(newDocument, newDocument.body); - - // Strip out unsupported http-equiv tags - for (const metaElement of Array.from(newDocument.querySelectorAll('meta'))) { - const httpEquiv = metaElement.getAttribute('http-equiv'); - if (httpEquiv && !/^(content-security-policy|default-style|content-type)$/i.test(httpEquiv)) { - console.warn(`Removing unsupported meta http-equiv: ${httpEquiv}`); - metaElement.remove(); - } - } - - // Check for CSP - const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]'); - if (!csp) { - hostMessaging.postMessage('no-csp-found'); - } else { - try { - // Attempt to rewrite CSPs that hardcode old-style resource endpoint - const cspContent = csp.getAttribute('content'); - if (cspContent) { - const newCsp = cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, data.cspSource); - csp.setAttribute('content', newCsp); - } - } catch (e) { - console.error(`Could not rewrite csp: ${e}`); - } - } - - // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off - // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden - return '<!DOCTYPE html>\n' + newDocument.documentElement.outerHTML; -} - -onDomReady(() => { - if (!document.body) { - return; - } - - hostMessaging.onMessage('styles', (_event, data) => { - ++styleVersion; - - initData.styles = data.styles; - initData.activeTheme = data.activeTheme; - initData.themeName = data.themeName; - initData.reduceMotion = data.reduceMotion; - initData.screenReader = data.screenReader; - - const target = getActiveFrame(); - if (!target) { - return; - } - - if (target.contentDocument) { - applyStyles(target.contentDocument, target.contentDocument.body); - } - }); - - // propagate focus - hostMessaging.onMessage('focus', () => { - const activeFrame = getActiveFrame(); - if (!activeFrame || !activeFrame.contentWindow) { - // Focus the top level webview instead - window.focus(); - return; - } - - if (document.activeElement === activeFrame) { - // We are already focused on the iframe (or one of its children) so no need - // to refocus. - return; - } - - activeFrame.contentWindow.focus(); - }); - - // update iframe-contents - let updateId = 0; - hostMessaging.onMessage('content', async (_event, /** @type {ContentUpdateData} */ data) => { - const currentUpdateId = ++updateId; - try { - await workerReady; - } catch (e) { - console.error(`Webview fatal error: ${e}`); - hostMessaging.postMessage('fatal-error', { message: e + '' }); - return; - } - - if (currentUpdateId !== updateId) { - return; - } - - const options = data.options; - const newDocument = toContentHtml(data); - - const initialStyleVersion = styleVersion; - - const frame = getActiveFrame(); - const wasFirstLoad = firstLoad; - // keep current scrollY around and use later - /** @type {(body: HTMLElement, window: Window) => void} */ - let setInitialScrollPosition; - if (firstLoad) { - firstLoad = false; - setInitialScrollPosition = (body, window) => { - if (typeof initData.initialScrollProgress === 'number' && !isNaN(initData.initialScrollProgress)) { - if (window.scrollY === 0) { - window.scroll(0, body.clientHeight * initData.initialScrollProgress); - } - } - }; - } else { - const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? assertIsDefined(frame.contentWindow).scrollY : 0; - setInitialScrollPosition = (body, window) => { - if (window.scrollY === 0) { - window.scroll(0, scrollY); - } - }; - } - - // Clean up old pending frames and set current one as new one - const previousPendingFrame = getPendingFrame(); - if (previousPendingFrame) { - previousPendingFrame.setAttribute('id', ''); - document.body.removeChild(previousPendingFrame); - } - if (!wasFirstLoad) { - pendingMessages = []; - } - - const newFrame = document.createElement('iframe'); - newFrame.setAttribute('id', 'pending-frame'); - newFrame.setAttribute('frameborder', '0'); - - const sandboxRules = new Set(['allow-same-origin', 'allow-pointer-lock']); - if (options.allowScripts) { - sandboxRules.add('allow-scripts'); - sandboxRules.add('allow-downloads'); - } - if (options.allowForms) { - sandboxRules.add('allow-forms'); - } - newFrame.setAttribute('sandbox', Array.from(sandboxRules).join(' ')); - if (!isFirefox) { - newFrame.setAttribute('allow', options.allowScripts ? 'clipboard-read; clipboard-write;' : ''); - } - // We should just be able to use srcdoc, but I wasn't - // seeing the service worker applying properly. - // Fake load an empty on the correct origin and then write real html - // into it to get around this. - newFrame.src = `./fake.html?id=${ID}`; - - newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; - document.body.appendChild(newFrame); - - /** - * @param {Document} contentDocument - */ - function onFrameLoaded(contentDocument) { - // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=978325 - setTimeout(() => { - contentDocument.open(); - contentDocument.write(newDocument); - contentDocument.close(); - hookupOnLoadHandlers(newFrame); - - if (initialStyleVersion !== styleVersion) { - applyStyles(contentDocument, contentDocument.body); - } - }, 0); - } - - if (!options.allowScripts && isSafari) { - // On Safari for iframes with scripts disabled, the `DOMContentLoaded` never seems to be fired: https://bugs.webkit.org/show_bug.cgi?id=33604 - // Use polling instead. - const interval = setInterval(() => { - // If the frame is no longer mounted, loading has stopped - if (!newFrame.parentElement) { - clearInterval(interval); - return; - } - - const contentDocument = assertIsDefined(newFrame.contentDocument); - if (contentDocument.location.pathname.endsWith('/fake.html') && contentDocument.readyState !== 'loading') { - clearInterval(interval); - onFrameLoaded(contentDocument); - } - }, 10); - } else { - assertIsDefined(newFrame.contentWindow).addEventListener('DOMContentLoaded', e => { - const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined; - onFrameLoaded(assertIsDefined(contentDocument)); - }); - } - - /** - * @param {Document} contentDocument - * @param {Window} contentWindow - */ - const onLoad = (contentDocument, contentWindow) => { - if (contentDocument && contentDocument.body) { - // Workaround for https://github.com/microsoft/vscode/issues/12865 - // check new scrollY and reset if necessary - setInitialScrollPosition(contentDocument.body, contentWindow); - } - - const newFrame = getPendingFrame(); - if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) { - const wasFocused = document.hasFocus(); - const oldActiveFrame = getActiveFrame(); - if (oldActiveFrame) { - document.body.removeChild(oldActiveFrame); - } - // Styles may have changed since we created the element. Make sure we re-style - if (initialStyleVersion !== styleVersion) { - applyStyles(newFrame.contentDocument, newFrame.contentDocument.body); - } - newFrame.setAttribute('id', 'active-frame'); - newFrame.style.visibility = 'visible'; - - contentWindow.addEventListener('scroll', handleInnerScroll); - contentWindow.addEventListener('wheel', handleWheel); - - if (wasFocused) { - contentWindow.focus(); - } - - pendingMessages.forEach((message) => { - contentWindow.postMessage(message.message, window.origin, message.transfer); - }); - pendingMessages = []; - } - }; - - /** - * @param {HTMLIFrameElement} newFrame - */ - function hookupOnLoadHandlers(newFrame) { - clearTimeout(loadTimeout); - loadTimeout = undefined; - loadTimeout = setTimeout(() => { - clearTimeout(loadTimeout); - loadTimeout = undefined; - onLoad(assertIsDefined(newFrame.contentDocument), assertIsDefined(newFrame.contentWindow)); - }, 200); - - const contentWindow = assertIsDefined(newFrame.contentWindow); - - contentWindow.addEventListener('load', function (e) { - const contentDocument = /** @type {Document} */ (e.target); - - if (loadTimeout) { - clearTimeout(loadTimeout); - loadTimeout = undefined; - onLoad(contentDocument, this); - } - }); - - // Bubble out various events - contentWindow.addEventListener('click', handleInnerClick); - contentWindow.addEventListener('auxclick', handleAuxClick); - contentWindow.addEventListener('keydown', handleInnerKeydown); - contentWindow.addEventListener('keyup', handleInnerUp); - contentWindow.addEventListener('contextmenu', e => { - if (e.defaultPrevented) { - // Extension code has already handled this event - return; - } - - e.preventDefault(); - hostMessaging.postMessage('did-context-menu', { - clientX: e.clientX, - clientY: e.clientY, - }); - }); - - contentWindow.addEventListener('dragenter', handleInnerDragStartEvent); - contentWindow.addEventListener('dragover', handleInnerDragStartEvent); - - unloadMonitor.onIframeLoaded(newFrame); - } - }); - - // Forward message to the embedded iframe - hostMessaging.onMessage('message', (_event, /** @type {{message: any, transfer?: ArrayBuffer[] }} */ data) => { - const pending = getPendingFrame(); - if (!pending) { - const target = getActiveFrame(); - if (target) { - assertIsDefined(target.contentWindow).postMessage(data.message, window.origin, data.transfer); - return; - } - } - pendingMessages.push(data); - }); - - hostMessaging.onMessage('initial-scroll-position', (_event, progress) => { - initData.initialScrollProgress = progress; - }); - - hostMessaging.onMessage('execCommand', (_event, data) => { - const target = getActiveFrame(); - if (!target) { - return; - } - assertIsDefined(target.contentDocument).execCommand(data); - }); - - /** @type {string | undefined} */ - let lastFindValue = undefined; - - hostMessaging.onMessage('find', (_event, data) => { - const target = getActiveFrame(); - if (!target) { - return; - } - - if (!data.previous && lastFindValue !== data.value) { - // Reset selection so we start search at the head of the last search - const selection = target.contentWindow.getSelection(); - selection.collapse(selection.anchorNode); - } - lastFindValue = data.value; - - const didFind = (/** @type {any} */ (target.contentWindow)).find( - data.value, - /* caseSensitive*/ false, - /* backwards*/ data.previous, - /* wrapAround*/ true, - /* wholeWord */ false, - /* searchInFrames*/ false, - false); - hostMessaging.postMessage('did-find', didFind); - }); - - hostMessaging.onMessage('find-stop', (_event, data) => { - const target = getActiveFrame(); - if (!target) { - return; - } - - lastFindValue = undefined; - - if (!data.clearSelection) { - const selection = target.contentWindow.getSelection(); - for (let i = 0; i < selection.rangeCount; i++) { - selection.removeRange(selection.getRangeAt(i)); - } - } - }); - - trackFocus({ - onFocus: () => hostMessaging.postMessage('did-focus'), - onBlur: () => hostMessaging.postMessage('did-blur') - }); - - (/** @type {any} */ (window))[vscodePostMessageFuncName] = (/** @type {string} */ command, /** @type {any} */ data) => { - switch (command) { - case 'onmessage': - case 'do-update-state': - hostMessaging.postMessage(command, data); - break; - } - }; - - // Also forward events before the contents of the webview have loaded - window.addEventListener('keydown', handleInnerKeydown); - window.addEventListener('dragenter', handleInnerDragStartEvent); - window.addEventListener('dragover', handleInnerDragStartEvent); - - hostMessaging.signalReady(); -}); diff --git a/src/vs/workbench/contrib/webview/browser/resourceLoading.ts b/src/vs/workbench/contrib/webview/browser/resourceLoading.ts index 9d717dd0c1c..cdff87cccd0 100644 --- a/src/vs/workbench/contrib/webview/browser/resourceLoading.ts +++ b/src/vs/workbench/contrib/webview/browser/resourceLoading.ts @@ -65,7 +65,7 @@ export async function loadLocalResource( const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime try { - const result = await fileService.readFileStream(resourceToLoad, { etag: options.ifNoneMatch }); + const result = await fileService.readFileStream(resourceToLoad, { etag: options.ifNoneMatch }, token); return new WebviewResourceResponse.StreamSuccess(result.value, result.etag, result.mtime, mime); } catch (err) { if (err instanceof FileOperationError) { diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index 3054fdda9fb..e9e90223d4e 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -14,6 +14,7 @@ import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IWebviewPortMapping } from 'vs/platform/webview/common/webviewPortMapping'; +import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; /** * Set when the find widget in a webview in a webview is visible. @@ -53,12 +54,7 @@ export interface IWebviewService { /** * Create a basic webview dom element. */ - createWebviewElement( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, - ): IWebviewElement; + createWebviewElement(initInfo: WebviewInitInfo): IWebviewElement; /** * Create a lazily created webview element that is overlaid on top of another element. @@ -66,12 +62,7 @@ export interface IWebviewService { * Allows us to avoid re-parenting the webview (which destroys its contents) when * moving webview around the workbench. */ - createWebviewOverlay( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, - ): IOverlayWebview; + createWebviewOverlay(initInfo: WebviewInitInfo): IOverlayWebview; } export const enum WebviewContentPurpose { @@ -160,8 +151,16 @@ export interface WebviewMessageReceivedEvent { export interface IWebview extends IDisposable { + /** + * External identifier of this webview. + */ readonly id: string; + /** + * The origin this webview itself is loaded from. May not be unique + */ + readonly origin: string; + html: string; contentOptions: WebviewContentOptions; localResourcesRoot: readonly URI[]; diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 6cd87f63f28..77aaf6683f9 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -100,11 +100,34 @@ namespace WebviewState { export type State = typeof Ready | Initializing; } +export interface WebviewInitInfo { + readonly id: string; + readonly origin?: string; + + readonly options: WebviewOptions; + readonly contentOptions: WebviewContentOptions; + + readonly extension: WebviewExtensionDescription | undefined; +} + + export class WebviewElement extends Disposable implements IWebview, WebviewFindDelegate { + /** + * External identifier of this webview. + */ public readonly id: string; + /** + * The origin this webview itself is loaded from. May not be unique + */ + public readonly origin: string; + + /** + * Unique internal identifier of this webview's iframe element. + */ private readonly iframeId: string; + private readonly encodedWebviewOriginPromise: Promise<string>; private encodedWebviewOrigin: string | undefined; @@ -153,11 +176,12 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD private _disposed = false; + + public extension: WebviewExtensionDescription | undefined; + private readonly options: WebviewOptions; + constructor( - id: string, - private readonly options: WebviewOptions, - contentOptions: WebviewContentOptions, - public extension: WebviewExtensionDescription | undefined, + initInfo: WebviewInitInfo, protected readonly webviewThemeDataProvider: WebviewThemeDataProvider, @IConfigurationService configurationService: IConfigurationService, @IContextMenuService contextMenuService: IContextMenuService, @@ -174,13 +198,18 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD ) { super(); - this.id = id; + this.id = initInfo.id; this.iframeId = generateUuid(); - this.encodedWebviewOriginPromise = parentOriginHash(window.origin, this.iframeId).then(id => this.encodedWebviewOrigin = id); + this.origin = initInfo.origin ?? this.iframeId; + + this.encodedWebviewOriginPromise = parentOriginHash(window.origin, this.origin).then(id => this.encodedWebviewOrigin = id); + + this.options = initInfo.options; + this.extension = initInfo.extension; this.content = { html: '', - options: contentOptions, + options: initInfo.contentOptions, state: undefined }; @@ -190,7 +219,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this._tunnelService )); - this._element = this.createElement(options, contentOptions); + this._element = this.createElement(initInfo.options, initInfo.contentOptions); const subscription = this._register(addDisposableListener(window, 'message', (e: MessageEvent) => { @@ -355,14 +384,14 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this.startBlockingIframeDragEvents(); })); - if (options.enableFindWidget) { + if (initInfo.options.enableFindWidget) { this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); this.styledFindWidget(); } this.encodedWebviewOriginPromise.then(encodedWebviewOrigin => { if (!this._disposed) { - this.initElement(encodedWebviewOrigin, extension, options); + this.initElement(encodedWebviewOrigin, this.extension, this.options); } }); } @@ -463,6 +492,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD // The extensionId and purpose in the URL are used for filtering in js-debug: const params: { [key: string]: string } = { id: this.iframeId, + origin: this.origin, swVersion: String(this._expectedServiceWorkerVersion), extensionId: extension?.id.value ?? '', platform: this.platform, diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts index ef902f5d5e8..1ca0b71be52 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -7,8 +7,8 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; -import { IWebviewService, IWebview, WebviewContentOptions, IWebviewElement, WebviewExtensionDescription, WebviewOptions, IOverlayWebview } from 'vs/workbench/contrib/webview/browser/webview'; -import { WebviewElement } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { IOverlayWebview, IWebview, IWebviewElement, IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewElement, WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { OverlayWebview } from './overlayWebview'; export class WebviewService extends Disposable implements IWebviewService { @@ -43,24 +43,14 @@ export class WebviewService extends Disposable implements IWebviewService { private readonly _onDidChangeActiveWebview = this._register(new Emitter<IWebview | undefined>()); public readonly onDidChangeActiveWebview = this._onDidChangeActiveWebview.event; - createWebviewElement( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, - ): IWebviewElement { - const webview = this._instantiationService.createInstance(WebviewElement, id, options, contentOptions, extension, this._webviewThemeDataProvider); + createWebviewElement(initInfo: WebviewInitInfo): IWebviewElement { + const webview = this._instantiationService.createInstance(WebviewElement, initInfo, this._webviewThemeDataProvider); this.registerNewWebview(webview); return webview; } - createWebviewOverlay( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, - ): IOverlayWebview { - const webview = this._instantiationService.createInstance(OverlayWebview, id, options, contentOptions, extension); + createWebviewOverlay(initInfo: WebviewInitInfo): IOverlayWebview { + const webview = this._instantiationService.createInstance(OverlayWebview, initInfo); this.registerNewWebview(webview); return webview; } diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts index 5d77ddbc1d9..692eeb591ba 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/webviewElement.ts @@ -23,8 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITunnelService } from 'vs/platform/tunnel/common/tunnel'; import { FindInFrameOptions, IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; -import { WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; -import { WebviewElement, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { WebviewElement, WebviewInitInfo, WebviewMessageChannels } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { WindowIgnoreMenuShortcutsManager } from 'vs/workbench/contrib/webview/electron-sandbox/windowIgnoreMenuShortcutsManager'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -44,10 +43,7 @@ export class ElectronWebviewElement extends WebviewElement { protected override get platform() { return 'electron'; } constructor( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, + initInfo: WebviewInitInfo, webviewThemeDataProvider: WebviewThemeDataProvider, @IContextMenuService contextMenuService: IContextMenuService, @ITunnelService tunnelService: ITunnelService, @@ -64,7 +60,7 @@ export class ElectronWebviewElement extends WebviewElement { @IInstantiationService instantiationService: IInstantiationService, @IAccessibilityService accessibilityService: IAccessibilityService, ) { - super(id, options, contentOptions, extension, webviewThemeDataProvider, + super(initInfo, webviewThemeDataProvider, configurationService, contextMenuService, menuService, notificationService, environmentService, fileService, logService, remoteAuthorityResolverService, telemetryService, tunnelService, instantiationService, accessibilityService); @@ -80,7 +76,7 @@ export class ElectronWebviewElement extends WebviewElement { this._webviewKeyboardHandler.didBlur(); })); - if (options.enableFindWidget) { + if (initInfo.options.enableFindWidget) { this._register(this.onDidHtmlChange((newContent) => { if (this._findStarted && this._cachedHtmlContent !== newContent) { this.stopFind(false); diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts b/src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts index c63c3a65675..20ec351f827 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/webviewService.ts @@ -3,19 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWebviewElement, WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { IWebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { WebviewService } from 'vs/workbench/contrib/webview/browser/webviewService'; import { ElectronWebviewElement } from 'vs/workbench/contrib/webview/electron-sandbox/webviewElement'; export class ElectronWebviewService extends WebviewService { - override createWebviewElement( - id: string, - options: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, - ): IWebviewElement { - const webview = this._instantiationService.createInstance(ElectronWebviewElement, id, options, contentOptions, extension, this._webviewThemeDataProvider); + override createWebviewElement(initInfo: WebviewInitInfo): IWebviewElement { + const webview = this._instantiationService.createInstance(ElectronWebviewElement, initInfo, this._webviewThemeDataProvider); this.registerNewWebview(webview); return webview; } diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts index 2e49d30d1f4..ec4f4c9ef91 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputSerializer.ts @@ -21,6 +21,7 @@ interface SerializedIconPath { export interface SerializedWebview { readonly id: string; + readonly origin: string | undefined; readonly viewType: string; readonly title: string; readonly options: SerializedWebviewOptions; @@ -33,6 +34,7 @@ export interface SerializedWebview { export interface DeserializedWebview { readonly id: string; + readonly origin: string | undefined; readonly viewType: string; readonly title: string; readonly webviewOptions: WebviewOptions; @@ -74,14 +76,17 @@ export class WebviewEditorInputSerializer implements IEditorSerializer { ): WebviewInput { const data = this.fromJson(JSON.parse(serializedEditorInput)); return this._webviewWorkbenchService.reviveWebview({ - id: data.id, + webviewInitInfo: { + id: data.id, + origin: data.origin, + options: data.webviewOptions, + contentOptions: data.contentOptions, + extension: data.extension, + }, viewType: data.viewType, title: data.title, iconPath: data.iconPath, state: data.state, - webviewOptions: data.webviewOptions, - contentOptions: data.contentOptions, - extension: data.extension, group: data.group }); } @@ -100,6 +105,7 @@ export class WebviewEditorInputSerializer implements IEditorSerializer { protected toJson(input: WebviewInput): SerializedWebview { return { id: input.id, + origin: input.webview.origin, viewType: input.viewType, title: input.getName(), options: { ...input.webview.options, ...input.webview.contentOptions }, diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts index 45d5a74cdf6..94ede834b02 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts @@ -15,7 +15,8 @@ import { createDecorator, IInstantiationService } from 'vs/platform/instantiatio import { GroupIdentifier } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; -import { IOverlayWebview, IWebviewService, WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { IOverlayWebview, IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewInitInfo } from 'vs/workbench/contrib/webview/browser/webviewElement'; import { WebviewIconManager, WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; @@ -34,24 +35,18 @@ export interface IWebviewWorkbenchService { readonly iconManager: WebviewIconManager; createWebview( - id: string, + webviewInitInfo: WebviewInitInfo, viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - webviewOptions: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, ): WebviewInput; reviveWebview(options: { - id: string; + webviewInitInfo: WebviewInitInfo; viewType: string; title: string; iconPath: WebviewIcons | undefined; state: any; - webviewOptions: WebviewOptions; - contentOptions: WebviewContentOptions; - extension: WebviewExtensionDescription | undefined; group: number | undefined; }): WebviewInput; @@ -218,16 +213,13 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc } public createWebview( - id: string, + webviewInitInfo: WebviewInitInfo, viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - webviewOptions: WebviewOptions, - contentOptions: WebviewContentOptions, - extension: WebviewExtensionDescription | undefined, ): WebviewInput { - const webview = this._webviewService.createWebviewOverlay(id, webviewOptions, contentOptions, extension); - const webviewInput = this._instantiationService.createInstance(WebviewInput, id, viewType, title, webview, this.iconManager); + const webview = this._webviewService.createWebviewOverlay(webviewInitInfo); + const webviewInput = this._instantiationService.createInstance(WebviewInput, webviewInitInfo.id, viewType, title, webview, this.iconManager); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus, @@ -268,20 +260,17 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc } public reviveWebview(options: { - id: string; + webviewInitInfo: WebviewInitInfo; viewType: string; title: string; iconPath: WebviewIcons | undefined; state: any; - webviewOptions: WebviewOptions; - contentOptions: WebviewContentOptions; - extension: WebviewExtensionDescription | undefined; group: number | undefined; }): WebviewInput { - const webview = this._webviewService.createWebviewOverlay(options.id, options.webviewOptions, options.contentOptions, options.extension); + const webview = this._webviewService.createWebviewOverlay(options.webviewInitInfo); webview.state = options.state; - const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, options.id, options.viewType, options.title, webview); + const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, options.webviewInitInfo.id, options.viewType, options.title, webview); webviewInput.iconPath = options.iconPath; if (typeof options.group === 'number') { diff --git a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts index b09e7f519cf..124df428f3f 100644 --- a/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts +++ b/src/vs/workbench/contrib/webviewView/browser/webviewViewPane.ts @@ -167,12 +167,12 @@ export class WebviewViewPane extends ViewPane { this._activated = true; const webviewId = generateUuid(); - const webview = this.webviewService.createWebviewOverlay( - webviewId, - { purpose: WebviewContentPurpose.WebviewView }, - {}, - this.extensionId ? { id: this.extensionId } : undefined - ); + const webview = this.webviewService.createWebviewOverlay({ + id: webviewId, + options: { purpose: WebviewContentPurpose.WebviewView }, + contentOptions: {}, + extension: this.extensionId ? { id: this.extensionId } : undefined + }); webview.state = this.viewState[storageKeys.webviewState]; this._webview.value = webview; diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts index 977b500b88d..5fac78668bf 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts @@ -529,7 +529,7 @@ export class GettingStartedPage extends EditorPane { this.stepsContent.classList.remove('markdown'); const media = stepToExpand.media; - const webview = this.stepDisposables.add(this.webviewService.createWebviewElement(this.webviewID, {}, {}, undefined)); + const webview = this.stepDisposables.add(this.webviewService.createWebviewElement({ id: this.webviewID, options: {}, contentOptions: {}, extension: undefined })); webview.mountTo(this.stepMediaComponent); webview.html = await this.detailsRenderer.renderSVG(media.path); @@ -570,7 +570,7 @@ export class GettingStartedPage extends EditorPane { const media = stepToExpand.media; - const webview = this.stepDisposables.add(this.webviewService.createWebviewElement(this.webviewID, {}, { localResourceRoots: [media.root], allowScripts: true }, undefined)); + const webview = this.stepDisposables.add(this.webviewService.createWebviewElement({ id: this.webviewID, options: {}, contentOptions: { localResourceRoots: [media.root], allowScripts: true }, extension: undefined })); webview.mountTo(this.stepMediaComponent); const rawHTML = await this.detailsRenderer.renderMarkdown(media.path, media.base); diff --git a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts index b491ce7079e..b4c0e11cbeb 100644 --- a/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-sandbox/contextmenuService.ts @@ -105,15 +105,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService // In areas where zoom is applied to the element or its ancestors, we need to adjust accordingly // e.g. The title bar has counter zoom behavior meaning it applies the inverse of zoom level. // Window Zoom Level: 1.5, Title Bar Zoom: 1/1.5, Coordinate Multiplier: 1.5 * 1.0 / 1.5 = 1.0 - let testElement: HTMLElement | null = anchor; - do { - const elementZoomLevel = (dom.getComputedStyle(testElement) as any).zoom; - if (elementZoomLevel !== null && elementZoomLevel !== undefined && elementZoomLevel !== '1') { - zoom *= elementZoomLevel; - } - - testElement = testElement.parentElement; - } while (testElement !== null && testElement !== document.documentElement); + zoom *= dom.getDomNodeZoomLevel(anchor); x = elementPosition.left; y = elementPosition.top + elementPosition.height; diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index d41839b87ba..f205de47189 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -189,7 +189,7 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi const webviewExternalEndpointCommit = this.payload?.get('webviewExternalEndpointCommit'); return endpoint - .replace('{{commit}}', webviewExternalEndpointCommit ?? this.productService.commit ?? '181b43c0e2949e36ecb623d8cc6de29d4fa2bae8') + .replace('{{commit}}', webviewExternalEndpointCommit ?? this.productService.commit ?? '3c8520fab514b9f56070214496b26ff68d1b1cb5') .replace('{{quality}}', (webviewExternalEndpointCommit ? 'insider' : this.productService.quality) ?? 'insider'); } diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index aa1eb99bc0e..1124b843b01 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -21,7 +21,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { localizeManifest } from 'vs/platform/extensionManagement/common/extensionNls'; import { localize } from 'vs/nls'; import * as semver from 'vs/base/common/semver/semver'; -import { isBoolean, isString } from 'vs/base/common/types'; +import { isString } from 'vs/base/common/types'; import { getErrorMessage } from 'vs/base/common/errors'; import { ResourceMap } from 'vs/base/common/map'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; @@ -140,11 +140,11 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten this.logService.info(`Checking additional builtin extensions: Ignoring '${extension.id}' because it is reported to be malicious.`); continue; } - const deprecated = extensionsControlManifest.deprecated ? extensionsControlManifest.deprecated[extension.id.toLowerCase()] : undefined; - if (deprecated && !isBoolean(deprecated)) { - const preReleaseExtensionId = deprecated.id; + const deprecationInfo = extensionsControlManifest.deprecated[extension.id.toLowerCase()]; + if (deprecationInfo?.extension?.autoMigrate) { + const preReleaseExtensionId = deprecationInfo.extension.id; this.logService.info(`Checking additional builtin extensions: '${extension.id}' is deprecated, instead using '${preReleaseExtensionId}'`); - result.push({ id: preReleaseExtensionId, preRelease: !!deprecated.preRelease }); + result.push({ id: preReleaseExtensionId, preRelease: !!extension.preRelease }); } else { result.push(extension); } diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index cc9bcdd1045..46c26ac1795 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -394,7 +394,7 @@ export class ExtensionManagementService extends Disposable implements IWorkbench if (this.extensionManagementServerService.webExtensionManagementServer) { return this.extensionManagementServerService.webExtensionManagementServer.extensionManagementService.getExtensionsControlManifest(); } - return Promise.resolve({ malicious: [] }); + return Promise.resolve({ malicious: [], deprecated: {} }); } private getServer(extension: ILocalExtension): IExtensionManagementServer | null { diff --git a/src/vs/workbench/services/hover/browser/hoverWidget.ts b/src/vs/workbench/services/hover/browser/hoverWidget.ts index 837a4bdfd52..24f4173e3f8 100644 --- a/src/vs/workbench/services/hover/browser/hoverWidget.ts +++ b/src/vs/workbench/services/hover/browser/hoverWidget.ts @@ -230,7 +230,19 @@ export class HoverWidget extends Widget { this._hover.containerDomNode.classList.remove('right-aligned'); this._hover.contentsDomNode.style.maxHeight = ''; - const targetBounds = this._target.targetElements.map(e => e.getBoundingClientRect()); + const getZoomAccountedBoundingClientRect = (e: HTMLElement) => { + const zoom = dom.getDomNodeZoomLevel(e); + + const boundingRect = e.getBoundingClientRect(); + return { + top: boundingRect.top * zoom, + bottom: boundingRect.bottom * zoom, + right: boundingRect.right * zoom, + left: boundingRect.left * zoom, + }; + }; + + const targetBounds = this._target.targetElements.map(e => getZoomAccountedBoundingClientRect(e)); const top = Math.min(...targetBounds.map(e => e.top)); const right = Math.max(...targetBounds.map(e => e.right)); const bottom = Math.max(...targetBounds.map(e => e.bottom)); diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 000a74b77ca..d93923deb81 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -707,17 +707,19 @@ export class DefaultSettings extends Disposable { }); } - const registeredConfigurationProp = prop as IRegisteredConfigurationPropertySchema; - let defaultValueSource: string | IExtensionInfo | undefined; - if (registeredConfigurationProp && registeredConfigurationProp.defaultValueSource) { - defaultValueSource = registeredConfigurationProp.defaultValueSource; - } - let isLanguageTagSetting = false; if (OVERRIDE_PROPERTY_REGEX.test(key)) { isLanguageTagSetting = true; } + let defaultValueSource: string | IExtensionInfo | undefined; + if (!isLanguageTagSetting) { + const registeredConfigurationProp = prop as IRegisteredConfigurationPropertySchema; + if (registeredConfigurationProp && registeredConfigurationProp.defaultValueSource) { + defaultValueSource = registeredConfigurationProp.defaultValueSource; + } + } + result.push({ key, value, diff --git a/test/integration/browser/src/index.ts b/test/integration/browser/src/index.ts index 18350685d5e..39a996b6ff4 100644 --- a/test/integration/browser/src/index.ts +++ b/test/integration/browser/src/index.ts @@ -65,7 +65,7 @@ async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWith const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true }); const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true }); - const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","181b43c0e2949e36ecb623d8cc6de29d4fa2bae8"],["skipWelcome","true"]]`; + const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","3c8520fab514b9f56070214496b26ff68d1b1cb5"],["skipWelcome","true"]]`; if (path.extname(testWorkspacePath) === '.code-workspace') { await page.goto(`${endpoint.href}&workspace=${testWorkspacePath}&payload=${payloadParam}`); diff --git a/yarn.lock b/yarn.lock index 73a712b8d7c..5217a3175a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2563,16 +2563,7 @@ bl@^1.0.0: readable-stream "^2.3.5" safe-buffer "^5.1.1" -bl@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" - integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bl@^4.0.3: +bl@^4.0.2, bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -3957,9 +3948,9 @@ decompress@^4.2.1: strip-dirs "^2.0.0" deemon@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/deemon/-/deemon-1.4.0.tgz#01c09cc23eec41e5d7ddac082eb52c3611d38dff" - integrity sha512-S0zK5tNTdVFsJZVUeKi/CYJn4zzhW0Y55lwXzv2hVxb7ajzAHf91BhE5y2xvx1X7czIZ6PHLPDj00TVAmylVXw== + version "1.7.1" + resolved "https://registry.yarnpkg.com/deemon/-/deemon-1.7.1.tgz#46cf8313fd320fac6ee944bbb1bea3e8c2a978ee" + integrity sha512-UcBiu6+4sZgkDrs7GT78FDkqmt9ZVN412XXT4Bm9sn5Hcrwv/M9HmCay3108Yvxl4Ti5n1UjkkuSVA1y3+FIvg== dependencies: bl "^4.0.2" tree-kill "^1.2.2" @@ -4296,10 +4287,10 @@ electron-to-chromium@^1.4.17: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.45.tgz#cf1144091d6683cbd45a231954a745f02fb24598" integrity sha512-czF9eYVuOmlY/vxyMQz2rGlNSjZpxNQYBe1gmQv7al171qOIhgyO9k7D5AKlgeTCSPKk+LHhj5ZyIdmEub9oNg== -electron@17.4.3: - version "17.4.3" - resolved "https://registry.yarnpkg.com/electron/-/electron-17.4.3.tgz#5f3c26cb211f9267d2becee717f34e3ce564a6bf" - integrity sha512-WQggyCgNUOzoOn+wJKe+xFhYy56gyrn/jIa/l7dyD3TxPb8lddSc86OAqPnP5EugcNXQ0yIu8b+SIE8duKozSw== +electron@17.4.4: + version "17.4.4" + resolved "https://registry.yarnpkg.com/electron/-/electron-17.4.4.tgz#a289fa5cff6a59ef83647517a295eca780d64a86" + integrity sha512-/CqXJwm1VLfhF7+QhCrPEoePcpGMdRh09A+sVHX+kgT1twrmNH8S+ZeMPYxX8EU0O0Eki3UfA5zA2ADWaCDq2Q== dependencies: "@electron/get" "^1.13.0" "@types/node" "^14.6.2" @@ -11399,10 +11390,10 @@ typescript@^2.6.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= -typescript@^4.8.0-dev.20220511: - version "4.8.0-dev.20220511" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220511.tgz#42dd5ad99dcd345277c784949cc36a7b5d43fa18" - integrity sha512-MDo0tI/TRHCJ1sxochoU4LhT41C6jhEIkWneehqsxNYV84+d+C4HvD7Nq4DQrI03cIGvPJbdW2s3ZladROXE+A== +typescript@^4.8.0-dev.20220518: + version "4.8.0-dev.20220518" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220518.tgz#3082c89c764daece904480552b9f2c3f5ce79c56" + integrity sha512-yczRLiowXD4THxpe2DrClYXsmIRt9VPDft1dat4Le50mQwuUcmvdqD43o4hmlbNP7HpyeEYX51KXozGq1s7zlw== typical@^4.0.0: version "4.0.0" @@ -12207,10 +12198,10 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.9.0-beta.35: - version "0.9.0-beta.35" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.35.tgz#524ee3be855c1e8db234c6795bdb44bb6baff8fd" - integrity sha512-hTDqAhqlhBvz3dtdK1Tg5Al2U3HquSHpV1xCX+bbOmbgprAxUrSQxslUPDD69CTazzTyif3L19M08hccRyr1Ug== +xterm-addon-search@0.9.0-beta.37: + version "0.9.0-beta.37" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.37.tgz#84a020f03b2cacc5afac78ca6ff2f1eb86fb6710" + integrity sha512-bfeFgKJkDYyIgqpWiV1oWYqDiTo+SHTeIPEbpOfxDr97pc3PtDF1Tyd79PrvJNfoxaV3VMUo//UEOy4D+KY9OQ== xterm-addon-serialize@0.7.0-beta.12: version "0.7.0-beta.12" @@ -12222,20 +12213,20 @@ xterm-addon-unicode11@0.4.0-beta.3: resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.34: - version "0.12.0-beta.34" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.34.tgz#51cac31cc7a78377be5d481b624ee82948360de1" - integrity sha512-TTIwun+a45oDN54sHhdUxsEx6VflgF2p9YGqS5+gVzpvPrEqP6GoDr6XFCDsZcSqi0ZT2FNGAKWlh7XSxsKQQw== +xterm-addon-webgl@0.12.0-beta.36: + version "0.12.0-beta.36" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.36.tgz#460f80829a78c979a448d5b764699af3f0366ff1" + integrity sha512-sgX7OHSGZQZE5b4xtPqd/5NEcll0Z+00tnTVxKZlXf5XEENcG0tnBF4I4f+k9K3cmjE1UIUVG2yYPrqWlYCdpA== -xterm-headless@4.19.0-beta.43: - version "4.19.0-beta.43" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.43.tgz#12fe4abe624265240a7de8a922bfc4fd28c5f92a" - integrity sha512-4T8TlWy5u+sS23aPtd8gBHJ0BVljbNQRPMFHzLigDNOMCwc4uWa9JsxYmKteKifcG5aMm11ALPUTxWZCgpATww== +xterm-headless@4.19.0-beta.47: + version "4.19.0-beta.47" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.47.tgz#9d5af8145c42b9a6241a040bb244b877c149761b" + integrity sha512-chVTURPMNDEerQIsN4lIRotpXCfJsTHioZGQxDBNdktZO1gMXGvNxDjzsbsJg5ikLN5llz/HLDfXZrjCeb3elg== -xterm@4.19.0-beta.43: - version "4.19.0-beta.43" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.43.tgz#f2113c8ce303d22c5cfad1a4a119b81c103285fa" - integrity sha512-eQ3fzkUApGdl4/rrhzK4OIdMb3+qO0c2iCZIMbeP9SqqDltZnhWncz+3lGa0tnxKizVoUV9kmGaP7orsQ/IavQ== +xterm@4.19.0-beta.47: + version "4.19.0-beta.47" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.47.tgz#f5931201346a485e3bcb29d24e83583727e55707" + integrity sha512-c8EcCSWCHnFYNdRMTnJIpYTV9J2Ze7kdB1GhTcPO2ipMEsqaP/u6Ca8rgBWwV9HeEVfe4rGRqWW2qcSy4U9hMQ== y18n@^3.2.1: version "3.2.2" |