From fa664bc92f08085611e7e07983ea36e8afee8ce2 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 27 Aug 2020 07:35:44 -0700 Subject: [PATCH] Show message when external endpoint isn't configured (#11962) --- extensions/arc/src/localizedConstants.ts | 4 +- extensions/arc/src/models/miaaModel.ts | 97 ++++++++++--------- .../miaa/miaaConnectionStringsPage.ts | 8 ++ .../miaa/miaaDashboardOverviewPage.ts | 20 +++- 4 files changed, 77 insertions(+), 52 deletions(-) diff --git a/extensions/arc/src/localizedConstants.ts b/extensions/arc/src/localizedConstants.ts index b3240a578f..394459d9b1 100644 --- a/extensions/arc/src/localizedConstants.ts +++ b/extensions/arc/src/localizedConstants.ts @@ -40,7 +40,7 @@ export const subscriptionId = localize('arc.subscriptionId', "Subscription ID"); export const state = localize('arc.state', "State"); export const connectionMode = localize('arc.connectionMode', "Connection Mode"); export const namespace = localize('arc.namespace', "Namespace"); -export const host = localize('arc.host', "Host"); +export const externalEndpoint = localize('arc.externalEndpoint', "External Endpoint"); export const name = localize('arc.name', "Name"); export const type = localize('arc.type', "Type"); export const status = localize('arc.status', "Status"); @@ -81,6 +81,7 @@ export const password = localize('arc.password', "Password"); export const rememberPassword = localize('arc.rememberPassword', "Remember Password"); export const connect = localize('arc.connect', "Connect"); export const cancel = localize('arc.cancel', "Cancel"); +export const notConfigured = localize('arc.notConfigured', "Not Configured"); // Database States - see https://docs.microsoft.com/sql/relational-databases/databases/database-states export const online = localize('arc.online', "Online"); @@ -119,6 +120,7 @@ export const podOverview = localize('arc.podOverview', "Pod overview"); export const condition = localize('arc.condition', "Condition"); export const details = localize('arc.details', "Details"); export const lastUpdated = localize('arc.lastUpdated', "Last updated"); +export const noExternalEndpoint = localize('arc.noExternalEndpoint', "No External Endpoint has been configured so this information isn't available."); export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database {0} created", name); } export function resourceDeleted(name: string): string { return localize('arc.resourceDeleted', "Resource '{0}' deleted", name); } diff --git a/extensions/arc/src/models/miaaModel.ts b/extensions/arc/src/models/miaaModel.ts index 03e5e6d54e..729ff9bb5b 100644 --- a/extensions/arc/src/models/miaaModel.ts +++ b/extensions/arc/src/models/miaaModel.ts @@ -74,11 +74,12 @@ export class MiaaModel extends ResourceModel { this._refreshPromise = new Deferred(); try { await this._controllerModel.azdataLogin(); - const instanceRefresh = this._azdataApi.azdata.arc.sql.mi.show(this.info.name).then(result => { + try { + const result = await this._azdataApi.azdata.arc.sql.mi.show(this.info.name); this._config = result.result; this.configLastUpdated = new Date(); this._onConfigUpdated.fire(this._config); - }).catch(err => { + } catch (err) { // If an error occurs show a message so the user knows something failed but still // fire the event so callers can know to update (e.g. so dashboards don't show the // loading icon forever) @@ -86,52 +87,29 @@ export class MiaaModel extends ResourceModel { this.configLastUpdated = new Date(); this._onConfigUpdated.fire(undefined); throw err; - }); - const promises: Thenable[] = [instanceRefresh]; - try { - await this.getConnectionProfile(); - if (this._connectionProfile) { - // We haven't connected yet so do so now and then store the ID for the active connection - if (!this._activeConnectionId) { - const result = await azdata.connection.connect(this._connectionProfile, false, false); - if (!result.connected) { - throw new Error(result.errorMessage); - } - this._activeConnectionId = result.connectionId; - } - - const provider = azdata.dataprotocol.getProvider(this._connectionProfile.providerName, azdata.DataProviderType.MetadataProvider); - const databasesRefresh = azdata.connection.getUriForConnection(this._activeConnectionId).then(ownerUri => { - provider.getDatabases(ownerUri).then(databases => { - if (!databases) { - throw new Error('Could not fetch databases'); - } - if (databases.length > 0 && typeof (databases[0]) === 'object') { - this._databases = (databases).map(db => { return { name: db.options['name'], status: db.options['state'] }; }); - } else { - this._databases = (databases).map(db => { return { name: db, status: '-' }; }); - } - this.databasesLastUpdated = new Date(); - this._onDatabasesUpdated.fire(this._databases); - }); - }); - promises.push(databasesRefresh); - } - } catch (err) { - // If an error occurs show a message so the user knows something failed but still - // fire the event so callers can know to update (e.g. so dashboards don't show the - // loading icon forever) - if (err instanceof UserCancelledError) { - vscode.window.showWarningMessage(loc.connectionRequired); - } else { - vscode.window.showErrorMessage(loc.fetchDatabasesFailed(this.info.name, err)); - } - this.databasesLastUpdated = new Date(); - this._onDatabasesUpdated.fire(this._databases); - throw err; } - await Promise.all(promises); + // If we have an external endpoint configured then fetch the databases now + if (this._config.status.externalEndpoint) { + this.getDatabases().catch(err => { + // If an error occurs show a message so the user knows something failed but still + // fire the event so callers can know to update (e.g. so dashboards don't show the + // loading icon forever) + if (err instanceof UserCancelledError) { + vscode.window.showWarningMessage(loc.connectionRequired); + } else { + vscode.window.showErrorMessage(loc.fetchDatabasesFailed(this.info.name, err)); + } + this.databasesLastUpdated = new Date(); + this._onDatabasesUpdated.fire(this._databases); + throw err; + }); + } else { + // Otherwise just fire the event so dashboards can update appropriately + this.databasesLastUpdated = new Date(); + this._onDatabasesUpdated.fire(this._databases); + } + this._refreshPromise.resolve(); } catch (err) { this._refreshPromise.reject(err); @@ -141,6 +119,33 @@ export class MiaaModel extends ResourceModel { } } + private async getDatabases(): Promise { + await this.getConnectionProfile(); + if (this._connectionProfile) { + // We haven't connected yet so do so now and then store the ID for the active connection + if (!this._activeConnectionId) { + const result = await azdata.connection.connect(this._connectionProfile, false, false); + if (!result.connected) { + throw new Error(result.errorMessage); + } + this._activeConnectionId = result.connectionId; + } + + const provider = azdata.dataprotocol.getProvider(this._connectionProfile.providerName, azdata.DataProviderType.MetadataProvider); + const ownerUri = await azdata.connection.getUriForConnection(this._activeConnectionId); + const databases = await provider.getDatabases(ownerUri); + if (!databases) { + throw new Error('Could not fetch databases'); + } + if (databases.length > 0 && typeof (databases[0]) === 'object') { + this._databases = (databases).map(db => { return { name: db.options['name'], status: db.options['state'] }; }); + } else { + this._databases = (databases).map(db => { return { name: db, status: '-' }; }); + } + this.databasesLastUpdated = new Date(); + this._onDatabasesUpdated.fire(this._databases); + } + } /** * Loads the saved connection profile associated with this model. Will prompt for one if * we don't have one or can't find it (it was deleted) diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts index e3f0c9e6e7..c3437e743d 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaConnectionStringsPage.ts @@ -15,6 +15,7 @@ import { parseIpAndPort } from '../../../common/utils'; export class MiaaConnectionStringsPage extends DashboardPage { private _keyValueContainer!: KeyValueContainer; + private _connectionStringsMessage!: azdata.TextComponent; constructor(modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _miaaModel: MiaaModel) { super(modelView); @@ -56,6 +57,12 @@ export class MiaaConnectionStringsPage extends DashboardPage { this._keyValueContainer = new KeyValueContainer(this.modelView.modelBuilder, this.getConnectionStrings()); this.disposables.push(this._keyValueContainer); content.addItem(this._keyValueContainer.container); + + this._connectionStringsMessage = this.modelView.modelBuilder.text() + .withProperties({ CSSStyles: { 'text-align': 'center' } }) + .component(); + content.addItem(this._connectionStringsMessage); + this.initialized = true; return root; } @@ -90,6 +97,7 @@ $conn = sqlsrv_connect($serverName, $connectionInfo);`), } private updateConnectionStrings(): void { + this._connectionStringsMessage.value = !this._miaaModel.config?.status.externalEndpoint ? loc.noExternalEndpoint : ''; this._keyValueContainer.refresh(this.getConnectionStrings()); } } diff --git a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts index 41d3c0115e..38c0631aae 100644 --- a/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts +++ b/extensions/arc/src/ui/dashboards/miaa/miaaDashboardOverviewPage.ts @@ -24,6 +24,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { private _kibanaLink!: azdata.HyperlinkComponent; private _grafanaLink!: azdata.HyperlinkComponent; private _databasesTable!: azdata.DeclarativeTableComponent; + private _databasesMessage!: azdata.TextComponent; private readonly _azdataApi: azdataExt.IExtension; @@ -34,7 +35,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { region: '-', subscriptionId: '-', miaaAdmin: '-', - host: '-', + externalEndpoint: '-', vCores: '' }; @@ -102,6 +103,10 @@ export class MiaaDashboardOverviewPage extends DashboardPage { data: [] }).component(); + this._databasesMessage = this.modelView.modelBuilder.text() + .withProperties({ CSSStyles: { 'text-align': 'center' } }) + .component(); + // Update loaded components with data this.handleRegistrationsUpdated(); this.handleMiaaConfigUpdated(); @@ -171,6 +176,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage { // Databases rootContainer.addItem(this.modelView.modelBuilder.text().withProperties({ value: loc.databases, CSSStyles: titleCSS }).component()); rootContainer.addItem(this._databasesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } }); + rootContainer.addItem(this._databasesMessage); this.initialized = true; return rootContainer; @@ -263,8 +269,12 @@ export class MiaaDashboardOverviewPage extends DashboardPage { } private handleMiaaConfigUpdated(): void { - this._instanceProperties.status = this._miaaModel.config?.status.state || '-'; - this._instanceProperties.host = this._miaaModel.config?.status.externalEndpoint || '-'; + if (this._miaaModel.config) { + this._instanceProperties.status = this._miaaModel.config.status.state || '-'; + this._instanceProperties.externalEndpoint = this._miaaModel.config.status.externalEndpoint || loc.notConfigured; + this._databasesMessage.value = !this._miaaModel.config.status.externalEndpoint ? loc.noExternalEndpoint : ''; + } + this.refreshDisplayedProperties(); } @@ -320,8 +330,8 @@ export class MiaaDashboardOverviewPage extends DashboardPage { value: this._instanceProperties.miaaAdmin }, { - displayName: loc.host, - value: this._instanceProperties.host + displayName: loc.externalEndpoint, + value: this._instanceProperties.externalEndpoint }, { displayName: loc.compute,