Merge branch 'master' into sandy081/settingsSync/align

This commit is contained in:
Sandeep Somavarapu 2021-02-10 21:20:58 +01:00
parent 62cbf21904
commit f57bdeab80
32 changed files with 516 additions and 466 deletions

View file

@ -195,7 +195,7 @@
"underscore": "^1.8.2",
"vinyl": "^2.0.0",
"vinyl-fs": "^3.0.0",
"vscode-debugprotocol": "1.44.0",
"vscode-debugprotocol": "1.45.0-pre.0",
"vscode-nls-dev": "^3.3.1",
"vscode-telemetry-extractor": "^1.6.0",
"webpack": "^4.43.0",

View file

@ -163,8 +163,11 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
this.actionRunner.run(this._action, context);
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus(): void {
if (this.element) {
this.element.tabIndex = 0;
this.element.focus();
this.element.classList.add('focused');
}
@ -173,10 +176,21 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
blur(): void {
if (this.element) {
this.element.blur();
this.element.tabIndex = -1;
this.element.classList.remove('focused');
}
}
setFocusable(): void {
if (this.element) {
this.element.tabIndex = 0;
}
}
get trapsArrowNavigation(): boolean {
return false;
}
protected updateEnabled(): void {
// implement in subclass
}
@ -259,14 +273,27 @@ export class ActionViewItem extends BaseActionViewItem {
this.updateChecked();
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus(): void {
super.focus();
if (this.label) {
this.label.tabIndex = 0;
this.label.focus();
}
}
blur(): void {
if (this.label) {
this.label.tabIndex = -1;
}
}
setFocusable(): void {
if (this.label) {
this.label.tabIndex = 0;
}
}
updateLabel(): void {
if (this.options.label && this.label) {
this.label.textContent = this.getAction().label;
@ -320,7 +347,6 @@ export class ActionViewItem extends BaseActionViewItem {
if (this.label) {
this.label.removeAttribute('aria-disabled');
this.label.classList.remove('disabled');
this.label.tabIndex = 0;
}
if (this.element) {

View file

@ -140,6 +140,7 @@ export class ActionBar extends Disposable implements IActionRunner {
this._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
let eventHandled = true;
const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined;
if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {
eventHandled = this.focusPrevious();
@ -147,6 +148,12 @@ export class ActionBar extends Disposable implements IActionRunner {
eventHandled = this.focusNext();
} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {
this._onDidCancel.fire();
} else if ((event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
if (event.equals(KeyCode.Tab)) {
this.focusNext();
} else {
this.focusPrevious();
}
} else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this._triggerKeys.keyDown) {
@ -294,6 +301,11 @@ export class ActionBar extends Disposable implements IActionRunner {
item.setActionContext(this.context);
item.render(actionViewItemElement);
if (this.viewItems.every(i => !i.isEnabled()) && item instanceof BaseActionViewItem && item.isEnabled()) {
// We need to allow for the first enabled item to be focused on using tab navigation #106441
item.setFocusable();
}
if (index === null || index < 0 || index >= this.actionsList.children.length) {
this.actionsList.appendChild(actionViewItemElement);
this.viewItems.push(item);

View file

@ -78,7 +78,6 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem {
this.element.classList.add(...classNames);
this.element.tabIndex = 0;
this.element.setAttribute('role', 'button');
this.element.setAttribute('aria-haspopup', 'true');
this.element.setAttribute('aria-expanded', 'false');

View file

@ -3,19 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
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 { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled';
export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces');
export enum WorkspaceTrustScope {
Local = 0,
@ -40,11 +31,6 @@ export function workspaceTrustStateToString(trustState: WorkspaceTrustState) {
}
}
export const WorkspaceTrustContext = {
PendingRequest: new RawContextKey<boolean>('workspaceTrustPendingRequest', false),
TrustState: new RawContextKey<WorkspaceTrustState>('workspaceTrustState', WorkspaceTrustState.Unknown)
};
export interface IWorkspaceTrustModel {
readonly onDidChangeTrustState: Event<void>;
@ -86,290 +72,11 @@ export interface IWorkspaceTrustService {
getWorkspaceTrustState(): WorkspaceTrustState;
isWorkspaceTrustEnabled(): boolean;
requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise<WorkspaceTrustState>;
resetWorkspaceTrust(): Promise<WorkspaceTrustState>;
}
interface IWorkspaceTrustStateInfo {
export interface IWorkspaceTrustStateInfo {
localFolders: { uri: string, trustState: WorkspaceTrustState }[]
// Removing complexity of remote items
//trustedRemoteItems: { uri: string }[]
}
export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key';
export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel {
private storageKey = WORKSPACE_TRUST_STORAGE_KEY;
private trustStateInfo: IWorkspaceTrustStateInfo;
private readonly _onDidChangeTrustState = this._register(new Emitter<void>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
constructor(
private readonly storageService: IStorageService
) {
super();
this.trustStateInfo = this.loadTrustInfo();
this._register(this.storageService.onDidChangeValue(changeEvent => {
if (changeEvent.key === this.storageKey) {
this.onDidStorageChange();
}
}));
}
private loadTrustInfo(): IWorkspaceTrustStateInfo {
const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL);
let result: IWorkspaceTrustStateInfo | undefined;
try {
if (infoAsString) {
result = JSON.parse(infoAsString);
}
} catch { }
if (!result) {
result = {
localFolders: [],
//trustedRemoteItems: []
};
}
if (!result.localFolders) {
result.localFolders = [];
}
// if (!result.trustedRemoteItems) {
// result.trustedRemoteItems = [];
// }
return result;
}
private saveTrustInfo(): void {
this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private onDidStorageChange(): void {
this.trustStateInfo = this.loadTrustInfo();
this._onDidChangeTrustState.fire();
}
setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void {
let changed = false;
if (trustState === WorkspaceTrustState.Unknown) {
const before = this.trustStateInfo.localFolders.length;
this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString());
if (this.trustStateInfo.localFolders.length !== before) {
changed = true;
}
} else {
let found = false;
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
found = true;
if (trustInfo.trustState !== trustState) {
trustInfo.trustState = trustState;
changed = true;
}
}
}
if (!found) {
this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState });
changed = true;
}
}
if (changed) {
this.saveTrustInfo();
}
}
getFolderTrustState(folder: URI): WorkspaceTrustState {
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
return trustInfo.trustState;
}
}
return WorkspaceTrustState.Unknown;
}
}
export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel {
trustRequest: IWorkspaceTrustRequest | undefined;
_onDidInitiateRequest = this._register(new Emitter<void>());
onDidInitiateRequest: Event<void> = this._onDidInitiateRequest.event;
_onDidCompleteRequest = this._register(new Emitter<WorkspaceTrustState | undefined>());
onDidCompleteRequest = this._onDidCompleteRequest.event;
initiateRequest(request: IWorkspaceTrustRequest): void {
if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) {
return;
}
this.trustRequest = request;
this._onDidInitiateRequest.fire();
}
completeRequest(trustState?: WorkspaceTrustState): void {
this.trustRequest = undefined;
this._onDidCompleteRequest.fire(trustState);
}
}
export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService {
_serviceBrand: undefined;
private readonly dataModel: IWorkspaceTrustModel;
readonly requestModel: IWorkspaceTrustRequestModel;
private readonly _onDidChangeTrustState = this._register(new Emitter<WorkspaceTrustStateChangeEvent>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown;
private _inFlightResolver?: (trustState: WorkspaceTrustState) => void;
private _trustRequestPromise?: Promise<WorkspaceTrustState>;
private _workspace: IWorkspace;
private readonly _ctxWorkspaceTrustState: IContextKey<WorkspaceTrustState>;
private readonly _ctxWorkspaceTrustPendingRequest: IContextKey<boolean>;
constructor(
@IStorageService private readonly storageService: IStorageService,
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
@IConfigurationService readonly configurationService: IConfigurationService,
@IContextKeyService readonly contextKeyService: IContextKeyService
) {
super();
this.dataModel = this._register(new WorkspaceTrustModel(this.storageService));
this.requestModel = this._register(new WorkspaceTrustRequestModel());
this._workspace = this.workspaceService.getWorkspace();
this._currentTrustState = this.calculateWorkspaceTrustState();
this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState()));
this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState)));
this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService);
this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService);
this._ctxWorkspaceTrustState.set(this.currentTrustState);
}
private get currentTrustState(): WorkspaceTrustState {
return this._currentTrustState;
}
private set currentTrustState(trustState: WorkspaceTrustState) {
if (this._currentTrustState === trustState) { return; }
const previousState = this._currentTrustState;
this._currentTrustState = trustState;
this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState });
}
private calculateWorkspaceTrustState(): WorkspaceTrustState {
if (!this.isWorkspaceTrustEnabled()) {
return WorkspaceTrustState.Trusted;
}
if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) {
return WorkspaceTrustState.Trusted;
}
let state = undefined;
for (const folder of this._workspace.folders) {
const folderTrust = this.dataModel.getFolderTrustState(folder.uri);
switch (folderTrust) {
case WorkspaceTrustState.Untrusted:
return WorkspaceTrustState.Untrusted;
case WorkspaceTrustState.Unknown:
state = folderTrust;
break;
case WorkspaceTrustState.Trusted:
if (state === undefined) {
state = folderTrust;
}
break;
}
}
return state ?? WorkspaceTrustState.Unknown;
}
private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void {
if (this._inFlightResolver) {
this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState);
}
this._inFlightResolver = undefined;
this._trustRequestPromise = undefined;
if (trustState === undefined) {
return;
}
this._workspace.folders.forEach(folder => {
this.dataModel.setFolderTrustState(folder.uri, trustState);
});
this._ctxWorkspaceTrustPendingRequest.set(false);
this._ctxWorkspaceTrustState.set(trustState);
}
getWorkspaceTrustState(): WorkspaceTrustState {
return this.currentTrustState;
}
isWorkspaceTrustEnabled(): boolean {
return this.configurationService.getValue<boolean>(WORKSPACE_TRUST_ENABLED) ?? false;
}
async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
if (this.currentTrustState === WorkspaceTrustState.Trusted) {
return this.currentTrustState;
}
if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) {
return this.currentTrustState;
}
if (this._trustRequestPromise) {
if (request?.immediate &&
this.requestModel.trustRequest &&
!this.requestModel.trustRequest.immediate) {
this.requestModel.initiateRequest(request);
}
return this._trustRequestPromise;
}
this._trustRequestPromise = new Promise(resolve => {
this._inFlightResolver = resolve;
});
this.requestModel.initiateRequest(request);
this._ctxWorkspaceTrustPendingRequest.set(true);
return this._trustRequestPromise;
}
async resetWorkspaceTrust(): Promise<WorkspaceTrustState> {
if (this.currentTrustState !== WorkspaceTrustState.Unknown) {
this._workspace.folders.forEach(folder => {
this.dataModel.setFolderTrustState(folder.uri, WorkspaceTrustState.Unknown);
});
}
return Promise.resolve(WorkspaceTrustState.Unknown);
}
}
registerSingleton(IWorkspaceTrustService, WorkspaceTrustService);

View file

@ -21,6 +21,8 @@ export class MainThreadAuthenticationProvider extends Disposable {
private _accounts = new Map<string, string[]>(); // Map account name to session ids
private _sessions = new Map<string, string>(); // Map account id to name
private _hasInitializedSessions = false;
constructor(
private readonly _proxy: ExtHostAuthenticationShape,
public readonly id: string,
@ -33,11 +35,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
) {
super();
}
public async initialize(): Promise<void> {
return this.registerCommandsAndContextMenuItems();
}
public hasSessions(): boolean {
return !!this._sessions.size;
}
@ -83,15 +80,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.show();
}
private async registerCommandsAndContextMenuItems(): Promise<void> {
try {
const sessions = await this._proxy.$getSessions(this.id);
sessions.forEach(session => this.registerSession(session));
} catch (_) {
// Ignore
}
}
private registerSession(session: modes.AuthenticationSession) {
this._sessions.set(session.id, session.account.label);
@ -123,7 +111,13 @@ export class MainThreadAuthenticationProvider extends Disposable {
}
async getSessions(): Promise<ReadonlyArray<modes.AuthenticationSession>> {
return this._proxy.$getSessions(this.id);
const sessions = await this._proxy.$getSessions(this.id);
if (!this._hasInitializedSessions) {
sessions.forEach(session => this.registerSession(session));
this._hasInitializedSessions = true;
}
return sessions;
}
async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise<void> {
@ -195,7 +189,6 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageService, this.quickInputService, this.dialogService);
await provider.initialize();
this.authenticationService.registerAuthenticationProvider(id, provider);
}
@ -268,7 +261,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
const orderedScopes = scopes.sort().join(' ');
const sessions = (await this.authenticationService.getSessions(providerId)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
const sessions = (await this.authenticationService.getSessions(providerId, true)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
const silent = !options.createIfNone;
let session: modes.AuthenticationSession | undefined;
@ -300,7 +293,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
throw new Error('User did not consent to login.');
}
session = await this.authenticationService.login(providerId, scopes);
session = await this.authenticationService.login(providerId, scopes, true);
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
} else {
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);

View file

@ -129,13 +129,13 @@ export class MainThreadFileSystemEventService {
}
} else {
if (operation === FileOperation.CREATE) {
message = localize('ask.N.create', "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length);
message = localize({ key: 'ask.N.create', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length);
} else if (operation === FileOperation.COPY) {
message = localize('ask.N.copy', "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length);
message = localize({ key: 'ask.N.copy', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length);
} else if (operation === FileOperation.MOVE) {
message = localize('ask.N.move', "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length);
message = localize({ key: 'ask.N.move', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length);
} else /* if (operation === FileOperation.DELETE) */ {
message = localize('ask.N.delete', "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length);
message = localize({ key: 'ask.N.delete', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length);
}
}

View file

@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellOutputEdit, ITransformedDisplayOutputDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellOutputEdit, ITransformedDisplayOutputDto, notebookDocumentMetadataDefaults, NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
@ -2813,6 +2813,72 @@ export enum ColorThemeKind {
//#region Notebook
export class NotebookCellMetadata {
constructor(
readonly editable?: boolean,
readonly breakpointMargin?: boolean,
readonly runnable?: boolean,
readonly hasExecutionOrder?: boolean,
readonly executionOrder?: number,
readonly runState?: NotebookCellRunState,
readonly runStartTime?: number,
readonly statusMessage?: string,
readonly lastRunDuration?: number,
readonly inputCollapsed?: boolean,
readonly outputCollapsed?: boolean,
readonly custom?: Record<string, any>,
) { }
with(change: Partial<Omit<NotebookCellMetadata, 'with'>>): NotebookCellMetadata {
return new NotebookCellMetadata(
change.editable ?? this.editable,
change.breakpointMargin ?? this.breakpointMargin,
change.runnable ?? this.runnable,
change.hasExecutionOrder ?? this.hasExecutionOrder,
change.executionOrder ?? this.executionOrder,
change.runState ?? this.runState,
change.runStartTime ?? this.runStartTime,
change.statusMessage ?? this.statusMessage,
change.lastRunDuration ?? this.lastRunDuration,
change.inputCollapsed ?? this.inputCollapsed,
change.outputCollapsed ?? this.outputCollapsed,
change.custom ?? this.custom
);
}
}
export class NotebookDocumentMetadata {
constructor(
readonly editable: boolean = true,
readonly runnable: boolean = true,
readonly cellEditable: boolean = true,
readonly cellRunnable: boolean = true,
readonly cellHasExecutionOrder: boolean = true,
readonly displayOrder: vscode.GlobPattern[] = NOTEBOOK_DISPLAY_ORDER,
readonly custom: { [key: string]: any; } = {},
readonly runState: NotebookRunState = NotebookRunState.Idle,
readonly trusted: boolean = true,
readonly languages: string[] = [],
) { }
with(change: Partial<Omit<NotebookDocumentMetadata, 'with'>>) {
return new NotebookDocumentMetadata(
change.editable ?? this.editable,
change.runnable ?? this.runnable,
change.cellEditable ?? this.cellEditable,
change.cellRunnable ?? this.cellRunnable,
change.cellHasExecutionOrder ?? this.cellHasExecutionOrder,
change.displayOrder ?? this.displayOrder,
change.custom ?? this.custom,
change.runState ?? this.runState,
change.trusted ?? this.trusted,
change.languages ?? this.languages,
);
}
}
export class NotebookCellOutputItem {
static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem {

View file

@ -182,6 +182,11 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.TimelineItemContext,
description: localize('view.timelineContext', "The Timeline view item context menu")
},
{
key: 'ports/item/context',
id: MenuId.TunnelContext,
description: localize('view.tunnelContext', "The Ports view item context menu")
}
];
namespace schema {

View file

@ -23,7 +23,7 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/platform/workspace/common/workspaceTrust';
import { WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust';
export class OpenFileAction extends Action {
@ -255,8 +255,9 @@ class WorkspaceTrustManageAction extends Action2 {
constructor() {
super({
id: 'workbench.action.manageTrust',
title: { value: nls.localize('resetTrustAction', "Manage Trusted Workspaces"), original: 'Manage Trusted Workspaces' },
title: { value: nls.localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' },
precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true),
category: nls.localize('workspacesCategory', "Workspaces"),
f1: true,
});
}

View file

@ -259,6 +259,11 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
}
});
if (providers.length && !menus.length) {
const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false));
menus.push(noAccountsAvailableAction);
}
if (menus.length && otherCommands.length) {
menus.push(disposables.add(new Separator()));
}

View file

@ -199,8 +199,6 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.container = container;
// Make the container tab-able for keyboard navigation
this.container.tabIndex = 0;
this.container.setAttribute('role', 'tab');
// Try hard to prevent keyboard only focus feedback when using mouse
@ -647,10 +645,6 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
});
}
focus(): void {
this.container.focus();
}
protected updateChecked(): void {
if (this.getAction().checked) {
this.container.classList.add('checked');

View file

@ -427,15 +427,9 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
}
async _revealElement(element: IFileStat | IWorkspaceFolder, options: IEditorOptions, sideBySide: boolean): Promise<boolean> {
let resource: URI | undefined;
if (isWorkspaceFolder(element)) {
resource = element.uri;
} else if (!element.isDirectory) {
resource = element.resource;
}
if (resource) {
if (!isWorkspaceFolder(element) && element.isFile) {
this._onWillPickElement.fire();
await this._editorService.openEditor({ resource, options }, sideBySide ? SIDE_GROUP : undefined);
await this._editorService.openEditor({ resource: element.resource, options }, sideBySide ? SIDE_GROUP : undefined);
return true;
}
return false;

View file

@ -20,7 +20,7 @@ import {
} from 'vs/workbench/contrib/debug/common/debug';
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { registerCommands, ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
import { isMacintosh, isWeb } from 'vs/base/common/platform';
@ -123,6 +123,8 @@ function registerCommandsAndActions(): void {
registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlineBreakpoint', "Inline Breakpoint"));
registerDebugCommandPaletteItem(DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
// Debug callstack context menu
const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation') => {

View file

@ -165,6 +165,10 @@ export class ReplFilterActionViewItem extends BaseActionViewItem {
return this.filterInputBox.getHistory();
}
get trapsArrowNavigation(): boolean {
return true;
}
private clearFilterText(): void {
this.filterInputBox.value = '';
}

View file

@ -704,6 +704,7 @@ declare module DebugProtocol {
The request configures the debuggers response to thrown exceptions.
If an exception is configured to break, a 'stopped' event is fired (with reason 'exception').
Clients should only call this request if the capability 'exceptionBreakpointFilters' returns one or more filters.
If a filter or filter option is invalid (e.g. due to an invalid 'condition'), the request should fail with an 'ErrorResponse' explaining the problem(s).
*/
export interface SetExceptionBreakpointsRequest extends Request {
// command: 'setExceptionBreakpoints';
@ -1629,10 +1630,14 @@ declare module DebugProtocol {
filter: string;
/** The name of the filter option. This will be shown in the UI. */
label: string;
/** An optional help text providing additional information about the exception filter. This string is typically shown as a hover and must be translated. */
description?: string;
/** Initial value of the filter option. If not specified a value 'false' is assumed. */
default?: boolean;
/** Controls whether a condition can be specified for this filter option. If false or missing, a condition can not be set. */
supportsCondition?: boolean;
/** An optional help text providing information about the condition. This string is shown as the placeholder text for a text box and must be translated. */
conditionDescription?: string;
}
/** A structured message object. Used to return errors from requests. */
@ -1774,6 +1779,8 @@ declare module DebugProtocol {
endLine?: number;
/** An optional end column of the range covered by the stack frame. */
endColumn?: number;
/** Indicates whether this frame can be restarted with the 'restart' request. Clients should only use this if the debug adapter supports the 'restart' request (capability 'supportsRestartRequest' is true). */
canRestart?: boolean;
/** Optional memory reference for the current instruction pointer in this frame. */
instructionPointerReference?: string;
/** The module associated with this frame, if any. */

View file

@ -32,7 +32,7 @@ import { timeout } from 'vs/base/common/async';
import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices';
import { OS } from 'vs/base/common/platform';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
interface ExperimentSettings {
enabled?: boolean;

View file

@ -56,7 +56,7 @@ import { UserDataSyncResourceEnablementService } from 'vs/platform/userDataSync/
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
let instantiationService: TestInstantiationService;
let installEvent: Emitter<InstallExtensionEvent>,

View file

@ -283,6 +283,10 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem {
}
}
get trapsArrowNavigation(): boolean {
return true;
}
private clearFilterText(): void {
if (this.filterInputBox) {
this.filterInputBox.value = '';

View file

@ -462,6 +462,7 @@ class OutputAutomaticPortForwarding extends Disposable {
class ProcAutomaticPortForwarding extends Disposable {
private candidateListener: IDisposable | undefined;
private autoForwarded: Set<string> = new Set();
private notifiedOnly: Set<string> = new Set();
private notifier: OnAutoForwardedAction;
private initialCandidates: Set<string> = new Set();
private portsFeatures: IDisposable | undefined;
@ -543,18 +544,18 @@ class ProcAutomaticPortForwarding extends Disposable {
if (this.initialCandidates.has(address)) {
return undefined;
}
const alreadyForwarded = mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port);
if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.detected, value.host, value.port)) {
return undefined;
}
if (mapHasAddressLocalhostOrAllInterfaces(this.remoteExplorerService.tunnelModel.forwarded, value.host, value.port)) {
return undefined;
}
if (this.portsAttributes.getAttributes(value.port)?.onAutoForward === OnPortForward.Ignore) {
return undefined;
}
const forwarded = await this.remoteExplorerService.forward(value, undefined, undefined, undefined, undefined, undefined, false);
if (forwarded) {
if (!alreadyForwarded && forwarded) {
this.autoForwarded.add(address);
} else if (forwarded) {
this.notifiedOnly.add(address);
}
return forwarded;
}))).filter(tunnel => !!tunnel);
@ -571,6 +572,9 @@ class ProcAutomaticPortForwarding extends Disposable {
this.remoteExplorerService.close(value);
this.autoForwarded.delete(key);
removedPorts.push(value.port);
} else if (this.notifiedOnly.has(key)) {
this.notifiedOnly.delete(key);
removedPorts.push(value.port);
} else if (this.initialCandidates.has(key)) {
this.initialCandidates.delete(key);
}

View file

@ -812,23 +812,26 @@ namespace LabelTunnelAction {
export const LABEL = nls.localize('remote.tunnel.label', "Set Label");
export function handler(): ICommandHandler {
return async (accessor, arg) => {
return async (accessor, arg): Promise<{ port: number, label: string } | undefined> => {
const context = (arg !== undefined || arg instanceof TunnelItem) ? arg : accessor.get(IContextKeyService).getContextKeyValue(TunnelViewSelectionKeyName);
if (context instanceof TunnelItem) {
const remoteExplorerService = accessor.get(IRemoteExplorerService);
remoteExplorerService.setEditable(context, {
onFinish: async (value, success) => {
if (success) {
remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value);
}
remoteExplorerService.setEditable(context, null);
},
validationMessage: () => null,
placeholder: nls.localize('remote.tunnelsView.labelPlaceholder', "Port label"),
startingValue: context.name
return new Promise(resolve => {
const remoteExplorerService = accessor.get(IRemoteExplorerService);
remoteExplorerService.setEditable(context, {
onFinish: async (value, success) => {
if (success) {
remoteExplorerService.tunnelModel.name(context.remoteHost, context.remotePort, value);
}
remoteExplorerService.setEditable(context, null);
resolve(success ? { port: context.remotePort, label: value } : undefined);
},
validationMessage: () => null,
placeholder: nls.localize('remote.tunnelsView.labelPlaceholder', "Port label"),
startingValue: context.name
});
});
}
return;
return undefined;
};
}
}

View file

@ -17,7 +17,7 @@ import { Action2, ICommandAction, MenuId, MenuRegistry, registerAction2, SyncAct
import { CommandsRegistry, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { ContextKeyRegexExpr, ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyEqualsExpr, ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IFileService } from 'vs/platform/files/common/files';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@ -637,10 +637,6 @@ const viewDescriptor: IViewDescriptor = {
mnemonicTitle: nls.localize({ key: 'miViewSearch', comment: ['&& denotes a mnemonic'] }, "&&Search"),
keybindings: {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F,
// View: Show Search is used for the keybindings in the View menu and the sidebar, but Find In Files should run the actual action.
// If the context key is clearly false (ContextKeyFalseExpression), the keybinding won't appear. Instead we use a regex that never is true.
// See #116188, #115556, #115511
when: ContextKeyRegexExpr.create(`never`, /(?!x)x/),
},
order: 1
}
@ -714,7 +710,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
]
},
id: Constants.FindInFilesActionId,
weight: KeybindingWeight.WorkbenchContrib,
// Give more weightage to this keybinding than of `View: Show Search` keybinding. See #116188, #115556, #115511
weight: KeybindingWeight.WorkbenchContrib + 1,
when: null,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F,
handler: FindInFilesCommand

View file

@ -436,7 +436,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
private registerGlobalActivityActions(): void {
CommandsRegistry.registerCommand('update.check', () => this.updateService.checkForUpdates(this.environmentService.sessionId));
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.check',
title: nls.localize('checkForUpdates', "Check for Updates...")
@ -446,7 +446,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.checking', () => { });
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.checking',
title: nls.localize('checkingForUpdates', "Checking for Updates..."),
@ -457,7 +457,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.downloadNow', () => this.updateService.downloadUpdate());
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.downloadNow',
title: nls.localize('download update_1', "Download Update (1)")
@ -467,7 +467,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.downloading', () => { });
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.downloading',
title: nls.localize('DownloadingUpdate', "Downloading Update..."),
@ -478,7 +478,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.install', () => this.updateService.applyUpdate());
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.install',
title: nls.localize('installUpdate...', "Install Update... (1)")
@ -488,7 +488,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.updating', () => { });
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.updating',
title: nls.localize('installingUpdate', "Installing Update..."),
@ -499,7 +499,7 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
CommandsRegistry.registerCommand('update.restart', () => this.updateService.quitAndInstall());
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
group: '6_update',
group: '7_update',
command: {
id: 'update.restart',
title: nls.localize('restartToUpdate', "Restart to Update (1)")
@ -536,7 +536,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor
menu: {
id: MenuId.GlobalActivity,
when: IsWebContext,
group: '6_update',
group: '7_update',
}
});
}

View file

@ -10,7 +10,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Severity } from 'vs/platform/notification/common/notification';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkspaceTrustService, WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI, WorkspaceTrustState, WorkspaceTrustStateChangeEvent, workspaceTrustStateToString } from 'vs/platform/workspace/common/workspaceTrust';
import { IWorkspaceTrustService, WorkspaceTrustState, WorkspaceTrustStateChangeEvent, workspaceTrustStateToString } from 'vs/platform/workspace/common/workspaceTrust';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { IActivityService, IconBadge } from 'vs/workbench/services/activity/common/activity';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
@ -20,11 +20,11 @@ import { ThemeColor } from 'vs/workbench/api/common/extHostTypes';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkspaceTrustFileSystemProvider } from 'vs/workbench/contrib/workspace/common/workspaceTrustFileSystemProvider';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
import { WorkspaceTrustContext, WORKSPACE_TRUST_ENABLED, WORKSPACE_TRUST_URI } from 'vs/workbench/services/workspaces/common/workspaceTrust';
const workspaceTrustIcon = registerIcon('workspace-trust-icon', Codicon.shield, localize('workspaceTrustIcon', "Icon for workspace trust badge."));
@ -200,7 +200,7 @@ registerAction2(class extends Action2 {
menu: {
id: MenuId.GlobalActivity,
when: WorkspaceTrustContext.PendingRequest,
group: '7_trust',
group: '6_workspace_trust',
order: 10
},
});
@ -240,7 +240,7 @@ registerAction2(class extends Action2 {
menu: {
id: MenuId.GlobalActivity,
when: WorkspaceTrustContext.PendingRequest,
group: '7_trust',
group: '6_workspace_trust',
order: 20
},
});
@ -264,53 +264,19 @@ registerAction2(class extends Action2 {
}
});
// Reset Workspace Trust
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.trust.reset',
title: {
original: 'Reset Workspace Trust',
value: localize('reset', "Reset Workspace Trust")
},
category: localize('workspacesCategory', "Workspaces"),
f1: true,
precondition: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('empty').negate(), WorkspaceTrustContext.TrustState.isEqualTo(WorkspaceTrustState.Unknown).negate())
});
}
async run(accessor: ServicesAccessor) {
const dialogService = accessor.get(IDialogService);
const workspaceTrustService = accessor.get(IWorkspaceTrustService);
const result = await dialogService.confirm({
message: localize('reset', "Reset Workspace Trust"),
detail: localize('confirmResetWorkspaceTrust', "Resetting workspace trust to the workspace will disable features that may pose a security risk if the contents of the workspace cannot be trusted. Are you sure you want to reset trust this workspace?"),
primaryButton: localize('yesGrant', 'Yes'),
secondaryButton: localize('noGrant', 'No')
});
if (result.confirmed) {
workspaceTrustService.resetWorkspaceTrust();
}
return;
}
});
// Manage Workspace Trust
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.trust.manage',
title: {
original: 'Manage Trusted Workspaces',
value: localize('manageWorkspaceTrust', "Manage Trusted Workspaces")
original: 'Manage Workspace Trust',
value: localize('manageWorkspaceTrust', "Manage Workspace Trust")
},
category: localize('workspacesCategory', "Workspaces"),
menu: {
id: MenuId.GlobalActivity,
group: '7_trust',
group: '6_workspace_trust',
order: 40,
when: ContextKeyExpr.and(ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest.negate())
},
@ -327,9 +293,9 @@ registerAction2(class extends Action2 {
MenuRegistry.appendMenuItem(MenuId.GlobalActivity, {
command: {
id: 'workbench.trust.manage',
title: localize('manageWorkspaceTrustPending', "Manage Trusted Workspaces (1)"),
title: localize('manageWorkspaceTrustPending', "Manage Workspace Trust (1)"),
},
group: '7_trust',
group: '6_workspace_trust',
order: 40,
when: ContextKeyExpr.and(ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true), WorkspaceTrustContext.PendingRequest)
});

View file

@ -10,7 +10,7 @@ import { FileDeleteOptions, FileOverwriteOptions, FileSystemProviderCapabilities
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { VSBuffer } from 'vs/base/common/buffer';
import { WORKSPACE_TRUST_STORAGE_KEY } from 'vs/platform/workspace/common/workspaceTrust';
import { WORKSPACE_TRUST_STORAGE_KEY } from 'vs/workbench/services/workspaces/common/workspaceTrust';
const WORKSPACE_TRUST_SCHEMA = 'workspaceTrust';

View file

@ -22,7 +22,7 @@ import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/exte
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { flatten } from 'vs/base/common/arrays';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { Severity } from 'vs/platform/notification/common/notification';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
@ -124,10 +124,10 @@ export interface IAuthenticationService {
declaredProviders: AuthenticationProviderInformation[];
readonly onDidChangeDeclaredProviders: Event<AuthenticationProviderInformation[]>;
getSessions(providerId: string): Promise<ReadonlyArray<AuthenticationSession>>;
getSessions(providerId: string, activateImmediate?: boolean): Promise<ReadonlyArray<AuthenticationSession>>;
getLabel(providerId: string): string;
supportsMultipleAccounts(providerId: string): boolean;
login(providerId: string, scopes: string[]): Promise<AuthenticationSession>;
login(providerId: string, scopes: string[], activateImmediate?: boolean): Promise<AuthenticationSession>;
logout(providerId: string, sessionId: string): Promise<void>;
manageTrustedExtensionsForAccount(providerId: string, accountName: string): Promise<void>;
@ -192,7 +192,6 @@ const authenticationExtPoint = ExtensionsRegistry.registerExtensionPoint<Authent
export class AuthenticationService extends Disposable implements IAuthenticationService {
declare readonly _serviceBrand: undefined;
private _placeholderMenuItem: IDisposable | undefined;
private _noAccountsMenuItem: IDisposable | undefined;
private _signInRequestItems = new Map<string, SessionRequestInfo>();
private _sessionAccessRequestItems = new Map<string, { [extensionId: string]: { disposables: IDisposable[], possibleSessions: AuthenticationSession[] } }>();
private _accountBadgeDisposable = this._register(new MutableDisposable());
@ -278,29 +277,6 @@ export class AuthenticationService extends Disposable implements IAuthentication
return this._authenticationProviders.has(id);
}
private updateAccountsMenuItem(): void {
let hasSession = false;
this._authenticationProviders.forEach(async provider => {
hasSession = hasSession || provider.hasSessions();
});
if (hasSession && this._noAccountsMenuItem) {
this._noAccountsMenuItem.dispose();
this._noAccountsMenuItem = undefined;
}
if (!hasSession && !this._noAccountsMenuItem) {
this._noAccountsMenuItem = MenuRegistry.appendMenuItem(MenuId.AccountsContext, {
group: '0_accounts',
command: {
id: 'noAccounts',
title: nls.localize('noAccounts', "You are not signed in to any accounts"),
precondition: ContextKeyExpr.false()
},
});
}
}
registerAuthenticationProvider(id: string, authenticationProvider: MainThreadAuthenticationProvider): void {
this._authenticationProviders.set(id, authenticationProvider);
this._onDidRegisterAuthenticationProvider.fire({ id, label: authenticationProvider.label });
@ -309,8 +285,6 @@ export class AuthenticationService extends Disposable implements IAuthentication
this._placeholderMenuItem.dispose();
this._placeholderMenuItem = undefined;
}
this.updateAccountsMenuItem();
}
unregisterAuthenticationProvider(id: string): void {
@ -319,7 +293,6 @@ export class AuthenticationService extends Disposable implements IAuthentication
provider.dispose();
this._authenticationProviders.delete(id);
this._onDidUnregisterAuthenticationProvider.fire({ id, label: provider.label });
this.updateAccountsMenuItem();
const accessRequests = this._sessionAccessRequestItems.get(id) || {};
Object.keys(accessRequests).forEach(extensionId => {
@ -343,7 +316,6 @@ export class AuthenticationService extends Disposable implements IAuthentication
if (provider) {
this._onDidChangeSessions.fire({ providerId: id, label: provider.label, event: event });
await provider.updateSessionItems(event);
this.updateAccountsMenuItem();
if (event.added) {
await this.updateNewSessionRequests(provider);
@ -693,8 +665,8 @@ export class AuthenticationService extends Disposable implements IAuthentication
}
}
private async tryActivateProvider(providerId: string): Promise<MainThreadAuthenticationProvider> {
await this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(providerId));
private async tryActivateProvider(providerId: string, activateImmediate: boolean): Promise<MainThreadAuthenticationProvider> {
await this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(providerId), activateImmediate ? ActivationKind.Immediate : ActivationKind.Normal);
let provider = this._authenticationProviders.get(providerId);
if (provider) {
return provider;
@ -724,18 +696,18 @@ export class AuthenticationService extends Disposable implements IAuthentication
return Promise.race([didRegister, didTimeout]);
}
async getSessions(id: string): Promise<ReadonlyArray<AuthenticationSession>> {
async getSessions(id: string, activateImmediate: boolean = false): Promise<ReadonlyArray<AuthenticationSession>> {
try {
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id);
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate);
return await authProvider.getSessions();
} catch (_) {
throw new Error(`No authentication provider '${id}' is currently registered.`);
}
}
async login(id: string, scopes: string[]): Promise<AuthenticationSession> {
async login(id: string, scopes: string[], activateImmediate: boolean = false): Promise<AuthenticationSession> {
try {
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id);
const authProvider = this._authenticationProviders.get(id) || await this.tryActivateProvider(id, activateImmediate);
return await authProvider.login(scopes);
} catch (_) {
throw new Error(`No authentication provider '${id}' is currently registered.`);

View file

@ -31,7 +31,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
import { mock } from 'vs/base/test/common/mock';
import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
function createStorageService(instantiationService: TestInstantiationService): IStorageService {
let service = instantiationService.get(IStorageService);

View file

@ -371,7 +371,9 @@ export class TunnelModel extends Disposable {
return tunnel;
}
} else {
existingTunnel.name = name;
if (name) {
existingTunnel.name = name;
}
this._onForwardPort.fire();
return mapHasAddressLocalhostOrAllInterfaces(this.remoteTunnels, remote.host, remote.port);
}

View file

@ -0,0 +1,290 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceTrustModel, IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, IWorkspaceTrustStateInfo, WorkspaceTrustState, WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust';
export const WORKSPACE_TRUST_ENABLED = 'workspace.trustEnabled';
export const WORKSPACE_TRUST_STORAGE_KEY = 'content.trust.model.key';
export const WORKSPACE_TRUST_URI = URI.parse('workspaceTrust:/Trusted Workspaces');
export const WorkspaceTrustContext = {
PendingRequest: new RawContextKey<boolean>('workspaceTrustPendingRequest', false),
TrustState: new RawContextKey<WorkspaceTrustState>('workspaceTrustState', WorkspaceTrustState.Unknown)
};
export class WorkspaceTrustModel extends Disposable implements IWorkspaceTrustModel {
private storageKey = WORKSPACE_TRUST_STORAGE_KEY;
private trustStateInfo: IWorkspaceTrustStateInfo;
private readonly _onDidChangeTrustState = this._register(new Emitter<void>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
constructor(
private readonly storageService: IStorageService
) {
super();
this.trustStateInfo = this.loadTrustInfo();
this._register(this.storageService.onDidChangeValue(changeEvent => {
if (changeEvent.key === this.storageKey) {
this.onDidStorageChange();
}
}));
}
private loadTrustInfo(): IWorkspaceTrustStateInfo {
const infoAsString = this.storageService.get(this.storageKey, StorageScope.GLOBAL);
let result: IWorkspaceTrustStateInfo | undefined;
try {
if (infoAsString) {
result = JSON.parse(infoAsString);
}
} catch { }
if (!result) {
result = {
localFolders: [],
//trustedRemoteItems: []
};
}
if (!result.localFolders) {
result.localFolders = [];
}
// if (!result.trustedRemoteItems) {
// result.trustedRemoteItems = [];
// }
return result;
}
private saveTrustInfo(): void {
this.storageService.store(this.storageKey, JSON.stringify(this.trustStateInfo), StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private onDidStorageChange(): void {
this.trustStateInfo = this.loadTrustInfo();
this._onDidChangeTrustState.fire();
}
setFolderTrustState(folder: URI, trustState: WorkspaceTrustState): void {
let changed = false;
if (trustState === WorkspaceTrustState.Unknown) {
const before = this.trustStateInfo.localFolders.length;
this.trustStateInfo.localFolders = this.trustStateInfo.localFolders.filter(info => info.uri !== folder.toString());
if (this.trustStateInfo.localFolders.length !== before) {
changed = true;
}
} else {
let found = false;
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
found = true;
if (trustInfo.trustState !== trustState) {
trustInfo.trustState = trustState;
changed = true;
}
}
}
if (!found) {
this.trustStateInfo.localFolders.push({ uri: folder.toString(), trustState });
changed = true;
}
}
if (changed) {
this.saveTrustInfo();
}
}
getFolderTrustState(folder: URI): WorkspaceTrustState {
for (const trustInfo of this.trustStateInfo.localFolders) {
if (trustInfo.uri === folder.toString()) {
return trustInfo.trustState;
}
}
return WorkspaceTrustState.Unknown;
}
}
export class WorkspaceTrustRequestModel extends Disposable implements IWorkspaceTrustRequestModel {
trustRequest: IWorkspaceTrustRequest | undefined;
private readonly _onDidInitiateRequest = this._register(new Emitter<void>());
readonly onDidInitiateRequest: Event<void> = this._onDidInitiateRequest.event;
private readonly _onDidCompleteRequest = this._register(new Emitter<WorkspaceTrustState | undefined>());
readonly onDidCompleteRequest = this._onDidCompleteRequest.event;
initiateRequest(request: IWorkspaceTrustRequest): void {
if (this.trustRequest && (!request.immediate || this.trustRequest.immediate)) {
return;
}
this.trustRequest = request;
this._onDidInitiateRequest.fire();
}
completeRequest(trustState?: WorkspaceTrustState): void {
this.trustRequest = undefined;
this._onDidCompleteRequest.fire(trustState);
}
}
export class WorkspaceTrustService extends Disposable implements IWorkspaceTrustService {
_serviceBrand: undefined;
private readonly dataModel: IWorkspaceTrustModel;
readonly requestModel: IWorkspaceTrustRequestModel;
private readonly _onDidChangeTrustState = this._register(new Emitter<WorkspaceTrustStateChangeEvent>());
readonly onDidChangeTrustState = this._onDidChangeTrustState.event;
private _currentTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown;
private _inFlightResolver?: (trustState: WorkspaceTrustState) => void;
private _trustRequestPromise?: Promise<WorkspaceTrustState>;
private _workspace: IWorkspace;
private readonly _ctxWorkspaceTrustState: IContextKey<WorkspaceTrustState>;
private readonly _ctxWorkspaceTrustPendingRequest: IContextKey<boolean>;
constructor(
@IConfigurationService readonly configurationService: IConfigurationService,
@IContextKeyService readonly contextKeyService: IContextKeyService,
@IStorageService private readonly storageService: IStorageService,
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
) {
super();
this.dataModel = this._register(new WorkspaceTrustModel(this.storageService));
this.requestModel = this._register(new WorkspaceTrustRequestModel());
this._workspace = this.workspaceService.getWorkspace();
this._currentTrustState = this.calculateWorkspaceTrustState();
this._register(this.dataModel.onDidChangeTrustState(() => this.currentTrustState = this.calculateWorkspaceTrustState()));
this._register(this.requestModel.onDidCompleteRequest((trustState) => this.onTrustRequestCompleted(trustState)));
this._ctxWorkspaceTrustState = WorkspaceTrustContext.TrustState.bindTo(contextKeyService);
this._ctxWorkspaceTrustPendingRequest = WorkspaceTrustContext.PendingRequest.bindTo(contextKeyService);
this._ctxWorkspaceTrustState.set(this.currentTrustState);
}
private get currentTrustState(): WorkspaceTrustState {
return this._currentTrustState;
}
private set currentTrustState(trustState: WorkspaceTrustState) {
if (this._currentTrustState === trustState) { return; }
const previousState = this._currentTrustState;
this._currentTrustState = trustState;
this._onDidChangeTrustState.fire({ previousTrustState: previousState, currentTrustState: this._currentTrustState });
}
private calculateWorkspaceTrustState(): WorkspaceTrustState {
if (!this.isWorkspaceTrustEnabled()) {
return WorkspaceTrustState.Trusted;
}
if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) {
return WorkspaceTrustState.Trusted;
}
let state = undefined;
for (const folder of this._workspace.folders) {
const folderTrust = this.dataModel.getFolderTrustState(folder.uri);
switch (folderTrust) {
case WorkspaceTrustState.Untrusted:
return WorkspaceTrustState.Untrusted;
case WorkspaceTrustState.Unknown:
state = folderTrust;
break;
case WorkspaceTrustState.Trusted:
if (state === undefined) {
state = folderTrust;
}
break;
}
}
return state ?? WorkspaceTrustState.Unknown;
}
private onTrustRequestCompleted(trustState?: WorkspaceTrustState): void {
if (this._inFlightResolver) {
this._inFlightResolver(trustState === undefined ? this.currentTrustState : trustState);
}
this._inFlightResolver = undefined;
this._trustRequestPromise = undefined;
if (trustState === undefined) {
return;
}
this._workspace.folders.forEach(folder => {
this.dataModel.setFolderTrustState(folder.uri, trustState);
});
this._ctxWorkspaceTrustPendingRequest.set(false);
this._ctxWorkspaceTrustState.set(trustState);
}
getWorkspaceTrustState(): WorkspaceTrustState {
return this.currentTrustState;
}
isWorkspaceTrustEnabled(): boolean {
return this.configurationService.getValue<boolean>(WORKSPACE_TRUST_ENABLED) ?? false;
}
async requireWorkspaceTrust(request?: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
if (this.currentTrustState === WorkspaceTrustState.Trusted) {
return this.currentTrustState;
}
if (this.currentTrustState === WorkspaceTrustState.Untrusted && !request?.immediate) {
return this.currentTrustState;
}
if (this._trustRequestPromise) {
if (request?.immediate &&
this.requestModel.trustRequest &&
!this.requestModel.trustRequest.immediate) {
this.requestModel.initiateRequest(request);
}
return this._trustRequestPromise;
}
this._trustRequestPromise = new Promise(resolve => {
this._inFlightResolver = resolve;
});
this.requestModel.initiateRequest(request);
this._ctxWorkspaceTrustPendingRequest.set(true);
return this._trustRequestPromise;
}
}
registerSingleton(IWorkspaceTrustService, WorkspaceTrustService);

View file

@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, WorkspaceTrustChangeEvent, WorkspaceTrustRequestModel, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
import { IWorkspaceTrustRequest, IWorkspaceTrustRequestModel, IWorkspaceTrustService, WorkspaceTrustChangeEvent, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
import { WorkspaceTrustRequestModel } from 'vs/workbench/services/workspaces/common/workspaceTrust';
export class TestWorkspaceTrustService implements IWorkspaceTrustService {
_serviceBrand: undefined;
@ -24,8 +25,4 @@ export class TestWorkspaceTrustService implements IWorkspaceTrustService {
requireWorkspaceTrust(request: IWorkspaceTrustRequest): Promise<WorkspaceTrustState> {
return Promise.resolve(WorkspaceTrustState.Trusted);
}
resetWorkspaceTrust(): Promise<WorkspaceTrustState> {
return Promise.resolve(WorkspaceTrustState.Unknown);
}
}

View file

@ -125,7 +125,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
import { IEnterWorkspaceResult, IRecent, IRecentlyOpened, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceTrustService } from 'vs/platform/workspace/common/workspaceTrust';
import { TestWorkspaceTrustService } from 'vs/platform/workspace/test/common/testWorkspaceTrust';
import { TestWorkspaceTrustService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput {
return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined);

View file

@ -10074,10 +10074,10 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
vscode-debugprotocol@1.44.0:
version "1.44.0"
resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.44.0.tgz#79d11844f908cc5104afc303b3780ad2e5fd486a"
integrity sha512-qf+eBnrDyR2MpP08y1JfzJnFZGHdkk86+SRGRp0XepDGNA6n/Nann5XhtAzdGX/yaZokjTAINK313S2yYhHoPQ==
vscode-debugprotocol@1.45.0-pre.0:
version "1.45.0-pre.0"
resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.45.0-pre.0.tgz#7ea4c6e84d966e96a8398241e46bdf98e0dacfde"
integrity sha512-q0ivFfnjFQyL4Qyxp1K8gSdTpfcvlCxmys5adLydBef1XvDKZNONAKalCZZCyaG/vtOlbV1ma6hS5eALNaLd8w==
vscode-nls-dev@^3.3.1:
version "3.3.1"