Debt: move open file trust request dialog into the contribution (#126062)
This commit is contained in:
parent
8440af2409
commit
18caeb21fa
|
@ -74,11 +74,14 @@ export const IWorkspaceTrustRequestService = createDecorator<IWorkspaceTrustRequ
|
|||
export interface IWorkspaceTrustRequestService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly onDidInitiateOpenFilesTrustRequest: Event<void>;
|
||||
readonly onDidInitiateWorkspaceTrustRequest: Event<WorkspaceTrustRequestOptions | undefined>;
|
||||
|
||||
requestOpenUris(uris: URI[]): Promise<WorkspaceTrustUriResponse>;
|
||||
cancelRequest(): void;
|
||||
completeRequest(trusted?: boolean): Promise<void>;
|
||||
completeOpenFilesTrustRequest(result: WorkspaceTrustUriResponse, saveResponse?: boolean): Promise<void>;
|
||||
requestOpenFilesTrust(openFiles: URI[]): Promise<WorkspaceTrustUriResponse>;
|
||||
|
||||
cancelWorkspaceTrustRequest(): void;
|
||||
completeWorkspaceTrustRequest(trusted?: boolean): Promise<void>;
|
||||
requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean | undefined>;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, workspaceTrustToString } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, workspaceTrustToString, WorkspaceTrustUriResponse } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
@ -71,15 +71,56 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
|
|||
return !isSingleFolderWorkspaceIdentifier(toWorkspaceIdentifier(this.workspaceContextService.getWorkspace()));
|
||||
}
|
||||
|
||||
private get modalTitle(): string {
|
||||
return this.useWorkspaceLanguage ?
|
||||
localize('workspaceTrust', "Do you trust the authors of the files in this workspace?") :
|
||||
localize('folderTrust', "Do you trust the authors of the files in this folder?");
|
||||
}
|
||||
|
||||
private async registerListeners(): Promise<void> {
|
||||
await this.workspaceTrustManagementService.workspaceResolved;
|
||||
|
||||
// Open files trust request
|
||||
this._register(this.workspaceTrustRequestService.onDidInitiateOpenFilesTrustRequest(async () => {
|
||||
// Details
|
||||
const markdownDetails = [
|
||||
this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY ?
|
||||
localize('openLooseFileWorkspaceDetails', "You are trying to open untrusted files in a workspace which is trusted.") :
|
||||
localize('openLooseFileWindowDetails', "You are trying to open untrusted files in a window which is trusted."),
|
||||
localize('openLooseFileLearnMore', "If you don't trust the authors of these files, we recommend to open them in Restricted Mode in a new window as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.")
|
||||
];
|
||||
|
||||
// Dialog
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
localize('openLooseFileMesssage', "Do you trust the authors of these files?"),
|
||||
[localize('open', "Open"), localize('newWindow', "Open in Restricted Mode"), localize('cancel', "Cancel")],
|
||||
{
|
||||
cancelId: 2,
|
||||
checkbox: {
|
||||
label: localize('openLooseFileWorkspaceCheckbox', "Remember my decision for all workspaces"),
|
||||
checked: false
|
||||
},
|
||||
custom: {
|
||||
icon: Codicon.shield,
|
||||
markdownDetails: markdownDetails.map(md => { return { markdown: new MarkdownString(md) }; })
|
||||
}
|
||||
});
|
||||
|
||||
switch (result.choice) {
|
||||
case 0:
|
||||
await this.workspaceTrustRequestService.completeOpenFilesTrustRequest(WorkspaceTrustUriResponse.Open, !!result.checkboxChecked);
|
||||
break;
|
||||
case 1:
|
||||
await this.workspaceTrustRequestService.completeOpenFilesTrustRequest(WorkspaceTrustUriResponse.OpenInNewWindow, !!result.checkboxChecked);
|
||||
break;
|
||||
default:
|
||||
await this.workspaceTrustRequestService.completeOpenFilesTrustRequest(WorkspaceTrustUriResponse.Cancel);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
// Workspace trust request
|
||||
this._register(this.workspaceTrustRequestService.onDidInitiateWorkspaceTrustRequest(async requestOptions => {
|
||||
// Title
|
||||
const title = this.useWorkspaceLanguage ?
|
||||
localize('workspaceTrust', "Do you trust the authors of the files in this workspace?") :
|
||||
localize('folderTrust', "Do you trust the authors of the files in this folder?");
|
||||
|
||||
// Message
|
||||
const defaultMessage = localize('immediateTrustRequestMessage', "A feature you are trying to use may be a security risk if you do not trust the source of the files or folders you currently have open.");
|
||||
const message = requestOptions?.message ?? defaultMessage;
|
||||
|
@ -89,6 +130,7 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
|
|||
{ label: this.useWorkspaceLanguage ? localize('grantWorkspaceTrustButton', "Trust Workspace & Continue") : localize('grantFolderTrustButton', "Trust Folder & Continue"), type: 'ContinueWithTrust' },
|
||||
{ label: localize('manageWorkspaceTrustButton', "Manage"), type: 'Manage' }
|
||||
];
|
||||
|
||||
// Add Cancel button if not provided
|
||||
if (!buttons.some(b => b.type === 'Cancel')) {
|
||||
buttons.push({ label: localize('cancelWorkspaceTrustButton', "Cancel"), type: 'Cancel' });
|
||||
|
@ -97,7 +139,7 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
|
|||
// Dialog
|
||||
const result = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
this.modalTitle,
|
||||
title,
|
||||
buttons.map(b => b.label),
|
||||
{
|
||||
cancelId: buttons.findIndex(b => b.type === 'Cancel'),
|
||||
|
@ -114,17 +156,17 @@ export class WorkspaceTrustRequestHandler extends Disposable implements IWorkben
|
|||
// Dialog result
|
||||
switch (buttons[result.choice].type) {
|
||||
case 'ContinueWithTrust':
|
||||
await this.workspaceTrustRequestService.completeRequest(true);
|
||||
await this.workspaceTrustRequestService.completeWorkspaceTrustRequest(true);
|
||||
break;
|
||||
case 'ContinueWithoutTrust':
|
||||
await this.workspaceTrustRequestService.completeRequest(undefined);
|
||||
await this.workspaceTrustRequestService.completeWorkspaceTrustRequest(undefined);
|
||||
break;
|
||||
case 'Manage':
|
||||
this.workspaceTrustRequestService.cancelRequest();
|
||||
this.workspaceTrustRequestService.cancelWorkspaceTrustRequest();
|
||||
await this.commandService.executeCommand(MANAGE_TRUST_COMMAND_ID);
|
||||
break;
|
||||
case 'Cancel':
|
||||
this.workspaceTrustRequestService.cancelRequest();
|
||||
this.workspaceTrustRequestService.cancelWorkspaceTrustRequest();
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
@ -223,12 +265,12 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon
|
|||
if (result.checkboxChecked) {
|
||||
await this.workspaceTrustManagementService.setParentFolderTrust(true);
|
||||
} else {
|
||||
await this.workspaceTrustRequestService.completeRequest(true);
|
||||
await this.workspaceTrustRequestService.completeWorkspaceTrustRequest(true);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
this.updateWorkbenchIndicators(false);
|
||||
this.workspaceTrustRequestService.cancelRequest();
|
||||
this.workspaceTrustRequestService.cancelWorkspaceTrustRequest();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -760,7 +760,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
|||
private async handleWorkspaceTrust(editors: Array<IEditorInputWithOptions | IResourceEditorInputType>): Promise<boolean> {
|
||||
const { resources, diffMode } = this.extractEditorResources(editors);
|
||||
|
||||
const trustResult = await this.workspaceTrustRequestService.requestOpenUris(resources);
|
||||
const trustResult = await this.workspaceTrustRequestService.requestOpenFilesTrust(resources);
|
||||
switch (trustResult) {
|
||||
case WorkspaceTrustUriResponse.Open:
|
||||
return true;
|
||||
|
|
|
@ -3,19 +3,15 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { splitName } from 'vs/base/common/labels';
|
||||
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { isVirtualResource } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
@ -577,20 +573,25 @@ export class WorkspaceTrustRequestService extends Disposable implements IWorkspa
|
|||
_serviceBrand: undefined;
|
||||
|
||||
private _trusted!: boolean;
|
||||
private _modalTrustRequestPromise?: Promise<boolean | undefined>;
|
||||
private _modalTrustRequestResolver?: (trusted: boolean | undefined) => void;
|
||||
private readonly _ctxWorkspaceTrustEnabled: IContextKey<boolean>;
|
||||
private readonly _ctxWorkspaceTrustState: IContextKey<boolean>;
|
||||
|
||||
private _openFilesTrustRequestPromise?: Promise<WorkspaceTrustUriResponse>;
|
||||
private _openFilesTrustRequestResolver?: (response: WorkspaceTrustUriResponse) => void;
|
||||
|
||||
private _workspaceTrustRequestPromise?: Promise<boolean | undefined>;
|
||||
private _workspaceTrustRequestResolver?: (trusted: boolean | undefined) => void;
|
||||
|
||||
private readonly _onDidInitiateOpenFilesTrustRequest = this._register(new Emitter<void>());
|
||||
readonly onDidInitiateOpenFilesTrustRequest = this._onDidInitiateOpenFilesTrustRequest.event;
|
||||
|
||||
private readonly _onDidInitiateWorkspaceTrustRequest = this._register(new Emitter<WorkspaceTrustRequestOptions | undefined>());
|
||||
readonly onDidInitiateWorkspaceTrustRequest = this._onDidInitiateWorkspaceTrustRequest.event;
|
||||
|
||||
private readonly _ctxWorkspaceTrustEnabled: IContextKey<boolean>;
|
||||
private readonly _ctxWorkspaceTrustState: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
|
||||
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService
|
||||
) {
|
||||
super();
|
||||
|
@ -613,6 +614,8 @@ export class WorkspaceTrustRequestService extends Disposable implements IWorkspa
|
|||
this._ctxWorkspaceTrustState.set(trusted);
|
||||
}
|
||||
|
||||
//#region Open file(s) trust request
|
||||
|
||||
private get untrustedFilesSetting(): 'prompt' | 'open' | 'newWindow' {
|
||||
return this.configurationService.getValue(WORKSPACE_TRUST_UNTRUSTED_FILES);
|
||||
}
|
||||
|
@ -621,36 +624,35 @@ export class WorkspaceTrustRequestService extends Disposable implements IWorkspa
|
|||
this.configurationService.updateValue(WORKSPACE_TRUST_UNTRUSTED_FILES, value);
|
||||
}
|
||||
|
||||
private resolveRequest(trusted?: boolean): void {
|
||||
if (this._modalTrustRequestResolver) {
|
||||
this._modalTrustRequestResolver(trusted ?? this.trusted);
|
||||
|
||||
this._modalTrustRequestResolver = undefined;
|
||||
this._modalTrustRequestPromise = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
cancelRequest(): void {
|
||||
if (this._modalTrustRequestResolver) {
|
||||
this._modalTrustRequestResolver(undefined);
|
||||
|
||||
this._modalTrustRequestResolver = undefined;
|
||||
this._modalTrustRequestPromise = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async completeRequest(trusted?: boolean): Promise<void> {
|
||||
if (trusted === undefined || trusted === this.trusted) {
|
||||
this.resolveRequest(trusted);
|
||||
async completeOpenFilesTrustRequest(result: WorkspaceTrustUriResponse, saveResponse?: boolean): Promise<void> {
|
||||
if (!this._openFilesTrustRequestResolver) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update storage, transition workspace, and resolve the promise
|
||||
await this.workspaceTrustManagementService.setWorkspaceTrust(trusted);
|
||||
this.resolveRequest(trusted);
|
||||
// Set acceptsOutOfWorkspaceFiles
|
||||
if (result === WorkspaceTrustUriResponse.Open) {
|
||||
this.workspaceTrustManagementService.acceptsOutOfWorkspaceFiles = true;
|
||||
}
|
||||
|
||||
// Save response
|
||||
if (saveResponse) {
|
||||
if (result === WorkspaceTrustUriResponse.Open) {
|
||||
this.untrustedFilesSetting = 'open';
|
||||
}
|
||||
|
||||
if (result === WorkspaceTrustUriResponse.OpenInNewWindow) {
|
||||
this.untrustedFilesSetting = 'newWindow';
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve promise
|
||||
this._openFilesTrustRequestResolver(result);
|
||||
|
||||
this._openFilesTrustRequestResolver = undefined;
|
||||
this._openFilesTrustRequestPromise = undefined;
|
||||
}
|
||||
|
||||
async requestOpenUris(uris: URI[]): Promise<WorkspaceTrustUriResponse> {
|
||||
async requestOpenFilesTrust(uris: URI[]): Promise<WorkspaceTrustUriResponse> {
|
||||
// If workspace is untrusted, there is no conflict
|
||||
if (!this.trusted) {
|
||||
return WorkspaceTrustUriResponse.Open;
|
||||
|
@ -679,48 +681,50 @@ export class WorkspaceTrustRequestService extends Disposable implements IWorkspa
|
|||
return WorkspaceTrustUriResponse.Open;
|
||||
}
|
||||
|
||||
const markdownDetails = [
|
||||
this.workspaceService.getWorkbenchState() !== WorkbenchState.EMPTY ?
|
||||
localize('openLooseFileWorkspaceDetails', "You are trying to open untrusted files in a workspace which is trusted.") :
|
||||
localize('openLooseFileWindowDetails', "You are trying to open untrusted files in a window which is trusted."),
|
||||
localize('openLooseFileLearnMore', "If you don't trust the authors of these files, we recommend to open them in Restricted Mode in a new window as the files may be malicious. See [our docs](https://aka.ms/vscode-workspace-trust) to learn more.")
|
||||
];
|
||||
|
||||
const result = await this.dialogService.show(Severity.Info, localize('openLooseFileMesssage', "Do you trust the authors of these files?"), [localize('open', "Open"), localize('newWindow', "Open in Restricted Mode"), localize('cancel', "Cancel")], {
|
||||
cancelId: 2,
|
||||
checkbox: {
|
||||
label: localize('openLooseFileWorkspaceCheckbox', "Remember my decision for all workspaces"),
|
||||
checked: false
|
||||
},
|
||||
custom: {
|
||||
icon: Codicon.shield,
|
||||
markdownDetails: markdownDetails.map(md => { return { markdown: new MarkdownString(md) }; })
|
||||
}
|
||||
});
|
||||
|
||||
const saveResponseIfChecked = (response: WorkspaceTrustUriResponse, checked: boolean) => {
|
||||
if (checked) {
|
||||
if (response === WorkspaceTrustUriResponse.Open) {
|
||||
this.untrustedFilesSetting = 'open';
|
||||
}
|
||||
|
||||
if (response === WorkspaceTrustUriResponse.OpenInNewWindow) {
|
||||
this.untrustedFilesSetting = 'newWindow';
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
switch (result.choice) {
|
||||
case 0:
|
||||
this.workspaceTrustManagementService.acceptsOutOfWorkspaceFiles = true;
|
||||
return saveResponseIfChecked(WorkspaceTrustUriResponse.Open, !!result.checkboxChecked);
|
||||
case 1:
|
||||
return saveResponseIfChecked(WorkspaceTrustUriResponse.OpenInNewWindow, !!result.checkboxChecked);
|
||||
default:
|
||||
return WorkspaceTrustUriResponse.Cancel;
|
||||
// Create/return a promise
|
||||
if (!this._openFilesTrustRequestPromise) {
|
||||
this._openFilesTrustRequestPromise = new Promise<WorkspaceTrustUriResponse>(resolve => {
|
||||
this._openFilesTrustRequestResolver = resolve;
|
||||
});
|
||||
} else {
|
||||
return this._openFilesTrustRequestPromise;
|
||||
}
|
||||
|
||||
this._onDidInitiateOpenFilesTrustRequest.fire();
|
||||
return this._openFilesTrustRequestPromise;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Workspace trust request
|
||||
|
||||
private resolveWorkspaceTrustRequest(trusted?: boolean): void {
|
||||
if (this._workspaceTrustRequestResolver) {
|
||||
this._workspaceTrustRequestResolver(trusted ?? this.trusted);
|
||||
|
||||
this._workspaceTrustRequestResolver = undefined;
|
||||
this._workspaceTrustRequestPromise = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
cancelWorkspaceTrustRequest(): void {
|
||||
if (this._workspaceTrustRequestResolver) {
|
||||
this._workspaceTrustRequestResolver(undefined);
|
||||
|
||||
this._workspaceTrustRequestResolver = undefined;
|
||||
this._workspaceTrustRequestPromise = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async completeWorkspaceTrustRequest(trusted?: boolean): Promise<void> {
|
||||
if (trusted === undefined || trusted === this.trusted) {
|
||||
this.resolveWorkspaceTrustRequest(trusted);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update storage, transition workspace, and resolve the promise
|
||||
await this.workspaceTrustManagementService.setWorkspaceTrust(trusted);
|
||||
this.resolveWorkspaceTrustRequest(trusted);
|
||||
}
|
||||
|
||||
async requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean | undefined> {
|
||||
|
@ -730,19 +734,21 @@ export class WorkspaceTrustRequestService extends Disposable implements IWorkspa
|
|||
}
|
||||
|
||||
// Modal request
|
||||
if (!this._modalTrustRequestPromise) {
|
||||
if (!this._workspaceTrustRequestPromise) {
|
||||
// Create promise
|
||||
this._modalTrustRequestPromise = new Promise(resolve => {
|
||||
this._modalTrustRequestResolver = resolve;
|
||||
this._workspaceTrustRequestPromise = new Promise(resolve => {
|
||||
this._workspaceTrustRequestResolver = resolve;
|
||||
});
|
||||
} else {
|
||||
// Return existing promise
|
||||
return this._modalTrustRequestPromise;
|
||||
return this._workspaceTrustRequestPromise;
|
||||
}
|
||||
|
||||
this._onDidInitiateWorkspaceTrustRequest.fire(options);
|
||||
return this._modalTrustRequestPromise;
|
||||
return this._workspaceTrustRequestPromise;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
class WorkspaceTrustTransitionManager extends Disposable {
|
||||
|
|
|
@ -98,27 +98,31 @@ export class TestWorkspaceTrustManagementService implements IWorkspaceTrustManag
|
|||
export class TestWorkspaceTrustRequestService implements IWorkspaceTrustRequestService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly _onDidInitiateOpenFilesTrustRequest = new Emitter<void>();
|
||||
readonly onDidInitiateOpenFilesTrustRequest = this._onDidInitiateOpenFilesTrustRequest.event;
|
||||
|
||||
private readonly _onDidInitiateWorkspaceTrustRequest = new Emitter<WorkspaceTrustRequestOptions>();
|
||||
readonly onDidInitiateWorkspaceTrustRequest = this._onDidInitiateWorkspaceTrustRequest.event;
|
||||
|
||||
private readonly _onDidCompleteWorkspaceTrustRequest = new Emitter<boolean>();
|
||||
readonly onDidCompleteWorkspaceTrustRequest = this._onDidCompleteWorkspaceTrustRequest.event;
|
||||
|
||||
constructor(private readonly _trusted: boolean) { }
|
||||
|
||||
requestOpenUrisHandler = async (uris: URI[]) => {
|
||||
return WorkspaceTrustUriResponse.Open;
|
||||
};
|
||||
|
||||
requestOpenUris(uris: URI[]): Promise<WorkspaceTrustUriResponse> {
|
||||
requestOpenFilesTrust(uris: URI[]): Promise<WorkspaceTrustUriResponse> {
|
||||
return this.requestOpenUrisHandler(uris);
|
||||
}
|
||||
|
||||
cancelRequest(): void {
|
||||
async completeOpenFilesTrustRequest(result: WorkspaceTrustUriResponse, saveResponse: boolean): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
async completeRequest(trusted?: boolean): Promise<void> {
|
||||
cancelWorkspaceTrustRequest(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
async completeWorkspaceTrustRequest(trusted?: boolean): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue