mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 09:42:34 -05:00
Merge from vscode 6fded8a497cd0142de3a1c607649a5423a091a25
This commit is contained in:
@@ -35,6 +35,7 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
|
||||
interface AllowedExtension {
|
||||
id: string;
|
||||
name: string;
|
||||
sessionIds?: string[];
|
||||
}
|
||||
|
||||
function readAllowedExtensions(storageService: IStorageService, providerId: string, accountName: string): AllowedExtension[] {
|
||||
@@ -85,6 +86,16 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
quickPick.onDidAccept(() => {
|
||||
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
|
||||
storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
|
||||
|
||||
// Remove sessions of untrusted extensions
|
||||
const deselectedItems = items.filter(item => !quickPick.selectedItems.includes(item));
|
||||
deselectedItems.forEach(item => {
|
||||
const extensionData = allowedExtensions.find(extension => item.extension.id === extension.id);
|
||||
extensionData?.sessionIds?.forEach(sessionId => {
|
||||
this.logout(sessionId);
|
||||
});
|
||||
});
|
||||
|
||||
quickPick.dispose();
|
||||
});
|
||||
|
||||
@@ -275,9 +286,19 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
this.authenticationService.sessionsUpdate(id, event);
|
||||
}
|
||||
|
||||
async $getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
|
||||
let allowList = readAllowedExtensions(this.storageService, providerId, accountName);
|
||||
if (allowList.some(extension => extension.id === extensionId)) {
|
||||
async $getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
|
||||
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
|
||||
const extensionData = allowList.find(extension => extension.id === extensionId);
|
||||
if (extensionData) {
|
||||
if (!extensionData.sessionIds) {
|
||||
extensionData.sessionIds = [];
|
||||
}
|
||||
|
||||
if (!extensionData.sessionIds.find(id => id === sessionId)) {
|
||||
extensionData.sessionIds.push(sessionId);
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -292,7 +313,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
|
||||
const allow = choice === 1;
|
||||
if (allow) {
|
||||
allowList = allowList.concat({ id: extensionId, name: extensionName });
|
||||
allowList.push({ id: extensionId, name: extensionName, sessionIds: [sessionId] });
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
@@ -313,7 +334,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
}
|
||||
|
||||
async $setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void> {
|
||||
const allowList = readAllowedExtensions(this.storageService, providerId, accountName).concat({ id: extensionId, name: extensionName });
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
|
||||
if (!allowList.find(allowed => allowed.id === extensionId)) {
|
||||
allowList.push({ id: extensionId, name: extensionName, sessionIds: [] });
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
resolveWebview: async (webviewInput): Promise<void> => {
|
||||
const viewType = webviewPanelViewType.toExternal(webviewInput.viewType);
|
||||
if (!viewType) {
|
||||
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewInput.viewType);
|
||||
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(webviewInput.viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
|
||||
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -339,7 +339,15 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
webviewInput.webview.options = options;
|
||||
webviewInput.webview.extension = extension;
|
||||
|
||||
let modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
|
||||
let modelRef: IReference<ICustomEditorModel>;
|
||||
try {
|
||||
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cancellation.isCancellationRequested) {
|
||||
modelRef.dispose();
|
||||
return;
|
||||
@@ -362,7 +370,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
await this._proxy.$resolveWebviewEditor(resource, handle, viewType, webviewInput.getTitle(), editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
|
||||
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
modelRef.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -522,14 +531,14 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
return this._webviewInputs.getInputForHandle(handle);
|
||||
}
|
||||
|
||||
private static getDeserializationFailedContents(viewType: string) {
|
||||
private static getWebviewResolvedFailedContent(viewType: string) {
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", escape(viewType))}</body>
|
||||
<body>${localize('errorMessage', "An error occurred while loading view: {0}", escape(viewType))}</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
@@ -795,6 +804,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
|
||||
return undefined;
|
||||
}
|
||||
// TODO: handle save untitled case
|
||||
// TODO: handle cancellation
|
||||
await createCancelablePromise(token => this._proxy.$onSave(this._editorResource, this.viewType, token));
|
||||
this.change(() => {
|
||||
this._savePoint = this._currentEditIndex;
|
||||
@@ -804,7 +814,8 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
|
||||
|
||||
public async saveCustomEditorAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise<boolean> {
|
||||
if (this._editable) {
|
||||
await this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource);
|
||||
// TODO: handle cancellation
|
||||
await createCancelablePromise(token => this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource, token));
|
||||
this.change(() => {
|
||||
this._savePoint = this._currentEditIndex;
|
||||
});
|
||||
|
||||
@@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors));
|
||||
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
|
||||
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
|
||||
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol, extHostStorage));
|
||||
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation, extHostDocuments));
|
||||
|
||||
@@ -585,7 +585,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
},
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomEditorProvider | vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
|
||||
},
|
||||
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
|
||||
},
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
|
||||
@@ -162,7 +162,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
|
||||
$registerAuthenticationProvider(id: string, displayName: string): void;
|
||||
$unregisterAuthenticationProvider(id: string): void;
|
||||
$onDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
|
||||
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
|
||||
$getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
|
||||
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
|
||||
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
|
||||
}
|
||||
@@ -653,7 +653,7 @@ export interface ExtHostWebviewsShape {
|
||||
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void;
|
||||
|
||||
$onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
|
||||
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise<void>;
|
||||
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void>;
|
||||
|
||||
$backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IMainContext, MainContext, MainThreadAuthenticationShape, ExtHostAuthenticationShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
|
||||
export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
private _proxy: MainThreadAuthenticationShape;
|
||||
@@ -20,7 +21,8 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
private _onDidChangeSessions = new Emitter<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }>();
|
||||
readonly onDidChangeSessions: Event<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }> = this._onDidChangeSessions.event;
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
constructor(mainContext: IMainContext,
|
||||
@IExtHostStorage private readonly storageService: IExtHostStorage) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
|
||||
}
|
||||
|
||||
@@ -33,15 +35,34 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
return ids;
|
||||
}
|
||||
|
||||
private async hasNotBeenReadByOtherExtension(providerId: string, session: vscode.AuthenticationSession, extensionId: string): Promise<boolean> {
|
||||
const readerId = await this.storageService.getValue(true, `${providerId}-${session.accountName}-${session.id}`);
|
||||
if (!readerId) {
|
||||
await this.storageService.setValue(true, `${providerId}-${session.accountName}-${session.id}`, extensionId as any);
|
||||
return true;
|
||||
}
|
||||
|
||||
return readerId === extensionId;
|
||||
}
|
||||
|
||||
private async isMatchingSession(session: vscode.AuthenticationSession, scopes: string, providerId: string, extensionId: string): Promise<boolean> {
|
||||
return session.scopes.sort().join(' ') === scopes && (await this.hasNotBeenReadByOtherExtension(providerId, session, extensionId));
|
||||
}
|
||||
|
||||
async getSessions(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<readonly vscode.AuthenticationSession[]> {
|
||||
const provider = this._authenticationProviders.get(providerId);
|
||||
if (!provider) {
|
||||
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
|
||||
}
|
||||
|
||||
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
|
||||
const orderedScopes = scopes.sort().join(' ');
|
||||
return (await provider.getSessions())
|
||||
.filter(session => session.scopes.sort().join(' ') === orderedScopes)
|
||||
|
||||
const sessions = await provider.getSessions();
|
||||
const filteredSessions = await Promise.all(sessions.map(session => this.isMatchingSession(session, orderedScopes, providerId, extensionId)));
|
||||
|
||||
return sessions
|
||||
.filter((_, i) => { return filteredSessions[i]; })
|
||||
.map(session => {
|
||||
return {
|
||||
id: session.id,
|
||||
@@ -51,8 +72,9 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
provider.id,
|
||||
session.accountName,
|
||||
session.id,
|
||||
provider.displayName,
|
||||
ExtensionIdentifier.toKey(requestingExtension.identifier),
|
||||
extensionId,
|
||||
requestingExtension.displayName || requestingExtension.name);
|
||||
|
||||
if (!isAllowed) {
|
||||
@@ -77,9 +99,28 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
throw new Error('User did not consent to login.');
|
||||
}
|
||||
|
||||
const newSession = await provider.login(scopes);
|
||||
await this._proxy.$setTrustedExtension(provider.id, newSession.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
|
||||
return newSession;
|
||||
const session = await provider.login(scopes);
|
||||
await this._proxy.$setTrustedExtension(provider.id, session.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
|
||||
return {
|
||||
id: session.id,
|
||||
accountName: session.accountName,
|
||||
scopes: session.scopes,
|
||||
getAccessToken: async () => {
|
||||
const isAllowed = await this._proxy.$getSessionsPrompt(
|
||||
provider.id,
|
||||
session.accountName,
|
||||
session.id,
|
||||
provider.displayName,
|
||||
ExtensionIdentifier.toKey(requestingExtension.identifier),
|
||||
requestingExtension.displayName || requestingExtension.name);
|
||||
|
||||
if (!isAllowed) {
|
||||
throw new Error('User did not consent to token access.');
|
||||
}
|
||||
|
||||
return session.getAccessToken();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {
|
||||
|
||||
@@ -402,11 +402,12 @@ export class NotebookEditorCellEdit {
|
||||
}
|
||||
}
|
||||
|
||||
insert(index: number, content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
|
||||
insert(index: number, content: string | string[], language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
|
||||
this._throwIfFinalized();
|
||||
|
||||
const sourceArr = Array.isArray(content) ? content : content.split(/\r|\n|\r\n/g);
|
||||
let cell = {
|
||||
source: [content],
|
||||
source: sourceArr,
|
||||
language,
|
||||
cellKind: type,
|
||||
outputs: (outputs as any[]), // TODO@rebornix
|
||||
|
||||
@@ -16,7 +16,7 @@ import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/p
|
||||
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import type * as vscode from 'vscode';
|
||||
import { Cache } from './cache';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { assertIsDefined, isStringArray } from 'vs/base/common/types';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
function es5ClassCompat(target: Function): any {
|
||||
@@ -2420,25 +2420,14 @@ export class SemanticTokensLegend {
|
||||
public readonly tokenTypes: string[];
|
||||
public readonly tokenModifiers: string[];
|
||||
|
||||
constructor(tokenTypes: string[], tokenModifiers: string[]) {
|
||||
constructor(tokenTypes: string[], tokenModifiers: string[] = []) {
|
||||
this.tokenTypes = tokenTypes;
|
||||
this.tokenModifiers = tokenModifiers;
|
||||
}
|
||||
}
|
||||
|
||||
function isStrArrayOrUndefined(arg: any): arg is string[] | undefined {
|
||||
if (typeof arg === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
if (Array.isArray(arg)) {
|
||||
for (const element of arg) {
|
||||
if (typeof element !== 'string') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return ((typeof arg === 'undefined') || isStringArray(arg));
|
||||
}
|
||||
|
||||
export class SemanticTokensBuilder {
|
||||
@@ -2472,10 +2461,13 @@ export class SemanticTokensBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void;
|
||||
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void;
|
||||
public push(range: Range, tokenType: string, tokenModifiers?: string[]): void;
|
||||
public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
|
||||
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'number') {
|
||||
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) {
|
||||
if (typeof arg4 === 'undefined') {
|
||||
arg4 = 0;
|
||||
}
|
||||
// 1st overload
|
||||
return this._pushEncoded(arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
|
||||
@@ -630,10 +630,10 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
return delegate.save(document, cancellation);
|
||||
}
|
||||
|
||||
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise<void> {
|
||||
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void> {
|
||||
const delegate = this.getEditingDelegate(viewType);
|
||||
const document = this.getCustomDocument(viewType, resourceComponents);
|
||||
return delegate.saveAs(document, URI.revive(targetResource));
|
||||
return delegate.saveAs(document, URI.revive(targetResource), cancellation);
|
||||
}
|
||||
|
||||
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
|
||||
@@ -41,10 +41,10 @@ namespace schema {
|
||||
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
|
||||
case 'scm/title': return MenuId.SCMTitle;
|
||||
case 'scm/sourceControl': return MenuId.SCMSourceControl;
|
||||
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
|
||||
case 'scm/resourceState/context': return MenuId.SCMResourceContext;//
|
||||
case 'scm/resourceFolder/context': return MenuId.SCMResourceFolderContext;
|
||||
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
|
||||
case 'scm/change/title': return MenuId.SCMChangeContext;
|
||||
case 'scm/change/title': return MenuId.SCMChangeContext;//
|
||||
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
|
||||
case 'view/title': return MenuId.ViewTitle;
|
||||
case 'view/item/context': return MenuId.ViewItemContext;
|
||||
@@ -171,6 +171,11 @@ namespace schema {
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'menuBar/webNavigation': {
|
||||
description: localize('menus.webNavigation', "The top level navigational menu (web only)"),
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'scm/title': {
|
||||
description: localize('menus.scmTitle', "The Source Control title menu"),
|
||||
type: 'array',
|
||||
@@ -191,6 +196,16 @@ namespace schema {
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'scm/resourceFolder/context': {
|
||||
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu"),
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'scm/change/title': {
|
||||
description: localize('menus.changeTitle', "The Source Control inline change menu"),
|
||||
type: 'array',
|
||||
items: menuItem
|
||||
},
|
||||
'view/title': {
|
||||
description: localize('view.viewTitle', "The contributed view title menu"),
|
||||
type: 'array',
|
||||
|
||||
Reference in New Issue
Block a user