bring Azure context menu to the new tree and enhance start cloud shell command (#13101)

* bring context menu to the new tree

* enhance start cloud shell command

* text
This commit is contained in:
Alan Ren
2020-10-28 13:48:28 -07:00
committed by GitHub
parent 281592fa97
commit 1d4398388c
3 changed files with 86 additions and 38 deletions

View File

@@ -282,6 +282,16 @@
"command": "azure.resource.refresh", "command": "azure.resource.refresh",
"when": "contextValue == azure.resource.itemType.account", "when": "contextValue == azure.resource.itemType.account",
"group": "navigation" "group": "navigation"
},
{
"command": "azure.resource.signin",
"when": "treeId == connectionDialog/azureResourceExplorer",
"group": "navigation"
},
{
"command": "azure.resource.refreshall",
"when": "treeId == connectionDialog/azureResourceExplorer",
"group": "navigation"
} }
] ]
}, },

View File

@@ -30,13 +30,34 @@ export function registerAzureResourceCommands(appContext: AppContext, trees: (Az
vscode.window.showInformationMessage(msg); vscode.window.showInformationMessage(msg);
return; return;
} }
if (!node || !(node instanceof AzureResourceAccountTreeNode)) { let azureAccount: AzureAccount | undefined;
if (node instanceof AzureResourceAccountTreeNode) {
azureAccount = node.account as AzureAccount;
} else {
let accounts = await azdata.accounts.getAllAccounts();
accounts = accounts.filter(a => a.key.providerId.startsWith('azure'));
if (accounts.length === 0) {
const signin = localize('azure.signIn', "Sign in");
const action = await vscode.window.showErrorMessage(localize('azure.noAccountError', "You are not currently signed into any Azure accounts, Please sign in and then try again."),
signin);
if (action === signin) {
vscode.commands.executeCommand('azure.resource.signin');
}
return;
} else if (accounts.length === 1) {
azureAccount = accounts[0];
} else {
const pickedAccount = await vscode.window.showQuickPick(accounts.map(account => account.displayInfo.displayName), {
canPickMany: false,
placeHolder: localize('azure.pickAnAzureAccount', "Select an Azure account")
});
if (!pickedAccount) {
vscode.window.showErrorMessage(localize('azure.accountNotSelectedError', "You must select an Azure account for this feature to work."));
return; return;
} }
azureAccount = accounts.find(acct => acct.displayInfo.displayName === pickedAccount);
const accountNode = node as AzureResourceAccountTreeNode; }
const azureAccount = accountNode.account as AzureAccount; }
const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService); const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService);

View File

@@ -47,7 +47,7 @@ import { IAction } from 'vs/base/common/actions';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
export type TreeElement = ConnectionProviderElement | ITreeItemFromProvider | SavedConnectionNode | ServerTreeElement; export type TreeElement = ConnectionDialogTreeProviderElement | ITreeItemFromProvider | SavedConnectionNode | ServerTreeElement;
export class ConnectionBrowseTab implements IPanelTab { export class ConnectionBrowseTab implements IPanelTab {
public readonly title = localize('connectionDialog.browser', "Browse"); public readonly title = localize('connectionDialog.browser', "Browse");
@@ -156,9 +156,17 @@ export class ConnectionBrowserView extends Disposable implements IPanelView {
accessibilityProvider: new ListAccessibilityProvider() accessibilityProvider: new ListAccessibilityProvider()
}) as WorkbenchAsyncDataTree<TreeModel, TreeElement>); }) as WorkbenchAsyncDataTree<TreeModel, TreeElement>);
this._register(this.tree.onContextMenu(e => { this._register(this.tree.onContextMenu(e => {
const context = e.element as ITreeItemFromProvider; let context: ITreeItem | ConnectionDialogTreeProviderElement | undefined;
if (context?.element) { let actionContext: TreeViewItemHandleArg | ConnectionDialogTreeProviderElement | undefined;
this.contextKey.set(context.element); if (instanceOfITreeItemFromProvider(e.element)) {
context = e.element.element;
actionContext = <TreeViewItemHandleArg>{ $treeViewId: e.element.treeId, $treeItemHandle: context.handle, $treeItem: context };
} else if (e.element instanceof ConnectionDialogTreeProviderElement) {
context = e.element;
actionContext = e.element;
}
if (context) {
this.contextKey.set(context);
const menu = this.menuService.createMenu(MenuId.ConnectionDialogBrowseTreeContext, this.contextKeyService); const menu = this.menuService.createMenu(MenuId.ConnectionDialogBrowseTreeContext, this.contextKeyService);
const primary: IAction[] = []; const primary: IAction[] = [];
const secondary: IAction[] = []; const secondary: IAction[] = [];
@@ -168,7 +176,7 @@ export class ConnectionBrowserView extends Disposable implements IPanelView {
this.contextMenuService.showContextMenu({ this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor, getAnchor: () => e.anchor,
getActions: () => result.primary, getActions: () => result.primary,
getActionsContext: () => (<TreeViewItemHandleArg>{ $treeViewId: context.treeId, $treeItemHandle: context.element.handle, $treeItem: context.element }) getActionsContext: () => actionContext
}); });
} }
})); }));
@@ -239,7 +247,11 @@ export interface ITreeItemFromProvider {
getChildren?(): Promise<ITreeItemFromProvider[]> getChildren?(): Promise<ITreeItemFromProvider[]>
} }
class ConnectionProviderElement { export function instanceOfITreeItemFromProvider(obj: any): obj is ITreeItemFromProvider {
return !!(<ITreeItemFromProvider>obj)?.element;
}
class ConnectionDialogTreeProviderElement {
public readonly id = this.descriptor.id; public readonly id = this.descriptor.id;
public readonly name = this.descriptor.name; public readonly name = this.descriptor.name;
@@ -262,7 +274,7 @@ class ListDelegate implements IListVirtualDelegate<TreeElement> {
} }
getTemplateId(element: TreeElement): string { getTemplateId(element: TreeElement): string {
if (element instanceof ConnectionProviderElement) { if (element instanceof ConnectionDialogTreeProviderElement) {
return ProviderElementRenderer.TEMPLATE_ID; return ProviderElementRenderer.TEMPLATE_ID;
} else if (element instanceof ConnectionProfile) { } else if (element instanceof ConnectionProfile) {
return ServerTreeRenderer.CONNECTION_TEMPLATE_ID; return ServerTreeRenderer.CONNECTION_TEMPLATE_ID;
@@ -283,7 +295,7 @@ interface ProviderElementTemplate {
readonly name: HTMLElement; readonly name: HTMLElement;
} }
class ProviderElementRenderer implements ITreeRenderer<ConnectionProviderElement, void, ProviderElementTemplate> { class ProviderElementRenderer implements ITreeRenderer<ConnectionDialogTreeProviderElement, void, ProviderElementTemplate> {
public static readonly TEMPLATE_ID = 'ProviderElementTemplate'; public static readonly TEMPLATE_ID = 'ProviderElementTemplate';
public readonly templateId = ProviderElementRenderer.TEMPLATE_ID; public readonly templateId = ProviderElementRenderer.TEMPLATE_ID;
@@ -293,7 +305,7 @@ class ProviderElementRenderer implements ITreeRenderer<ConnectionProviderElement
return { name, icon }; return { name, icon };
} }
renderElement(element: ITreeNode<ConnectionProviderElement, void>, index: number, templateData: ProviderElementTemplate, height: number): void { renderElement(element: ITreeNode<ConnectionDialogTreeProviderElement, void>, index: number, templateData: ProviderElementTemplate, height: number): void {
templateData.name.innerText = element.element.name; templateData.name.innerText = element.element.name;
} }
@@ -306,7 +318,7 @@ interface SavedConnectionNodeElementTemplate {
readonly name: HTMLElement; readonly name: HTMLElement;
} }
class SavedConnectionsNodeRenderer implements ITreeRenderer<ConnectionProviderElement, void, SavedConnectionNodeElementTemplate> { class SavedConnectionsNodeRenderer implements ITreeRenderer<ConnectionDialogTreeProviderElement, void, SavedConnectionNodeElementTemplate> {
public static readonly TEMPLATE_ID = 'savedConnectionNode'; public static readonly TEMPLATE_ID = 'savedConnectionNode';
public readonly templateId = SavedConnectionsNodeRenderer.TEMPLATE_ID; public readonly templateId = SavedConnectionsNodeRenderer.TEMPLATE_ID;
@@ -316,7 +328,7 @@ class SavedConnectionsNodeRenderer implements ITreeRenderer<ConnectionProviderEl
return { name, icon }; return { name, icon };
} }
renderElement(element: ITreeNode<ConnectionProviderElement, void>, index: number, templateData: SavedConnectionNodeElementTemplate, height: number): void { renderElement(element: ITreeNode<ConnectionDialogTreeProviderElement, void>, index: number, templateData: SavedConnectionNodeElementTemplate, height: number): void {
templateData.name.innerText = localize('savedConnections', "Saved Connections"); templateData.name.innerText = localize('savedConnections', "Saved Connections");
} }
@@ -326,7 +338,7 @@ class SavedConnectionsNodeRenderer implements ITreeRenderer<ConnectionProviderEl
class IdentityProvider implements IIdentityProvider<TreeElement> { class IdentityProvider implements IIdentityProvider<TreeElement> {
getId(element: TreeElement): string { getId(element: TreeElement): string {
if (element instanceof ConnectionProviderElement) { if (element instanceof ConnectionDialogTreeProviderElement) {
return element.id; return element.id;
} else if (element instanceof ConnectionProfile) { } else if (element instanceof ConnectionProfile) {
return element.id; return element.id;
@@ -353,7 +365,7 @@ class TreeModel {
getChildren(): TreeElement[] { getChildren(): TreeElement[] {
this._savedConnectionNode = this.instantiationService.createInstance(SavedConnectionNode); this._savedConnectionNode = this.instantiationService.createInstance(SavedConnectionNode);
const descriptors = Array.from(this.connectionTreeService.descriptors); const descriptors = Array.from(this.connectionTreeService.descriptors);
return [this._savedConnectionNode, ...Iterable.map(this.connectionTreeService.providers, ([id, provider]) => new ConnectionProviderElement(provider, descriptors.find(i => i.id === id)))]; return [this._savedConnectionNode, ...Iterable.map(this.connectionTreeService.providers, ([id, provider]) => new ConnectionDialogTreeProviderElement(provider, descriptors.find(i => i.id === id)))];
} }
public get savedConnectionNode(): SavedConnectionNode | undefined { public get savedConnectionNode(): SavedConnectionNode | undefined {
@@ -363,7 +375,7 @@ class TreeModel {
class ListAccessibilityProvider implements IListAccessibilityProvider<TreeElement> { class ListAccessibilityProvider implements IListAccessibilityProvider<TreeElement> {
getAriaLabel(element: TreeElement): string { getAriaLabel(element: TreeElement): string {
if (element instanceof ConnectionProviderElement) { if (element instanceof ConnectionDialogTreeProviderElement) {
return element.name; return element.name;
} else if (element instanceof ConnectionProfile) { } else if (element instanceof ConnectionProfile) {
return element.serverName; return element.serverName;
@@ -394,7 +406,7 @@ class DataSource implements IAsyncDataSource<TreeModel, TreeElement> {
hasChildren(element: TreeModel | TreeElement): boolean { hasChildren(element: TreeModel | TreeElement): boolean {
if (element instanceof TreeModel) { if (element instanceof TreeModel) {
return true; return true;
} else if (element instanceof ConnectionProviderElement) { } else if (element instanceof ConnectionDialogTreeProviderElement) {
return true; return true;
} else if (element instanceof ConnectionProfile) { } else if (element instanceof ConnectionProfile) {
return false; return false;
@@ -413,12 +425,7 @@ class DataSource implements IAsyncDataSource<TreeModel, TreeElement> {
public get expandableTreeNodes(): TreeElement[] { public get expandableTreeNodes(): TreeElement[] {
return this.treeNodes.filter(node => { return this.treeNodes.filter(node => {
return node instanceof TreeModel return instanceOfITreeItemFromProvider(node) && node.element.collapsibleState !== TreeItemCollapsibleState.None;
|| node instanceof SavedConnectionNode
|| node instanceof ConnectionProfileGroup
|| node instanceof TreeNode
|| node instanceof ConnectionProviderElement
|| (!(node instanceof ConnectionProfile) && node.element.collapsibleState !== TreeItemCollapsibleState.None);
}); });
} }
@@ -436,7 +443,7 @@ class DataSource implements IAsyncDataSource<TreeModel, TreeElement> {
} else if ( } else if (
!(element instanceof TreeModel) && !(element instanceof TreeModel) &&
!(element instanceof TreeNode) && !(element instanceof TreeNode) &&
!(element instanceof ConnectionProviderElement) !(element instanceof ConnectionDialogTreeProviderElement)
) { ) {
children = (children as ITreeItemFromProvider[]).filter(item => { children = (children as ITreeItemFromProvider[]).filter(item => {
return item.element.collapsibleState !== TreeItemCollapsibleState.None || this._filterRegex.test(item.element.label.label); return item.element.collapsibleState !== TreeItemCollapsibleState.None || this._filterRegex.test(item.element.label.label);
@@ -599,26 +606,36 @@ class TreeItemRenderer extends Disposable implements ITreeRenderer<ITreeItemFrom
} }
} }
class ContextKey extends Disposable implements IContextKey<ITreeItem> { type ContextValueType = ITreeItem | ConnectionDialogTreeProviderElement;
static readonly ContextValue = new RawContextKey<string>('contextValue', undefined);
static readonly Item = new RawContextKey<ITreeItem>('item', undefined); class ContextKey extends Disposable implements IContextKey<ContextValueType> {
private _contextValueKey: IContextKey<string>; static readonly ContextValue = new RawContextKey<string | undefined>('contextValue', undefined);
private _itemKey: IContextKey<ITreeItem>; static readonly TreeId = new RawContextKey<string | undefined>('treeId', undefined);
private _contextValueKey: IContextKey<string | undefined>;
private _treeIdKey: IContextKey<string | undefined>;
private _item: ContextValueType;
constructor( constructor(
@IContextKeyService contextKeyService: IContextKeyService @IContextKeyService contextKeyService: IContextKeyService
) { ) {
super(); super();
this._contextValueKey = ContextKey.ContextValue.bindTo(contextKeyService); this._contextValueKey = ContextKey.ContextValue.bindTo(contextKeyService);
this._itemKey = ContextKey.Item.bindTo(contextKeyService); this._treeIdKey = ContextKey.TreeId.bindTo(contextKeyService);
} }
set(value: ITreeItem): void { set(value: ContextValueType): void {
this.reset();
this._item = value;
if (value instanceof ConnectionDialogTreeProviderElement) {
this._treeIdKey.set(value.id);
} else {
this._contextValueKey.set(value.contextValue); this._contextValueKey.set(value.contextValue);
} }
}
reset(): void { reset(): void {
this._contextValueKey.reset(); this._contextValueKey.reset();
this._treeIdKey.reset();
} }
get(): ITreeItem { get(): ContextValueType {
return this._itemKey.get(); return this._item;
} }
} }