mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-29 08:10:29 -04:00
Add refresh support to Arc Postgres pages (#10607)
This commit is contained in:
@@ -27,6 +27,7 @@ export class IconPathHelper {
|
||||
public static backup: IconPath;
|
||||
public static properties: IconPath;
|
||||
public static networking: IconPath;
|
||||
public static refresh: IconPath;
|
||||
|
||||
public static setExtensionContext(context: vscode.ExtensionContext) {
|
||||
IconPathHelper.context = context;
|
||||
@@ -86,6 +87,10 @@ export class IconPathHelper {
|
||||
light: context.asAbsolutePath('images/security.svg'),
|
||||
dark: context.asAbsolutePath('images/security.svg')
|
||||
};
|
||||
IconPathHelper.refresh = {
|
||||
light: context.asAbsolutePath('images/refresh.svg'),
|
||||
dark: context.asAbsolutePath('images/refresh.svg')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,19 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
const dbNamespace = '';
|
||||
const dbName = '';
|
||||
|
||||
const controllerModel = new ControllerModel(controllerUrl, auth);
|
||||
const databaseModel = new PostgresModel(controllerUrl, auth, dbNamespace, dbName);
|
||||
const postgresDashboard = new PostgresDashboard(loc.postgresDashboard, controllerModel, databaseModel);
|
||||
await postgresDashboard.showDashboard();
|
||||
try {
|
||||
const controllerModel = new ControllerModel(controllerUrl, auth);
|
||||
const postgresModel = new PostgresModel(controllerUrl, auth, dbNamespace, dbName);
|
||||
const postgresDashboard = new PostgresDashboard(loc.postgresDashboard, controllerModel, postgresModel);
|
||||
|
||||
await Promise.all([
|
||||
postgresDashboard.showDashboard(),
|
||||
controllerModel.refresh(),
|
||||
postgresModel.refresh()
|
||||
]);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.failedToManagePostgres(`${dbNamespace}.${dbName}`, error));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ export const feedback = localize('arc.feedback', 'Feedback');
|
||||
export const selectConnectionString = localize('arc.selectConnectionString', 'Select from available client connection strings below');
|
||||
export const vCores = localize('arc.vCores', 'vCores');
|
||||
export const ram = localize('arc.ram', 'RAM');
|
||||
export const refresh = localize('arc.refresh', 'Refresh');
|
||||
|
||||
// Postgres constants
|
||||
export const coordinatorEndpoint = localize('arc.coordinatorEndpoint', 'Coordinator endpoint');
|
||||
@@ -66,14 +67,16 @@ export const node = localize('arc.node', 'node');
|
||||
export const nodes = localize('arc.nodes', 'nodes');
|
||||
export const storagePerNode = localize('arc.storagePerNode', 'storage per node');
|
||||
|
||||
export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database '{0}' created", name); }
|
||||
export function databaseCreationFailed(name: string, error: any): string { return localize('arc.databaseCreationFailed', "Failed to create database '{0}'. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function passwordReset(name: string): string { return localize('arc.passwordReset', "Password reset for service '{0}'", name); }
|
||||
export function passwordResetFailed(name: string, error: any): string { return localize('arc.passwordResetFailed', "Failed to reset password for service '{0}'. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function deleteServicePrompt(name: string): string { return localize('arc.deleteServicePrompt', "Delete service '{0}'?", name); }
|
||||
export function serviceDeleted(name: string): string { return localize('arc.serviceDeleted', "Service '{0}' deleted", name); }
|
||||
export function serviceDeletionFailed(name: string, error: any): string { return localize('arc.serviceDeletionFailed', "Failed to delete service '{0}'. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function couldNotFindAzureResource(name: string): string { return localize('arc.couldNotFindAzureResource', "Could not find Azure resource for '{0}'", name); }
|
||||
export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database {0} created", name); }
|
||||
export function databaseCreationFailed(name: string, error: any): string { return localize('arc.databaseCreationFailed', "Failed to create database {0}. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function passwordReset(name: string): string { return localize('arc.passwordReset', "Password reset for service {0}", name); }
|
||||
export function passwordResetFailed(name: string, error: any): string { return localize('arc.passwordResetFailed', "Failed to reset password for service {0}. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function deleteServicePrompt(name: string): string { return localize('arc.deleteServicePrompt', "Delete service {0}?", name); }
|
||||
export function serviceDeleted(name: string): string { return localize('arc.serviceDeleted', "Service {0} deleted", name); }
|
||||
export function serviceDeletionFailed(name: string, error: any): string { return localize('arc.serviceDeletionFailed', "Failed to delete service {0}. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
export function couldNotFindAzureResource(name: string): string { return localize('arc.couldNotFindAzureResource', "Could not find Azure resource for {0}", name); }
|
||||
export function copiedToClipboard(name: string): string { return localize('arc.copiedToClipboard', '{0} copied to clipboard', name); }
|
||||
export function refreshFailed(error: any): string { return localize('arc.refreshFailed', "Refresh failed. {0}", (error instanceof Error ? error.message : error)); }
|
||||
export function failedToManagePostgres(name: string, error: any): string { return localize('arc.failedToManagePostgres', "Failed to manage Postgres {0}. {1}", name, (error instanceof Error ? error.message : error)); }
|
||||
|
||||
export const arcResources = localize('arc.arcResources', "Azure Arc Resources");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Authentication } from '../controller/auth';
|
||||
import { EndpointsRouterApi, EndpointModel, RegistrationRouterApi, RegistrationResponse, TokenRouterApi } from '../controller/generated/v1/api';
|
||||
|
||||
@@ -10,9 +11,16 @@ export class ControllerModel {
|
||||
private _endpointsRouter: EndpointsRouterApi;
|
||||
private _tokenRouter: TokenRouterApi;
|
||||
private _registrationRouter: RegistrationRouterApi;
|
||||
private _endpoints!: EndpointModel[];
|
||||
private _namespace!: string;
|
||||
private _registrations!: RegistrationResponse[];
|
||||
private _endpoints?: EndpointModel[];
|
||||
private _namespace?: string;
|
||||
private _registrations?: RegistrationResponse[];
|
||||
|
||||
private readonly _onEndpointsUpdated = new vscode.EventEmitter<EndpointModel[]>();
|
||||
private readonly _onRegistrationsUpdated = new vscode.EventEmitter<RegistrationResponse[]>();
|
||||
public onEndpointsUpdated = this._onEndpointsUpdated.event;
|
||||
public onRegistrationsUpdated = this._onRegistrationsUpdated.event;
|
||||
public endpointsLastUpdated?: Date;
|
||||
public registrationsLastUpdated?: Date;
|
||||
|
||||
constructor(controllerUrl: string, auth: Authentication) {
|
||||
this._endpointsRouter = new EndpointsRouterApi(controllerUrl);
|
||||
@@ -29,33 +37,36 @@ export class ControllerModel {
|
||||
await Promise.all([
|
||||
this._endpointsRouter.apiV1BdcEndpointsGet().then(response => {
|
||||
this._endpoints = response.body;
|
||||
this.endpointsLastUpdated = new Date();
|
||||
this._onEndpointsUpdated.fire(this._endpoints);
|
||||
}),
|
||||
this._tokenRouter.apiV1TokenPost().then(async response => {
|
||||
this._namespace = response.body.namespace!;
|
||||
this._registrations = (await this._registrationRouter.apiV1RegistrationListResourcesNsGet(this._namespace)).body;
|
||||
this.registrationsLastUpdated = new Date();
|
||||
this._onRegistrationsUpdated.fire(this._registrations);
|
||||
})
|
||||
]).then(async _ => {
|
||||
this._registrations = (await this._registrationRouter.apiV1RegistrationListResourcesNsGet(this._namespace)).body;
|
||||
});
|
||||
]);
|
||||
}
|
||||
|
||||
public endpoints(): EndpointModel[] {
|
||||
public endpoints(): EndpointModel[] | undefined {
|
||||
return this._endpoints;
|
||||
}
|
||||
|
||||
public endpoint(name: string): EndpointModel | undefined {
|
||||
return this._endpoints.find(e => e.name === name);
|
||||
return this._endpoints?.find(e => e.name === name);
|
||||
}
|
||||
|
||||
public namespace(): string {
|
||||
public namespace(): string | undefined {
|
||||
return this._namespace;
|
||||
}
|
||||
|
||||
public registrations(): RegistrationResponse[] {
|
||||
public registrations(): RegistrationResponse[] | undefined {
|
||||
return this._registrations;
|
||||
}
|
||||
|
||||
public registration(type: string, namespace: string, name: string): RegistrationResponse | undefined {
|
||||
return this._registrations.find(r => {
|
||||
return this._registrations?.find(r => {
|
||||
// Resources deployed outside the controller's namespace are named in the format 'namespace_name'
|
||||
let instanceName = r.instanceName!;
|
||||
const parts: string[] = instanceName.split('_');
|
||||
|
||||
@@ -3,14 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as loc from '../localizedConstants';
|
||||
import { DuskyObjectModelsDatabaseService, DatabaseRouterApi, DuskyObjectModelsDatabase, V1Status } from '../controller/generated/dusky/api';
|
||||
import { Authentication } from '../controller/auth';
|
||||
|
||||
export class PostgresModel {
|
||||
private _databaseRouter: DatabaseRouterApi;
|
||||
private _service!: DuskyObjectModelsDatabaseService;
|
||||
private _password!: string;
|
||||
private _service?: DuskyObjectModelsDatabaseService;
|
||||
private _password?: string;
|
||||
private readonly _onServiceUpdated = new vscode.EventEmitter<DuskyObjectModelsDatabaseService>();
|
||||
private readonly _onPasswordUpdated = new vscode.EventEmitter<string>();
|
||||
public onServiceUpdated = this._onServiceUpdated.event;
|
||||
public onPasswordUpdated = this._onPasswordUpdated.event;
|
||||
public serviceLastUpdated?: Date;
|
||||
public passwordLastUpdated?: Date;
|
||||
|
||||
constructor(controllerUrl: string, auth: Authentication, private _namespace: string, private _name: string) {
|
||||
this._databaseRouter = new DatabaseRouterApi(controllerUrl);
|
||||
@@ -33,23 +40,27 @@ export class PostgresModel {
|
||||
}
|
||||
|
||||
/** Returns the service's spec */
|
||||
public service(): DuskyObjectModelsDatabaseService {
|
||||
public service(): DuskyObjectModelsDatabaseService | undefined {
|
||||
return this._service;
|
||||
}
|
||||
|
||||
/** Returns the service's password */
|
||||
public password(): string {
|
||||
public password(): string | undefined {
|
||||
return this._password;
|
||||
}
|
||||
|
||||
/** Refreshes the service's model */
|
||||
/** Refreshes the model */
|
||||
public async refresh() {
|
||||
await Promise.all([
|
||||
this._databaseRouter.getDuskyDatabaseService(this._namespace, this._name).then(response => {
|
||||
this._service = response.body;
|
||||
this.serviceLastUpdated = new Date();
|
||||
this._onServiceUpdated.fire(this._service);
|
||||
}),
|
||||
this._databaseRouter.getDuskyPassword(this._namespace, this._name).then(async response => {
|
||||
this._password = response.body;
|
||||
this.passwordLastUpdated = new Date();
|
||||
this._onPasswordUpdated.fire(this._password!);
|
||||
})
|
||||
]);
|
||||
}
|
||||
@@ -82,7 +93,7 @@ export class PostgresModel {
|
||||
|
||||
/** Returns the number of nodes in the service */
|
||||
public numNodes(): number {
|
||||
let nodes = this._service.spec.scale?.shards ?? 1;
|
||||
let nodes = this._service?.spec.scale?.shards ?? 1;
|
||||
if (nodes > 1) { nodes++; } // for multiple shards there is an additional node for the coordinator
|
||||
return nodes;
|
||||
}
|
||||
@@ -92,10 +103,10 @@ export class PostgresModel {
|
||||
* internal IP. If either field is not available it will be set to undefined.
|
||||
*/
|
||||
public endpoint(): { ip?: string, port?: number } {
|
||||
const externalIp = this._service.status?.externalIP;
|
||||
const internalIp = this._service.status?.internalIP;
|
||||
const externalPort = this._service.status?.externalPort;
|
||||
const internalPort = this._service.status?.internalPort;
|
||||
const externalIp = this._service?.status?.externalIP;
|
||||
const internalIp = this._service?.status?.internalIP;
|
||||
const externalPort = this._service?.status?.externalPort;
|
||||
const internalPort = this._service?.status?.internalPort;
|
||||
|
||||
return externalIp ? { ip: externalIp, port: externalPort ?? undefined }
|
||||
: internalIp ? { ip: internalIp, port: internalPort ?? undefined }
|
||||
@@ -105,26 +116,22 @@ export class PostgresModel {
|
||||
/** Returns the service's configuration e.g. '3 nodes, 1.5 vCores, 1GiB RAM, 2GiB storage per node' */
|
||||
public configuration(): string {
|
||||
const nodes = this.numNodes();
|
||||
const cpuLimit = this._service.spec.scheduling?.resources?.limits?.['cpu'];
|
||||
const ramLimit = this._service.spec.scheduling?.resources?.limits?.['memory'];
|
||||
const cpuRequest = this._service.spec.scheduling?.resources?.requests?.['cpu'];
|
||||
const ramRequest = this._service.spec.scheduling?.resources?.requests?.['memory'];
|
||||
const storage = this._service.spec.storage.volumeSize;
|
||||
const cpuLimit = this._service?.spec.scheduling?.resources?.limits?.['cpu'];
|
||||
const ramLimit = this._service?.spec.scheduling?.resources?.limits?.['memory'];
|
||||
const cpuRequest = this._service?.spec.scheduling?.resources?.requests?.['cpu'];
|
||||
const ramRequest = this._service?.spec.scheduling?.resources?.requests?.['memory'];
|
||||
const storage = this._service?.spec.storage.volumeSize;
|
||||
|
||||
// Prefer limits if they're provided, otherwise use requests if they're provided
|
||||
let nodeConfiguration = `${nodes} ${nodes > 1 ? loc.nodes : loc.node}`;
|
||||
if (cpuLimit) {
|
||||
nodeConfiguration += `, ${this.formatCores(cpuLimit)} ${loc.vCores}`;
|
||||
} else if (cpuRequest) {
|
||||
nodeConfiguration += `, ${this.formatCores(cpuRequest)} ${loc.vCores}`;
|
||||
let configuration = `${nodes} ${nodes > 1 ? loc.nodes : loc.node}`;
|
||||
if (cpuLimit || cpuRequest) {
|
||||
configuration += `, ${this.formatCores(cpuLimit ?? cpuRequest!)} ${loc.vCores}`;
|
||||
}
|
||||
if (ramLimit) {
|
||||
nodeConfiguration += `, ${this.formatMemory(ramLimit)} ${loc.ram}`;
|
||||
} else if (ramRequest) {
|
||||
nodeConfiguration += `, ${this.formatMemory(ramRequest)} ${loc.ram}`;
|
||||
if (ramLimit || ramRequest) {
|
||||
configuration += `, ${this.formatMemory(ramLimit ?? ramRequest!)} ${loc.ram}`;
|
||||
}
|
||||
if (storage) { nodeConfiguration += `, ${storage} ${loc.storagePerNode}`; }
|
||||
return nodeConfiguration;
|
||||
if (storage) { configuration += `, ${storage} ${loc.storagePerNode}`; }
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper } from '../../../constants';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
|
||||
export class PostgresBackupPage extends PostgresDashboardPage {
|
||||
export class PostgresBackupPage extends DashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.backup;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper } from '../../../constants';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
|
||||
export class PostgresComputeStoragePage extends PostgresDashboardPage {
|
||||
export class PostgresComputeStoragePage extends DashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.computeAndStorage;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,23 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles } from '../../../constants';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { KeyValueContainer, KeyValue, InputKeyValue } from '../../components/keyValueContainer';
|
||||
import { KeyValueContainer, InputKeyValue } from '../../components/keyValueContainer';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresConnectionStringsPage extends DashboardPage {
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
this._postgresModel.onPasswordUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
}
|
||||
|
||||
export class PostgresConnectionStringsPage extends PostgresDashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.connectionStrings;
|
||||
}
|
||||
@@ -46,10 +56,39 @@ export class PostgresConnectionStringsPage extends PostgresDashboardPage {
|
||||
this.modelView.modelBuilder.flexContainer().withItems([info, link]).withLayout({ flexWrap: 'wrap' }).component(),
|
||||
{ CSSStyles: { display: 'inline-flex', 'margin-bottom': '25px' } });
|
||||
|
||||
const endpoint: { ip?: string, port?: number } = this.databaseModel.endpoint();
|
||||
const password = this.databaseModel.password();
|
||||
this.keyValueContainer = new KeyValueContainer(this.modelView.modelBuilder, []);
|
||||
content.addItem(this.keyValueContainer.container);
|
||||
this.initialized = true;
|
||||
return root;
|
||||
}
|
||||
|
||||
const pairs: KeyValue[] = [
|
||||
protected get toolbarContainer(): azdata.ToolbarContainer {
|
||||
const refreshButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.refresh,
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
refreshButton.onDidClick(async () => {
|
||||
refreshButton.enabled = false;
|
||||
try {
|
||||
await this._postgresModel.refresh();
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
} finally {
|
||||
refreshButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems([
|
||||
{ component: refreshButton }
|
||||
]).component();
|
||||
}
|
||||
|
||||
private refresh() {
|
||||
const endpoint: { ip?: string, port?: number } = this._postgresModel.endpoint();
|
||||
const password = this._postgresModel.password();
|
||||
|
||||
this.keyValueContainer?.refresh([
|
||||
new InputKeyValue('ADO.NET', `Server=${endpoint.ip};Database=postgres;Port=${endpoint.port};User Id=postgres;Password=${password};Ssl Mode=Require;`),
|
||||
new InputKeyValue('C++ (libpq)', `host=${endpoint.ip} port=${endpoint.port} dbname=postgres user=postgres password=${password} sslmode=require`),
|
||||
new InputKeyValue('JDBC', `jdbc:postgresql://${endpoint.ip}:${endpoint.port}/postgres?user=postgres&password=${password}&sslmode=require`),
|
||||
@@ -59,14 +98,6 @@ export class PostgresConnectionStringsPage extends PostgresDashboardPage {
|
||||
new InputKeyValue('Python', `dbname='postgres' user='postgres' host='${endpoint.ip}' password='${password}' port='${endpoint.port}' sslmode='true'`),
|
||||
new InputKeyValue('Ruby', `host=${endpoint.ip}; dbname=postgres user=postgres password=${password} port=${endpoint.port} sslmode=require`),
|
||||
new InputKeyValue('Web App', `Database=postgres; Data Source=${endpoint.ip}; User Id=postgres; Password=${password}`)
|
||||
];
|
||||
|
||||
const keyValueContainer = new KeyValueContainer(this.modelView.modelBuilder, pairs);
|
||||
content.addItem(keyValueContainer.container);
|
||||
return root;
|
||||
}
|
||||
|
||||
protected get toolbarContainer(): azdata.ToolbarContainer {
|
||||
return this.modelView.modelBuilder.toolbarContainer().component();
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,17 @@ import { PostgresNetworkingPage } from './postgresNetworkingPage';
|
||||
import { Dashboard } from '../../components/dashboard';
|
||||
|
||||
export class PostgresDashboard extends Dashboard {
|
||||
constructor(title: string, private _controllerModel: ControllerModel, private _databaseModel: PostgresModel) {
|
||||
constructor(title: string, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {
|
||||
await Promise.all([this._controllerModel.refresh(), this._databaseModel.refresh()]);
|
||||
|
||||
const overviewPage = new PostgresOverviewPage(modelView, this._controllerModel, this._databaseModel);
|
||||
const computeStoragePage = new PostgresComputeStoragePage(modelView, this._controllerModel, this._databaseModel);
|
||||
const connectionStringsPage = new PostgresConnectionStringsPage(modelView, this._controllerModel, this._databaseModel);
|
||||
const backupPage = new PostgresBackupPage(modelView, this._controllerModel, this._databaseModel);
|
||||
const propertiesPage = new PostgresPropertiesPage(modelView, this._controllerModel, this._databaseModel);
|
||||
const networkingPage = new PostgresNetworkingPage(modelView, this._controllerModel, this._databaseModel);
|
||||
const overviewPage = new PostgresOverviewPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const computeStoragePage = new PostgresComputeStoragePage(modelView);
|
||||
const connectionStringsPage = new PostgresConnectionStringsPage(modelView, this._postgresModel);
|
||||
const backupPage = new PostgresBackupPage(modelView);
|
||||
const propertiesPage = new PostgresPropertiesPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const networkingPage = new PostgresNetworkingPage(modelView);
|
||||
|
||||
return [
|
||||
overviewPage.tab,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
|
||||
export abstract class PostgresDashboardPage extends DashboardPage {
|
||||
constructor(protected modelView: azdata.ModelView, protected controllerModel: ControllerModel, protected databaseModel: PostgresModel) {
|
||||
super(modelView);
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper } from '../../../constants';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
|
||||
export class PostgresNetworkingPage extends PostgresDashboardPage {
|
||||
export class PostgresNetworkingPage extends DashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.networking;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,32 @@ import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles } from '../../../constants';
|
||||
import { DuskyObjectModelsDatabase, DuskyObjectModelsDatabaseServiceArcPayload } from '../../../controller/generated/dusky/api';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresOverviewPage extends DashboardPage {
|
||||
private propertiesLoading?: azdata.LoadingComponent;
|
||||
private kibanaLoading?: azdata.LoadingComponent;
|
||||
private grafanaLoading?: azdata.LoadingComponent;
|
||||
private nodesTableLoading?: azdata.LoadingComponent;
|
||||
|
||||
private properties?: azdata.PropertiesContainerComponent;
|
||||
private kibanaLink?: azdata.HyperlinkComponent;
|
||||
private grafanaLink?: azdata.HyperlinkComponent;
|
||||
private nodesTable?: azdata.DeclarativeTableComponent;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._controllerModel.onEndpointsUpdated(() => this.eventuallyRunOnInitialized(() => this.refreshEndpoints()));
|
||||
this._controllerModel.onRegistrationsUpdated(() => this.eventuallyRunOnInitialized(() => this.refreshProperties()));
|
||||
this._postgresModel.onPasswordUpdated(() => this.eventuallyRunOnInitialized(() => this.refreshProperties()));
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => {
|
||||
this.refreshProperties();
|
||||
this.refreshNodes();
|
||||
}));
|
||||
}
|
||||
|
||||
export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.overview;
|
||||
}
|
||||
@@ -28,34 +51,18 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '10px 20px 0px 20px' } });
|
||||
|
||||
const registration = this.controllerModel.registration('postgresInstances', this.databaseModel.namespace(), this.databaseModel.name());
|
||||
const endpoint: { ip?: string, port?: number } = this.databaseModel.endpoint();
|
||||
const essentials = this.modelView.modelBuilder.propertiesContainer().withProperties<azdata.PropertiesContainerComponentProperties>({
|
||||
propertyItems: [
|
||||
{ displayName: loc.name, value: this.databaseModel.name() },
|
||||
{ displayName: loc.serverGroupType, value: loc.postgresArcProductName },
|
||||
{ displayName: loc.resourceGroup, value: registration?.resourceGroupName ?? 'None' },
|
||||
{ displayName: loc.coordinatorEndpoint, value: `postgresql://postgres:${this.databaseModel.password()}@${endpoint.ip}:${endpoint.port}` },
|
||||
{ displayName: loc.status, value: this.databaseModel.service().status?.state ?? '' },
|
||||
{ displayName: loc.postgresAdminUsername, value: 'postgres' },
|
||||
{ displayName: loc.dataController, value: this.controllerModel.namespace() },
|
||||
{ displayName: loc.nodeConfiguration, value: this.databaseModel.configuration() },
|
||||
{ displayName: loc.subscriptionId, value: registration?.subscriptionId ?? 'None' },
|
||||
{ displayName: loc.postgresVersion, value: this.databaseModel.service().spec.engine.version?.toString() ?? '' }
|
||||
]
|
||||
}).component();
|
||||
content.addItem(essentials, { CSSStyles: cssStyles.text });
|
||||
// Properties
|
||||
this.properties = this.modelView.modelBuilder.propertiesContainer().component();
|
||||
this.propertiesLoading = this.modelView.modelBuilder.loadingComponent().withItem(this.properties).component();
|
||||
content.addItem(this.propertiesLoading, { CSSStyles: cssStyles.text });
|
||||
|
||||
// Service endpoints
|
||||
const titleCSS = { ...cssStyles.title, 'margin-block-start': '2em', 'margin-block-end': '0' };
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: loc.serviceEndpoints, CSSStyles: titleCSS }).component());
|
||||
|
||||
const kibanaQuery = `kubernetes_namespace:"${this.databaseModel.namespace()}" and cluster_name:"${this.databaseModel.name()}"`;
|
||||
const kibanaUrl = `${this.controllerModel.endpoint('logsui')?.endpoint}/app/kibana#/discover?_a=(query:(language:kuery,query:'${kibanaQuery}'))`;
|
||||
const grafanaUrl = `${this.controllerModel.endpoint('metricsui')?.endpoint}/d/postgres-metrics?var-Namespace=${this.databaseModel.namespace()}&var-Name=${this.databaseModel.name()}`;
|
||||
|
||||
const kibanaLink = this.modelView.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({ label: kibanaUrl, url: kibanaUrl, }).component();
|
||||
const grafanaLink = this.modelView.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({ label: grafanaUrl, url: grafanaUrl }).component();
|
||||
this.kibanaLink = this.modelView.modelBuilder.hyperlink().component();
|
||||
this.grafanaLink = this.modelView.modelBuilder.hyperlink().component();
|
||||
this.kibanaLoading = this.modelView.modelBuilder.loadingComponent().withItem(this.kibanaLink).component();
|
||||
this.grafanaLoading = this.modelView.modelBuilder.loadingComponent().withItem(this.grafanaLink).component();
|
||||
|
||||
const endpointsTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||
width: '100%',
|
||||
@@ -92,14 +99,14 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
}
|
||||
],
|
||||
data: [
|
||||
[loc.kibanaDashboard, kibanaLink, loc.kibanaDashboardDescription],
|
||||
[loc.grafanaDashboard, grafanaLink, loc.grafanaDashboardDescription]]
|
||||
[loc.kibanaDashboard, this.kibanaLoading, loc.kibanaDashboardDescription],
|
||||
[loc.grafanaDashboard, this.grafanaLoading, loc.grafanaDashboardDescription]]
|
||||
}).component();
|
||||
content.addItem(endpointsTable);
|
||||
|
||||
// Server group nodes
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: loc.serverGroupNodes, CSSStyles: titleCSS }).component());
|
||||
const nodesTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||
this.nodesTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||
width: '100%',
|
||||
columns: [
|
||||
{
|
||||
@@ -130,15 +137,9 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
data: []
|
||||
}).component();
|
||||
|
||||
const nodes = this.databaseModel.numNodes();
|
||||
for (let i = 0; i < nodes; i++) {
|
||||
nodesTable.data.push([
|
||||
`${this.databaseModel.name()}-${i}`,
|
||||
i === 0 ? loc.coordinatorEndpoint : loc.worker,
|
||||
i === 0 ? `${endpoint.ip}:${endpoint.port}` : `${this.databaseModel.name()}-${i}.${this.databaseModel.name()}-svc.${this.databaseModel.namespace()}.svc.cluster.local`]);
|
||||
}
|
||||
|
||||
content.addItem(nodesTable, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
this.nodesTableLoading = this.modelView.modelBuilder.loadingComponent().withItem(this.nodesTable).component();
|
||||
content.addItem(this.nodesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
this.initialized = true;
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -150,14 +151,18 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
}).component();
|
||||
|
||||
newDatabaseButton.onDidClick(async () => {
|
||||
const name = await vscode.window.showInputBox({ prompt: loc.databaseName });
|
||||
if (name === undefined) { return; }
|
||||
const db: DuskyObjectModelsDatabase = { name: name }; // TODO support other options (sharded, owner)
|
||||
newDatabaseButton.enabled = false;
|
||||
let name;
|
||||
try {
|
||||
await this.databaseModel.createDatabase(db);
|
||||
name = await vscode.window.showInputBox({ prompt: loc.databaseName });
|
||||
if (name === undefined) { return; }
|
||||
const db: DuskyObjectModelsDatabase = { name: name }; // TODO support other options (sharded, owner)
|
||||
await this._postgresModel.createDatabase(db);
|
||||
vscode.window.showInformationMessage(loc.databaseCreated(db.name));
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.databaseCreationFailed(db.name, error));
|
||||
vscode.window.showErrorMessage(loc.databaseCreationFailed(name ?? '', error));
|
||||
} finally {
|
||||
newDatabaseButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -168,16 +173,19 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
}).component();
|
||||
|
||||
resetPasswordButton.onDidClick(async () => {
|
||||
const password = await vscode.window.showInputBox({ prompt: loc.newPassword, password: true });
|
||||
if (password === undefined) { return; }
|
||||
resetPasswordButton.enabled = false;
|
||||
try {
|
||||
await this.databaseModel.update(s => {
|
||||
const password = await vscode.window.showInputBox({ prompt: loc.newPassword, password: true });
|
||||
if (password === undefined) { return; }
|
||||
await this._postgresModel.update(s => {
|
||||
s.arc = s.arc ?? new DuskyObjectModelsDatabaseServiceArcPayload();
|
||||
s.arc.servicePassword = password;
|
||||
});
|
||||
vscode.window.showInformationMessage(loc.passwordReset(this.databaseModel.fullName()));
|
||||
vscode.window.showInformationMessage(loc.passwordReset(this._postgresModel.fullName()));
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.passwordResetFailed(this.databaseModel.fullName(), error));
|
||||
vscode.window.showErrorMessage(loc.passwordResetFailed(this._postgresModel.fullName(), error));
|
||||
} finally {
|
||||
resetPasswordButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -188,15 +196,44 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
}).component();
|
||||
|
||||
deleteButton.onDidClick(async () => {
|
||||
const response = await vscode.window.showQuickPick([loc.yes, loc.no], {
|
||||
placeHolder: loc.deleteServicePrompt(this.databaseModel.fullName())
|
||||
});
|
||||
if (response !== loc.yes) { return; }
|
||||
deleteButton.enabled = false;
|
||||
try {
|
||||
await this.databaseModel.delete();
|
||||
vscode.window.showInformationMessage(loc.serviceDeleted(this.databaseModel.fullName()));
|
||||
const response = await vscode.window.showQuickPick([loc.yes, loc.no], {
|
||||
placeHolder: loc.deleteServicePrompt(this._postgresModel.fullName())
|
||||
});
|
||||
if (response !== loc.yes) { return; }
|
||||
await this._postgresModel.delete();
|
||||
vscode.window.showInformationMessage(loc.serviceDeleted(this._postgresModel.fullName()));
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.serviceDeletionFailed(this.databaseModel.fullName(), error));
|
||||
vscode.window.showErrorMessage(loc.serviceDeletionFailed(this._postgresModel.fullName(), error));
|
||||
} finally {
|
||||
deleteButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh
|
||||
const refreshButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.refresh,
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
refreshButton.onDidClick(async () => {
|
||||
refreshButton.enabled = false;
|
||||
try {
|
||||
this.propertiesLoading!.loading = true;
|
||||
this.kibanaLoading!.loading = true;
|
||||
this.grafanaLoading!.loading = true;
|
||||
this.nodesTableLoading!.loading = true;
|
||||
|
||||
await Promise.all([
|
||||
this._postgresModel.refresh(),
|
||||
this._controllerModel.refresh()
|
||||
]);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
}
|
||||
finally {
|
||||
refreshButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -207,27 +244,70 @@ export class PostgresOverviewPage extends PostgresDashboardPage {
|
||||
}).component();
|
||||
|
||||
openInAzurePortalButton.onDidClick(async () => {
|
||||
const r = this.controllerModel.registration('postgresInstances', this.databaseModel.namespace(), this.databaseModel.name());
|
||||
const r = this._controllerModel.registration('postgresInstances', this._postgresModel.namespace(), this._postgresModel.name());
|
||||
if (r === undefined) {
|
||||
vscode.window.showErrorMessage(loc.couldNotFindAzureResource(this.databaseModel.fullName()));
|
||||
vscode.window.showErrorMessage(loc.couldNotFindAzureResource(this._postgresModel.fullName()));
|
||||
} else {
|
||||
vscode.env.openExternal(vscode.Uri.parse(
|
||||
`https://portal.azure.com/#resource/subscriptions/${r.subscriptionId}/resourceGroups/${r.resourceGroupName}/providers/Microsoft.AzureData/postgresInstances/${r.instanceName}`));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO implement click
|
||||
const feedbackButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.feedback,
|
||||
iconPath: IconPathHelper.heart
|
||||
}).component();
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems([
|
||||
{ component: newDatabaseButton },
|
||||
{ component: resetPasswordButton },
|
||||
{ component: deleteButton, toolbarSeparatorAfter: true },
|
||||
{ component: openInAzurePortalButton },
|
||||
{ component: feedbackButton }
|
||||
{ component: deleteButton },
|
||||
{ component: refreshButton, toolbarSeparatorAfter: true },
|
||||
{ component: openInAzurePortalButton }
|
||||
]).component();
|
||||
}
|
||||
|
||||
private refreshProperties() {
|
||||
const registration = this._controllerModel.registration('postgresInstances', this._postgresModel.namespace(), this._postgresModel.name());
|
||||
const endpoint: { ip?: string, port?: number } = this._postgresModel.endpoint();
|
||||
|
||||
this.properties!.propertyItems = [
|
||||
{ displayName: loc.name, value: this._postgresModel.name() },
|
||||
{ displayName: loc.coordinatorEndpoint, value: `postgresql://postgres:${this._postgresModel.password()}@${endpoint.ip}:${endpoint.port}` },
|
||||
{ displayName: loc.status, value: this._postgresModel.service()?.status?.state ?? '' },
|
||||
{ displayName: loc.postgresAdminUsername, value: 'postgres' },
|
||||
{ displayName: loc.dataController, value: this._controllerModel?.namespace() ?? '' },
|
||||
{ displayName: loc.nodeConfiguration, value: this._postgresModel.configuration() },
|
||||
{ displayName: loc.subscriptionId, value: registration?.subscriptionId ?? '' },
|
||||
{ displayName: loc.postgresVersion, value: this._postgresModel.service()?.spec.engine.version?.toString() ?? '' }
|
||||
];
|
||||
|
||||
this.propertiesLoading!.loading = false;
|
||||
}
|
||||
|
||||
private refreshEndpoints() {
|
||||
const kibanaQuery = `kubernetes_namespace:"${this._postgresModel.namespace()}" and cluster_name:"${this._postgresModel.name()}"`;
|
||||
const kibanaUrl = `${this._controllerModel.endpoint('logsui')?.endpoint}/app/kibana#/discover?_a=(query:(language:kuery,query:'${kibanaQuery}'))`;
|
||||
this.kibanaLink!.label = kibanaUrl;
|
||||
this.kibanaLink!.url = kibanaUrl;
|
||||
|
||||
const grafanaUrl = `${this._controllerModel.endpoint('metricsui')?.endpoint}/d/postgres-metrics?var-Namespace=${this._postgresModel.namespace()}&var-Name=${this._postgresModel.name()}`;
|
||||
this.grafanaLink!.label = grafanaUrl;
|
||||
this.grafanaLink!.url = grafanaUrl;
|
||||
|
||||
this.kibanaLoading!.loading = false;
|
||||
this.grafanaLoading!.loading = false;
|
||||
}
|
||||
|
||||
private refreshNodes() {
|
||||
const nodes = this._postgresModel.numNodes();
|
||||
const endpoint: { ip?: string, port?: number } = this._postgresModel.endpoint();
|
||||
|
||||
const data: any[][] = [];
|
||||
for (let i = 0; i < nodes; i++) {
|
||||
data.push([
|
||||
`${this._postgresModel.name()}-${i}`,
|
||||
i === 0 ? loc.coordinatorEndpoint : loc.worker,
|
||||
i === 0 ? `${endpoint.ip}:${endpoint.port}` :
|
||||
`${this._postgresModel.name()}-${i}.${this._postgresModel.name()}-svc.${this._postgresModel.namespace()}.svc.cluster.local`]);
|
||||
}
|
||||
|
||||
this.nodesTable!.data = data;
|
||||
this.nodesTableLoading!.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,21 @@ import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles } from '../../../constants';
|
||||
import { PostgresDashboardPage } from './postgresDashboardPage';
|
||||
import { KeyValueContainer, KeyValue, InputKeyValue, LinkKeyValue, TextKeyValue } from '../../components/keyValueContainer';
|
||||
import { KeyValueContainer, InputKeyValue, LinkKeyValue, TextKeyValue } from '../../components/keyValueContainer';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresPropertiesPage extends DashboardPage {
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
this._postgresModel.onPasswordUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
this._controllerModel.onRegistrationsUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
}
|
||||
|
||||
export class PostgresPropertiesPage extends PostgresDashboardPage {
|
||||
protected get title(): string {
|
||||
return loc.properties;
|
||||
}
|
||||
@@ -34,27 +44,52 @@ export class PostgresPropertiesPage extends PostgresDashboardPage {
|
||||
CSSStyles: { ...cssStyles.title, 'margin-bottom': '25px' }
|
||||
}).component());
|
||||
|
||||
const endpoint: { ip?: string, port?: number } = this.databaseModel.endpoint();
|
||||
const connectionString = `postgresql://postgres:${this.databaseModel.password()}@${endpoint.ip}:${endpoint.port}`;
|
||||
const registration = this.controllerModel.registration('postgresInstances', this.databaseModel.namespace(), this.databaseModel.name());
|
||||
|
||||
const pairs: KeyValue[] = [
|
||||
new InputKeyValue(loc.coordinatorEndpoint, connectionString),
|
||||
new InputKeyValue(loc.postgresAdminUsername, 'postgres'),
|
||||
new TextKeyValue(loc.status, this.databaseModel.service().status?.state ?? 'Unknown'),
|
||||
new LinkKeyValue(loc.dataController, this.controllerModel.namespace(), _ => vscode.window.showInformationMessage('goto data controller')),
|
||||
new LinkKeyValue(loc.nodeConfiguration, this.databaseModel.configuration(), _ => vscode.window.showInformationMessage('goto configuration')),
|
||||
new TextKeyValue(loc.postgresVersion, this.databaseModel.service().spec.engine.version?.toString() ?? ''),
|
||||
new TextKeyValue(loc.resourceGroup, registration?.resourceGroupName ?? ''),
|
||||
new TextKeyValue(loc.subscriptionId, registration?.subscriptionId ?? '')
|
||||
];
|
||||
|
||||
const keyValueContainer = new KeyValueContainer(this.modelView.modelBuilder, pairs);
|
||||
content.addItem(keyValueContainer.container);
|
||||
this.keyValueContainer = new KeyValueContainer(this.modelView.modelBuilder, []);
|
||||
content.addItem(this.keyValueContainer.container);
|
||||
this.initialized = true;
|
||||
return root;
|
||||
}
|
||||
|
||||
protected get toolbarContainer(): azdata.ToolbarContainer {
|
||||
return this.modelView.modelBuilder.toolbarContainer().component();
|
||||
const refreshButton = this.modelView.modelBuilder.button().withProperties<azdata.ButtonProperties>({
|
||||
label: loc.refresh,
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
|
||||
refreshButton.onDidClick(async () => {
|
||||
refreshButton.enabled = false;
|
||||
try {
|
||||
await Promise.all([
|
||||
this._postgresModel.refresh(),
|
||||
this._controllerModel.refresh()
|
||||
]);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
}
|
||||
finally {
|
||||
refreshButton.enabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems([
|
||||
{ component: refreshButton }
|
||||
]).component();
|
||||
}
|
||||
|
||||
private refresh() {
|
||||
const endpoint: { ip?: string, port?: number } = this._postgresModel.endpoint();
|
||||
const connectionString = `postgresql://postgres:${this._postgresModel.password()}@${endpoint.ip}:${endpoint.port}`;
|
||||
const registration = this._controllerModel.registration('postgresInstances', this._postgresModel.namespace(), this._postgresModel.name());
|
||||
|
||||
this.keyValueContainer?.refresh([
|
||||
new InputKeyValue(loc.coordinatorEndpoint, connectionString),
|
||||
new InputKeyValue(loc.postgresAdminUsername, 'postgres'),
|
||||
new TextKeyValue(loc.status, this._postgresModel.service()?.status?.state ?? 'Unknown'),
|
||||
new LinkKeyValue(loc.dataController, this._controllerModel.namespace() ?? '', _ => vscode.window.showInformationMessage('TODO: Go to data controller')),
|
||||
new LinkKeyValue(loc.nodeConfiguration, this._postgresModel.configuration(), _ => vscode.window.showInformationMessage('TODO: Go to configuration')),
|
||||
new TextKeyValue(loc.postgresVersion, this._postgresModel.service()?.spec.engine.version?.toString() ?? ''),
|
||||
new TextKeyValue(loc.resourceGroup, registration?.resourceGroupName ?? ''),
|
||||
new TextKeyValue(loc.subscriptionId, registration?.subscriptionId ?? '')
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user