mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Open in azure portal (#10535)
* initial commit to get it working * Change configuration to use package.nls.json * Make the necessary plumbing * Support multi cloud * Move the menu item to the bottom * Fix failing tests * Fix the tests
This commit is contained in:
@@ -151,6 +151,10 @@
|
||||
"light": "resources/light/console.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.openInAzurePortal",
|
||||
"title": "%azure.openInAzurePortal.title%"
|
||||
},
|
||||
{
|
||||
"command": "azure.resource.connectsqlserver",
|
||||
"title": "%azure.resource.connectsqlserver.title%",
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
"azure.accounts.getSubscriptions.title": "Get Azure Account Subscriptions",
|
||||
"azure.accounts.getResourceGroups.title": "Get Azure Account Subscription Resource Groups",
|
||||
|
||||
"azure.openInAzurePortal.title": "Open in Azure Portal",
|
||||
|
||||
"config.azureAccountConfigurationSection": "Azure Account Configuration",
|
||||
"config.enablePublicCloudDescription": "Should Azure public cloud integration be enabled",
|
||||
"config.enableUsGovCloudDescription": "Should US Government Azure cloud (Fairfax) integration be enabled",
|
||||
|
||||
@@ -118,6 +118,8 @@ interface Settings {
|
||||
redirectUri?: string;
|
||||
|
||||
scopes?: string[]
|
||||
|
||||
portalEndpoint?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,7 +52,8 @@ const publicAzureSettings: ProviderSettings = {
|
||||
scopes: [
|
||||
'openid', 'email', 'profile', 'offline_access',
|
||||
'https://management.azure.com/user_impersonation',
|
||||
]
|
||||
],
|
||||
portalEndpoint: 'https://portal.azure.com'
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -101,7 +102,8 @@ const usGovAzureSettings: ProviderSettings = {
|
||||
scopes: [
|
||||
'openid', 'email', 'profile', 'offline_access',
|
||||
'https://management.usgovcloudapi.net/user_impersonation'
|
||||
]
|
||||
],
|
||||
portalEndpoint: 'https://portal.azure.us'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@ export namespace azureResource {
|
||||
export interface AzureResource {
|
||||
name: string;
|
||||
id: string;
|
||||
tenant?: string;
|
||||
}
|
||||
|
||||
export interface AzureResourceSubscription extends AzureResource {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
import { window, QuickPickItem } from 'vscode';
|
||||
import { window, QuickPickItem, env, Uri } from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import { TokenCredentials } from '@azure/ms-rest-js';
|
||||
import * as nls from 'vscode-nls';
|
||||
@@ -237,4 +237,23 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
|
||||
appContext.apiWrapper.executeCommand('workbench.view.connections');
|
||||
}
|
||||
});
|
||||
|
||||
appContext.apiWrapper.registerCommand('azure.resource.openInAzurePortal', async (node?: TreeNode) => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
const treeItem: azdata.TreeItem = await node.getTreeItem();
|
||||
if (!treeItem.payload) {
|
||||
return;
|
||||
}
|
||||
let connectionProfile = Object.assign({}, treeItem.payload, { saveProfile: true });
|
||||
|
||||
if (!connectionProfile.azureResourceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const urlToOpen = `${connectionProfile.azurePortalEndpoint}//${connectionProfile.azureTenantId}/#resource/${connectionProfile.azureResourceId}`;
|
||||
env.openExternal(Uri.parse(urlToOpen));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ export class AzureResourceDatabaseService implements IAzureResourceService<azure
|
||||
id: db.id,
|
||||
serverName: server.name,
|
||||
serverFullName: server.properties.fullyQualifiedDomainName,
|
||||
loginName: server.properties.administratorLogin
|
||||
loginName: server.properties.administratorLogin,
|
||||
tenant: db.tenantId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,10 @@ export class AzureResourceDatabaseTreeDataProvider extends ResourceTreeDataProvi
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
options: {},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureResourceId: database.id,
|
||||
azureTenantId: database.tenant,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'MSSQL',
|
||||
type: ExtensionNodeType.Database
|
||||
|
||||
@@ -29,7 +29,8 @@ export class AzureResourceDatabaseServerService extends ResourceServiceBase<DbSe
|
||||
name: resource.name,
|
||||
fullName: resource.properties.fullyQualifiedDomainName,
|
||||
loginName: resource.properties.administratorLogin,
|
||||
defaultDatabaseName: 'master'
|
||||
defaultDatabaseName: 'master',
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,10 @@ export class AzureResourceDatabaseServerTreeDataProvider extends ResourceTreeDat
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
options: {},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureTenantId: databaseServer.tenant,
|
||||
azureResourceId: databaseServer.id,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'MSSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
|
||||
@@ -26,7 +26,8 @@ export class PostgresServerArcService extends ResourceServiceBase<PostgresArcSer
|
||||
name: resource.name,
|
||||
fullName: resource.name,
|
||||
loginName: resource.properties.admin,
|
||||
defaultDatabaseName: 'postgres'
|
||||
defaultDatabaseName: 'postgres',
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,10 @@ export class PostgresServerArcTreeDataProvider extends ResourceTreeDataProviderB
|
||||
// Set default for SSL or will get error complaining about it not being set correctly
|
||||
'sslmode': 'require'
|
||||
},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureTenantId: databaseServer.tenant,
|
||||
azureResourceId: databaseServer.id,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'PGSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
|
||||
@@ -29,7 +29,8 @@ export class PostgresServerService extends ResourceServiceBase<DbServerGraphData
|
||||
name: resource.name,
|
||||
fullName: resource.properties.fullyQualifiedDomainName,
|
||||
loginName: resource.properties.administratorLogin,
|
||||
defaultDatabaseName: 'postgres'
|
||||
defaultDatabaseName: 'postgres',
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,10 @@ export class PostgresServerTreeDataProvider extends ResourceTreeDataProviderBase
|
||||
// Set default for SSL or will get error complaining about it not being set correctly
|
||||
'sslmode': 'require'
|
||||
},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureTenantId: databaseServer.tenant,
|
||||
azureResourceId: databaseServer.id,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'PGSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
|
||||
@@ -58,6 +58,7 @@ export abstract class ResourceTreeDataProviderBase<T extends azureResource.Azure
|
||||
}
|
||||
|
||||
export interface GraphData {
|
||||
tenantId: string;
|
||||
id: string;
|
||||
name: string;
|
||||
location: string;
|
||||
|
||||
@@ -27,7 +27,8 @@ export class SqlInstanceResourceService extends ResourceServiceBase<SqlInstanceG
|
||||
name: resource.name,
|
||||
fullName: resource.properties.fullyQualifiedDomainName,
|
||||
loginName: resource.properties.administratorLogin,
|
||||
defaultDatabaseName: 'master'
|
||||
defaultDatabaseName: 'master',
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,10 @@ export class SqlInstanceTreeDataProvider extends ResourceTreeDataProviderBase<az
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
options: {},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureTenantId: databaseServer.tenant,
|
||||
azureResourceId: databaseServer.id,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'MSSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
|
||||
@@ -26,7 +26,8 @@ export class SqlInstanceArcResourceService extends ResourceServiceBase<SqlInstan
|
||||
name: resource.name,
|
||||
fullName: resource.name,
|
||||
loginName: resource.properties.admin,
|
||||
defaultDatabaseName: 'master'
|
||||
defaultDatabaseName: 'master',
|
||||
tenant: resource.tenantId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,10 @@ export class SqlInstanceArcTreeDataProvider extends ResourceTreeDataProviderBase
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
options: {},
|
||||
azureAccount: account.key.accountId
|
||||
azureAccount: account.key.accountId,
|
||||
azureTenantId: databaseServer.tenant,
|
||||
azureResourceId: databaseServer.id,
|
||||
azurePortalEndpoint: account.properties.providerSettings.settings.portalEndpoint
|
||||
},
|
||||
childProvider: 'MSSQL',
|
||||
type: ExtensionNodeType.Server
|
||||
|
||||
@@ -14,6 +14,8 @@ import { ApiWrapper } from '../../../../apiWrapper';
|
||||
import { AzureResourceDatabaseTreeDataProvider } from '../../../../azureResource/providers/database/databaseTreeDataProvider';
|
||||
import { AzureResourceItemType } from '../../../../azureResource/constants';
|
||||
import { IAzureResourceService } from '../../../../azureResource/interfaces';
|
||||
import { AzureAccount } from '../../../../account-provider/interfaces';
|
||||
import settings from '../../../../account-provider/providerSettings';
|
||||
|
||||
// Mock services
|
||||
let mockDatabaseService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabase>>;
|
||||
@@ -21,7 +23,7 @@ let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
|
||||
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
|
||||
|
||||
// Mock test data
|
||||
const mockAccount: azdata.Account = {
|
||||
const mockAccount: AzureAccount = {
|
||||
key: {
|
||||
accountId: 'mock_account',
|
||||
providerId: 'mock_provider'
|
||||
@@ -32,7 +34,11 @@ const mockAccount: azdata.Account = {
|
||||
contextualDisplayName: 'test',
|
||||
userId: 'test@email.com'
|
||||
},
|
||||
properties: undefined,
|
||||
properties: {
|
||||
providerSettings: settings[0].metadata,
|
||||
isMsAccount: true,
|
||||
tenants: []
|
||||
},
|
||||
isStale: false
|
||||
};
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@ import { IAzureResourceService } from '../../../../azureResource/interfaces';
|
||||
let mockDatabaseServerService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>;
|
||||
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
|
||||
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
|
||||
import settings from '../../../../account-provider/providerSettings';
|
||||
import { AzureAccount } from '../../../../account-provider/interfaces';
|
||||
|
||||
// Mock test data
|
||||
const mockAccount: azdata.Account = {
|
||||
const mockAccount: AzureAccount = {
|
||||
key: {
|
||||
accountId: 'mock_account',
|
||||
providerId: 'mock_provider'
|
||||
@@ -32,7 +34,11 @@ const mockAccount: azdata.Account = {
|
||||
contextualDisplayName: 'test',
|
||||
userId: 'test@email.com'
|
||||
},
|
||||
properties: undefined,
|
||||
properties: {
|
||||
providerSettings: settings[0].metadata,
|
||||
isMsAccount: true,
|
||||
tenants: []
|
||||
},
|
||||
isStale: false
|
||||
};
|
||||
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as azdata from 'azdata';
|
||||
import 'mocha';
|
||||
import { fail } from 'assert';
|
||||
|
||||
import { azureResource } from '../../azureResource/azure-resource';
|
||||
import { AzureResourceService } from '../../azureResource/resourceService';
|
||||
import { AzureAccount } from '../../account-provider/interfaces';
|
||||
import settings from '../../account-provider/providerSettings';
|
||||
|
||||
// Mock test data
|
||||
const mockAccount: azdata.Account = {
|
||||
const mockAccount: AzureAccount = {
|
||||
key: {
|
||||
accountId: 'mock_account',
|
||||
providerId: 'mock_provider'
|
||||
@@ -24,7 +25,11 @@ const mockAccount: azdata.Account = {
|
||||
contextualDisplayName: 'test',
|
||||
userId: 'test@email.com'
|
||||
},
|
||||
properties: undefined,
|
||||
properties: {
|
||||
providerSettings: settings[0].metadata,
|
||||
isMsAccount: true,
|
||||
tenants: []
|
||||
},
|
||||
isStale: false
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import 'mocha';
|
||||
|
||||
@@ -15,9 +14,11 @@ import { AzureResourceResourceTreeNode } from '../../azureResource/resourceTreeN
|
||||
import { AppContext } from '../../appContext';
|
||||
import { ApiWrapper } from '../../apiWrapper';
|
||||
import { AzureResourceServiceNames } from '../../azureResource/constants';
|
||||
import settings from '../../account-provider/providerSettings';
|
||||
import { AzureAccount } from '../../account-provider/interfaces';
|
||||
|
||||
// Mock test data
|
||||
const mockAccount: azdata.Account = {
|
||||
const mockAccount: AzureAccount = {
|
||||
key: {
|
||||
accountId: 'mock_account',
|
||||
providerId: 'mock_provider'
|
||||
@@ -28,7 +29,11 @@ const mockAccount: azdata.Account = {
|
||||
contextualDisplayName: 'test',
|
||||
userId: 'test@email.com'
|
||||
},
|
||||
properties: undefined,
|
||||
properties: {
|
||||
providerSettings: settings[0].metadata,
|
||||
isMsAccount: true,
|
||||
tenants: []
|
||||
},
|
||||
isStale: false
|
||||
};
|
||||
|
||||
|
||||
1
src/sql/azdata.d.ts
vendored
1
src/sql/azdata.d.ts
vendored
@@ -333,6 +333,7 @@ declare module 'azdata' {
|
||||
saveProfile: boolean;
|
||||
id: string;
|
||||
azureTenantId?: string;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
src/sql/azdata.proposed.d.ts
vendored
2
src/sql/azdata.proposed.d.ts
vendored
@@ -111,6 +111,8 @@ declare module 'azdata' {
|
||||
*/
|
||||
export interface IConnectionProfile extends ConnectionInfo {
|
||||
azureAccount?: string;
|
||||
azureResourceId?: string;
|
||||
azurePortalEndpoint?: string;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { MssqlNodeContext } from 'sql/workbench/services/objectExplorer/browser/mssqlNodeContext';
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, {
|
||||
group: 'z-azurecore',
|
||||
order: 1,
|
||||
command: {
|
||||
id: 'azure.resource.openInAzurePortal',
|
||||
title: localize('azure.openInAzurePortal.title', "Open in Azure Portal")
|
||||
},
|
||||
when: MssqlNodeContext.CanOpenInAzurePortal
|
||||
});
|
||||
|
||||
@@ -34,6 +34,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
static NodeType = new RawContextKey<string>('nodeType', undefined);
|
||||
static NodeLabel = new RawContextKey<string>('nodeLabel', undefined);
|
||||
static EngineEdition = new RawContextKey<number>('engineEdition', DatabaseEngineEdition.Unknown);
|
||||
static CanOpenInAzurePortal = new RawContextKey<boolean>('canOpenInAzurePortal', false);
|
||||
|
||||
// Scripting context keys
|
||||
static CanScriptAsSelect = new RawContextKey<boolean>('canScriptAsSelect', false);
|
||||
@@ -48,6 +49,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
private nodeLabelKey: IContextKey<string>;
|
||||
private isDatabaseOrServerKey: IContextKey<boolean>;
|
||||
private engineEditionKey: IContextKey<number>;
|
||||
private canOpenInAzurePortal: IContextKey<boolean>;
|
||||
|
||||
private canScriptAsSelectKey: IContextKey<boolean>;
|
||||
private canEditDataKey: IContextKey<boolean>;
|
||||
@@ -71,6 +73,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
this.setNodeProvider();
|
||||
this.setIsCloud();
|
||||
this.setEngineEdition();
|
||||
this.setCanOpenInPortal();
|
||||
if (node.type) {
|
||||
this.setIsDatabaseOrServer();
|
||||
this.nodeTypeKey.set(node.type);
|
||||
@@ -98,6 +101,7 @@ export class MssqlNodeContext extends Disposable {
|
||||
this.canScriptAsExecuteKey = MssqlNodeContext.CanScriptAsExecute.bindTo(this.contextKeyService);
|
||||
this.canScriptAsAlterKey = MssqlNodeContext.CanScriptAsAlter.bindTo(this.contextKeyService);
|
||||
this.nodeProviderKey = MssqlNodeContext.NodeProvider.bindTo(this.contextKeyService);
|
||||
this.canOpenInAzurePortal = MssqlNodeContext.CanOpenInAzurePortal.bindTo(this.contextKeyService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,6 +125,16 @@ export class MssqlNodeContext extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private setCanOpenInPortal(): void {
|
||||
const connectionProfile = this.nodeContextValue.node.payload;
|
||||
if (connectionProfile &&
|
||||
connectionProfile.azureResourceId &&
|
||||
connectionProfile.azureTenantId &&
|
||||
connectionProfile.azurePortalEndpoint) {
|
||||
this.canOpenInAzurePortal.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set engine edition
|
||||
*/
|
||||
|
||||
@@ -469,4 +469,7 @@ import 'sql/workbench/contrib/resourceDeployment/browser/resourceDeployment.cont
|
||||
// Extension
|
||||
import 'sql/workbench/contrib/extensions/browser/extensions.contribution';
|
||||
|
||||
// Azure
|
||||
import 'sql/workbench/contrib/azure/browser/azure.contribution';
|
||||
|
||||
//#endregion
|
||||
|
||||
Reference in New Issue
Block a user