mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Add connect button to MIAA dashboard (#14183)
* Add connect button to MIAA dashboard * PR comments
This commit is contained in:
@@ -197,8 +197,8 @@ export function updated(when: string): string { return localize('arc.updated', "
|
|||||||
export function validationMin(min: number): string { return localize('arc.validationMin', "Value must be greater than or equal to {0}.", min); }
|
export function validationMin(min: number): string { return localize('arc.validationMin', "Value must be greater than or equal to {0}.", min); }
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
export const connectionRequired = localize('arc.connectionRequired', "A connection is required to show all properties. Click refresh to re-enter connection information");
|
|
||||||
export const pgConnectionRequired = localize('arc.pgConnectionRequired', "A connection is required to show and set database engine settings.");
|
export const pgConnectionRequired = localize('arc.pgConnectionRequired', "A connection is required to show and set database engine settings.");
|
||||||
|
export const miaaConnectionRequired = localize('arc.miaaConnectionRequired', "A connection is required to list the databases on this instance.");
|
||||||
export const couldNotFindControllerRegistration = localize('arc.couldNotFindControllerRegistration', "Could not find controller registration.");
|
export const couldNotFindControllerRegistration = localize('arc.couldNotFindControllerRegistration', "Could not find controller registration.");
|
||||||
export function outOfRange(min: string, max: string): string { return localize('arc.outOfRange', "The number must be in range {0} - {1}", min, max); }
|
export function outOfRange(min: string, max: string): string { return localize('arc.outOfRange', "The number must be in range {0} - {1}", min, max); }
|
||||||
export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", getErrorMessage(error)); }
|
export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", getErrorMessage(error)); }
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export class MiaaModel extends ResourceModel {
|
|||||||
private readonly _azdataApi: azdataExt.IExtension;
|
private readonly _azdataApi: azdataExt.IExtension;
|
||||||
public onConfigUpdated = this._onConfigUpdated.event;
|
public onConfigUpdated = this._onConfigUpdated.event;
|
||||||
public onDatabasesUpdated = this._onDatabasesUpdated.event;
|
public onDatabasesUpdated = this._onDatabasesUpdated.event;
|
||||||
public configLastUpdated?: Date;
|
public configLastUpdated: Date | undefined;
|
||||||
public databasesLastUpdated?: Date;
|
public databasesLastUpdated: Date | undefined;
|
||||||
|
|
||||||
private _refreshPromise: Deferred<void> | undefined = undefined;
|
private _refreshPromise: Deferred<void> | undefined = undefined;
|
||||||
|
|
||||||
@@ -91,22 +91,16 @@ export class MiaaModel extends ResourceModel {
|
|||||||
|
|
||||||
// If we have an external endpoint configured then fetch the databases now
|
// If we have an external endpoint configured then fetch the databases now
|
||||||
if (this._config.status.externalEndpoint) {
|
if (this._config.status.externalEndpoint) {
|
||||||
this.getDatabases().catch(err => {
|
this.getDatabases(false).catch(_err => {
|
||||||
// If an error occurs show a message so the user knows something failed but still
|
// If an error occurs still fire the event so callers can know to
|
||||||
// fire the event so callers can know to update (e.g. so dashboards don't show the
|
// update (e.g. so dashboards don't show the loading icon forever)
|
||||||
// loading icon forever)
|
|
||||||
if (err instanceof UserCancelledError) {
|
this.databasesLastUpdated = undefined;
|
||||||
vscode.window.showWarningMessage(loc.connectionRequired);
|
|
||||||
} else {
|
|
||||||
vscode.window.showErrorMessage(loc.fetchDatabasesFailed(this.info.name, err));
|
|
||||||
}
|
|
||||||
this.databasesLastUpdated = new Date();
|
|
||||||
this._onDatabasesUpdated.fire(this._databases);
|
this._onDatabasesUpdated.fire(this._databases);
|
||||||
throw err;
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Otherwise just fire the event so dashboards can update appropriately
|
// Otherwise just fire the event so dashboards can update appropriately
|
||||||
this.databasesLastUpdated = new Date();
|
this.databasesLastUpdated = undefined;
|
||||||
this._onDatabasesUpdated.fire(this._databases);
|
this._onDatabasesUpdated.fire(this._databases);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,9 +114,9 @@ export class MiaaModel extends ResourceModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getDatabases(): Promise<void> {
|
public async getDatabases(promptForConnection: boolean = true): Promise<void> {
|
||||||
if (!this._connectionProfile) {
|
if (!this._connectionProfile) {
|
||||||
await this.getConnectionProfile();
|
await this.getConnectionProfile(promptForConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We haven't connected yet so do so now and then store the ID for the active connection
|
// We haven't connected yet so do so now and then store the ID for the active connection
|
||||||
@@ -182,6 +176,7 @@ export class MiaaModel extends ResourceModel {
|
|||||||
|
|
||||||
protected async updateConnectionProfile(connectionProfile: azdata.IConnectionProfile): Promise<void> {
|
protected async updateConnectionProfile(connectionProfile: azdata.IConnectionProfile): Promise<void> {
|
||||||
this._connectionProfile = connectionProfile;
|
this._connectionProfile = connectionProfile;
|
||||||
|
this._activeConnectionId = connectionProfile.id;
|
||||||
this.info.connectionId = connectionProfile.id;
|
this.info.connectionId = connectionProfile.id;
|
||||||
this._miaaInfo.userName = connectionProfile.userName;
|
this._miaaInfo.userName = connectionProfile.userName;
|
||||||
await this._treeDataProvider.saveControllers();
|
await this._treeDataProvider.saveControllers();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export abstract class ResourceModel {
|
|||||||
* Loads the saved connection profile associated with this model. Will prompt for one if
|
* 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)
|
* we don't have one or can't find it (it was deleted)
|
||||||
*/
|
*/
|
||||||
protected async getConnectionProfile(): Promise<void> {
|
protected async getConnectionProfile(promptForConnection: boolean = true): Promise<void> {
|
||||||
let connectionProfile: azdata.IConnectionProfile | undefined = this.createConnectionProfile();
|
let connectionProfile: azdata.IConnectionProfile | undefined = this.createConnectionProfile();
|
||||||
|
|
||||||
// If we have the ID stored then try to retrieve the password from previous connections
|
// If we have the ID stored then try to retrieve the password from previous connections
|
||||||
@@ -50,7 +50,11 @@ export abstract class ResourceModel {
|
|||||||
if (connectionProfile.userName) {
|
if (connectionProfile.userName) {
|
||||||
const result = await azdata.connection.connect(connectionProfile, false, false);
|
const result = await azdata.connection.connect(connectionProfile, false, false);
|
||||||
if (!result.connected) {
|
if (!result.connected) {
|
||||||
await this.promptForConnection(connectionProfile);
|
if (promptForConnection) {
|
||||||
|
await this.promptForConnection(connectionProfile);
|
||||||
|
} else {
|
||||||
|
throw new Error(result.errorMessage);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.updateConnectionProfile(connectionProfile);
|
this.updateConnectionProfile(connectionProfile);
|
||||||
}
|
}
|
||||||
@@ -63,8 +67,13 @@ export abstract class ResourceModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!connectionProfile?.userName || !connectionProfile?.password) {
|
if (!connectionProfile?.userName || !connectionProfile?.password) {
|
||||||
// Need to prompt user for password since we don't have one stored
|
if (promptForConnection) {
|
||||||
await this.promptForConnection(connectionProfile);
|
// Need to prompt user for password since we don't have one stored
|
||||||
|
await this.promptForConnection(connectionProfile);
|
||||||
|
} else {
|
||||||
|
throw new Error('Missing username/password for connection profile');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ import { ControllerModel } from '../../../models/controllerModel';
|
|||||||
import { MiaaModel } from '../../../models/miaaModel';
|
import { MiaaModel } from '../../../models/miaaModel';
|
||||||
import { DashboardPage } from '../../components/dashboardPage';
|
import { DashboardPage } from '../../components/dashboardPage';
|
||||||
import { ResourceType } from 'arc';
|
import { ResourceType } from 'arc';
|
||||||
|
import { UserCancelledError } from '../../../common/api';
|
||||||
|
|
||||||
export class MiaaDashboardOverviewPage extends DashboardPage {
|
export class MiaaDashboardOverviewPage extends DashboardPage {
|
||||||
|
|
||||||
private _propertiesLoading!: azdata.LoadingComponent;
|
private _propertiesLoading!: azdata.LoadingComponent;
|
||||||
private _kibanaLoading!: azdata.LoadingComponent;
|
private _kibanaLoading!: azdata.LoadingComponent;
|
||||||
private _grafanaLoading!: azdata.LoadingComponent;
|
private _grafanaLoading!: azdata.LoadingComponent;
|
||||||
private _databasesTableLoading!: azdata.LoadingComponent;
|
|
||||||
|
|
||||||
private _propertiesContainer!: azdata.PropertiesContainerComponent;
|
private _propertiesContainer!: azdata.PropertiesContainerComponent;
|
||||||
private _kibanaLink!: azdata.HyperlinkComponent;
|
private _kibanaLink!: azdata.HyperlinkComponent;
|
||||||
@@ -29,6 +29,11 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
private _databasesMessage!: azdata.TextComponent;
|
private _databasesMessage!: azdata.TextComponent;
|
||||||
private _openInAzurePortalButton!: azdata.ButtonComponent;
|
private _openInAzurePortalButton!: azdata.ButtonComponent;
|
||||||
|
|
||||||
|
private _databasesContainer!: azdata.DivContainer;
|
||||||
|
private _connectToServerLoading!: azdata.LoadingComponent;
|
||||||
|
private _connectToServerButton!: azdata.ButtonComponent;
|
||||||
|
private _databasesTableLoading!: azdata.LoadingComponent;
|
||||||
|
|
||||||
private readonly _azdataApi: azdataExt.IExtension;
|
private readonly _azdataApi: azdataExt.IExtension;
|
||||||
private readonly _azurecoreApi: azurecore.IExtension;
|
private readonly _azurecoreApi: azurecore.IExtension;
|
||||||
|
|
||||||
@@ -84,6 +89,28 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
this._grafanaLink = this.modelView.modelBuilder.hyperlink().component();
|
this._grafanaLink = this.modelView.modelBuilder.hyperlink().component();
|
||||||
this._grafanaLoading = this.modelView.modelBuilder.loadingComponent().component();
|
this._grafanaLoading = this.modelView.modelBuilder.loadingComponent().component();
|
||||||
|
|
||||||
|
this._databasesContainer = this.modelView.modelBuilder.divContainer().component();
|
||||||
|
|
||||||
|
const connectToServerText = this.modelView.modelBuilder.text().withProps({
|
||||||
|
value: loc.miaaConnectionRequired
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
this._connectToServerButton = this.modelView.modelBuilder.button().withProps({
|
||||||
|
label: loc.connectToServer,
|
||||||
|
enabled: false,
|
||||||
|
CSSStyles: { 'max-width': '125px', 'margin-left': '40%' }
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
const connectToServerContainer = this.modelView.modelBuilder.divContainer().component();
|
||||||
|
|
||||||
|
|
||||||
|
connectToServerContainer.addItem(connectToServerText, { CSSStyles: { 'text-align': 'center', 'margin-top': '20px' } });
|
||||||
|
connectToServerContainer.addItem(this._connectToServerButton);
|
||||||
|
|
||||||
|
this._connectToServerLoading = this.modelView.modelBuilder.loadingComponent().withItem(connectToServerContainer).component();
|
||||||
|
|
||||||
|
this._databasesContainer.addItem(this._connectToServerLoading, { CSSStyles: { 'margin-top': '20px' } });
|
||||||
|
|
||||||
this._databasesTableLoading = this.modelView.modelBuilder.loadingComponent().component();
|
this._databasesTableLoading = this.modelView.modelBuilder.loadingComponent().component();
|
||||||
this._databasesTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
this._databasesTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@@ -180,7 +207,18 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
|
|
||||||
// Databases
|
// Databases
|
||||||
rootContainer.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: loc.databases, CSSStyles: titleCSS }).component());
|
rootContainer.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: loc.databases, CSSStyles: titleCSS }).component());
|
||||||
rootContainer.addItem(this._databasesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
this.disposables.push(
|
||||||
|
this._connectToServerButton!.onDidClick(async () => {
|
||||||
|
this._connectToServerButton!.enabled = false;
|
||||||
|
this._databasesTableLoading!.loading = true;
|
||||||
|
try {
|
||||||
|
await this.callGetDatabases();
|
||||||
|
} catch {
|
||||||
|
this._connectToServerButton!.enabled = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
rootContainer.addItem(this._databasesContainer);
|
||||||
rootContainer.addItem(this._databasesMessage);
|
rootContainer.addItem(this._databasesMessage);
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
@@ -283,6 +321,19 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
).component();
|
).component();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async callGetDatabases(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this._miaaModel.getDatabases();
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UserCancelledError) {
|
||||||
|
vscode.window.showWarningMessage(loc.miaaConnectionRequired);
|
||||||
|
} else {
|
||||||
|
vscode.window.showErrorMessage(loc.fetchDatabasesFailed(this._miaaModel.info.name, error));
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private handleRegistrationsUpdated(): void {
|
private handleRegistrationsUpdated(): void {
|
||||||
const config = this._controllerModel.controllerConfig;
|
const config = this._controllerModel.controllerConfig;
|
||||||
if (this._openInAzurePortalButton) {
|
if (this._openInAzurePortalButton) {
|
||||||
@@ -301,6 +352,9 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
this._instanceProperties.externalEndpoint = this._miaaModel.config.status.externalEndpoint || loc.notConfigured;
|
this._instanceProperties.externalEndpoint = this._miaaModel.config.status.externalEndpoint || loc.notConfigured;
|
||||||
this._instanceProperties.vCores = this._miaaModel.config.spec.limits?.vcores?.toString() || '';
|
this._instanceProperties.vCores = this._miaaModel.config.spec.limits?.vcores?.toString() || '';
|
||||||
this._databasesMessage.value = !this._miaaModel.config.status.externalEndpoint ? loc.noExternalEndpoint : '';
|
this._databasesMessage.value = !this._miaaModel.config.status.externalEndpoint ? loc.noExternalEndpoint : '';
|
||||||
|
if (!this._miaaModel.config.status.externalEndpoint) {
|
||||||
|
this._databasesContainer.removeItem(this._connectToServerLoading);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refreshDisplayedProperties();
|
this.refreshDisplayedProperties();
|
||||||
@@ -312,7 +366,20 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
|
|||||||
this._instanceProperties.miaaAdmin = this._miaaModel.username || this._instanceProperties.miaaAdmin;
|
this._instanceProperties.miaaAdmin = this._miaaModel.username || this._instanceProperties.miaaAdmin;
|
||||||
this.refreshDisplayedProperties();
|
this.refreshDisplayedProperties();
|
||||||
this._databasesTable.data = this._miaaModel.databases.map(d => [d.name, getDatabaseStateDisplayText(d.status)]);
|
this._databasesTable.data = this._miaaModel.databases.map(d => [d.name, getDatabaseStateDisplayText(d.status)]);
|
||||||
this._databasesTableLoading.loading = !this._miaaModel.databasesLastUpdated;
|
this._databasesTableLoading.loading = false;
|
||||||
|
|
||||||
|
if (this._miaaModel.databasesLastUpdated) {
|
||||||
|
// We successfully connected so now can remove the button and replace it with the actual databases table
|
||||||
|
this._databasesContainer.removeItem(this._connectToServerLoading);
|
||||||
|
this._databasesContainer.addItem(this._databasesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||||
|
} else {
|
||||||
|
// If we don't have an endpoint then there's no point in showing the connect button - but the logic
|
||||||
|
// to display text informing the user of this is already handled by the handleMiaaConfigUpdated
|
||||||
|
if (this._miaaModel?.config?.status.externalEndpoint) {
|
||||||
|
this._connectToServerLoading.loading = false;
|
||||||
|
this._connectToServerButton.enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private refreshDisplayedProperties(): void {
|
private refreshDisplayedProperties(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user