mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 03:28:33 -05:00
Arc Postgres resource health page (#11065)
This commit is contained in:
@@ -12,11 +12,20 @@ import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresConnectionStringsPage extends DashboardPage {
|
||||
private disposables: vscode.Disposable[] = [];
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
|
||||
modelView.onClosed(() =>
|
||||
this.disposables.forEach(d => {
|
||||
try { d.dispose(); }
|
||||
catch { }
|
||||
}));
|
||||
|
||||
this.disposables.push(this._postgresModel.onServiceUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refresh())));
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { PostgresPropertiesPage } from './postgresPropertiesPage';
|
||||
import { Dashboard } from '../../components/dashboard';
|
||||
import { PostgresDiagnoseAndSolveProblemsPage } from './postgresDiagnoseAndSolveProblemsPage';
|
||||
import { PostgresSupportRequestPage } from './postgresSupportRequestPage';
|
||||
import { PostgresResourceHealthPage } from './postgresResourceHealthPage';
|
||||
|
||||
export class PostgresDashboard extends Dashboard {
|
||||
constructor(private _context: vscode.ExtensionContext, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
@@ -24,6 +25,7 @@ export class PostgresDashboard extends Dashboard {
|
||||
const overviewPage = new PostgresOverviewPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const connectionStringsPage = new PostgresConnectionStringsPage(modelView, this._postgresModel);
|
||||
const propertiesPage = new PostgresPropertiesPage(modelView, this._controllerModel, this._postgresModel);
|
||||
const resourceHealthPage = new PostgresResourceHealthPage(modelView, this._postgresModel);
|
||||
const diagnoseAndSolveProblemsPage = new PostgresDiagnoseAndSolveProblemsPage(modelView, this._context, this._postgresModel);
|
||||
const supportRequestPage = new PostgresSupportRequestPage(modelView, this._controllerModel, this._postgresModel);
|
||||
|
||||
@@ -39,6 +41,7 @@ export class PostgresDashboard extends Dashboard {
|
||||
{
|
||||
title: loc.supportAndTroubleshooting,
|
||||
tabs: [
|
||||
resourceHealthPage.tab,
|
||||
diagnoseAndSolveProblemsPage.tab,
|
||||
supportRequestPage.tab
|
||||
]
|
||||
|
||||
@@ -14,6 +14,8 @@ import { PostgresModel, PodRole } from '../../../models/postgresModel';
|
||||
import { promptForResourceDeletion, promptAndConfirmPassword } from '../../../common/utils';
|
||||
|
||||
export class PostgresOverviewPage extends DashboardPage {
|
||||
private disposables: vscode.Disposable[] = [];
|
||||
|
||||
private propertiesLoading?: azdata.LoadingComponent;
|
||||
private kibanaLoading?: azdata.LoadingComponent;
|
||||
private grafanaLoading?: azdata.LoadingComponent;
|
||||
@@ -26,18 +28,30 @@ export class PostgresOverviewPage extends DashboardPage {
|
||||
|
||||
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.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => {
|
||||
this.refreshProperties();
|
||||
this.refreshNodes();
|
||||
}));
|
||||
modelView.onClosed(() =>
|
||||
this.disposables.forEach(d => {
|
||||
try { d.dispose(); }
|
||||
catch { }
|
||||
}));
|
||||
|
||||
this._postgresModel.onPodsUpdated(() => this.eventuallyRunOnInitialized(() => {
|
||||
this.refreshProperties();
|
||||
this.refreshNodes();
|
||||
}));
|
||||
this.disposables.push(this._controllerModel.onEndpointsUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refreshEndpoints())));
|
||||
|
||||
this.disposables.push(this._controllerModel.onRegistrationsUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refreshProperties())));
|
||||
|
||||
this.disposables.push(this._postgresModel.onServiceUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => {
|
||||
this.refreshProperties();
|
||||
this.refreshNodes();
|
||||
})));
|
||||
|
||||
this.disposables.push(this._postgresModel.onPodsUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => {
|
||||
this.refreshProperties();
|
||||
this.refreshNodes();
|
||||
})));
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
@@ -207,7 +221,7 @@ export class PostgresOverviewPage extends DashboardPage {
|
||||
vscode.window.showInformationMessage(loc.passwordReset);
|
||||
}
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.passwordResetFailed);
|
||||
vscode.window.showErrorMessage(loc.passwordResetFailed(error));
|
||||
} finally {
|
||||
resetPasswordButton.enabled = true;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,23 @@ import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
|
||||
export class PostgresPropertiesPage extends DashboardPage {
|
||||
private disposables: vscode.Disposable[] = [];
|
||||
private keyValueContainer?: KeyValueContainer;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
this._postgresModel.onServiceUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
this._controllerModel.onRegistrationsUpdated(() => this.eventuallyRunOnInitialized(() => this.refresh()));
|
||||
|
||||
modelView.onClosed(() =>
|
||||
this.disposables.forEach(d => {
|
||||
try { d.dispose(); }
|
||||
catch { }
|
||||
}));
|
||||
|
||||
this.disposables.push(this._postgresModel.onServiceUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refresh())));
|
||||
|
||||
this.disposables.push(this._controllerModel.onRegistrationsUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refresh())));
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* 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 { DashboardPage } from '../../components/dashboardPage';
|
||||
import { PostgresModel } from '../../../models/postgresModel';
|
||||
import { fromNow } from '../../../common/date';
|
||||
|
||||
export class PostgresResourceHealthPage extends DashboardPage {
|
||||
private disposables: vscode.Disposable[] = [];
|
||||
private interval: NodeJS.Timeout;
|
||||
private podsUpdated?: azdata.TextComponent;
|
||||
private podsTable?: azdata.DeclarativeTableComponent;
|
||||
private conditionsTable?: azdata.DeclarativeTableComponent;
|
||||
|
||||
constructor(protected modelView: azdata.ModelView, private _postgresModel: PostgresModel) {
|
||||
super(modelView);
|
||||
|
||||
modelView.onClosed(() => {
|
||||
try { clearInterval(this.interval); }
|
||||
catch { }
|
||||
|
||||
this.disposables.forEach(d => {
|
||||
try { d.dispose(); }
|
||||
catch { }
|
||||
});
|
||||
});
|
||||
|
||||
this.disposables.push(this._postgresModel.onServiceUpdated(
|
||||
() => this.eventuallyRunOnInitialized(() => this.refresh())));
|
||||
|
||||
// Keep the last updated timestamps up to date with the current time
|
||||
this.interval = setInterval(() => this.refresh(), 60 * 1000);
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
return loc.resourceHealth;
|
||||
}
|
||||
|
||||
protected get id(): string {
|
||||
return 'postgres-resource-health';
|
||||
}
|
||||
|
||||
protected get icon(): { dark: string; light: string; } {
|
||||
return IconPathHelper.health;
|
||||
}
|
||||
|
||||
protected get container(): azdata.Component {
|
||||
const root = this.modelView.modelBuilder.divContainer().component();
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '20px' } });
|
||||
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.resourceHealth,
|
||||
CSSStyles: { ...cssStyles.title, 'margin-bottom': '30px' }
|
||||
}).component());
|
||||
|
||||
const titleCSS = { ...cssStyles.title, 'margin-block-start': '2em', 'margin-block-end': '0' };
|
||||
content.addItem(this.modelView.modelBuilder.text().withProperties<azdata.TextComponentProperties>({
|
||||
value: loc.podOverview,
|
||||
CSSStyles: titleCSS
|
||||
}).component());
|
||||
|
||||
this.podsUpdated = this.modelView.modelBuilder.text().component();
|
||||
content.addItem(this.podsUpdated);
|
||||
|
||||
// Pod overview
|
||||
this.podsTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||
columns: [
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: { ...cssStyles.tableRow, 'font-size': '20px', 'font-weight': 'bold' }
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '50%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
}
|
||||
],
|
||||
data: []
|
||||
}).component();
|
||||
content.addItem(this.podsTable, { CSSStyles: { 'margin-bottom': '30px' } });
|
||||
|
||||
// Conditions table
|
||||
this.conditionsTable = this.modelView.modelBuilder.declarativeTable().withProperties<azdata.DeclarativeTableProperties>({
|
||||
width: '100%',
|
||||
columns: [
|
||||
{
|
||||
displayName: loc.condition,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '15%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: '',
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
width: '1%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.details,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '64%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.lastUpdated,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
width: '20%',
|
||||
isReadOnly: true,
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: { ...cssStyles.tableRow, 'white-space': 'nowrap' }
|
||||
}
|
||||
],
|
||||
data: []
|
||||
}).component();
|
||||
content.addItem(this.conditionsTable);
|
||||
|
||||
this.initialized = true;
|
||||
return root;
|
||||
}
|
||||
|
||||
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() {
|
||||
this.podsUpdated!.value = loc.updated(fromNow(this._postgresModel.serviceLastUpdated!, true));
|
||||
|
||||
this.podsTable!.data = [
|
||||
[this._postgresModel.service?.status?.podsRunning, loc.running],
|
||||
[this._postgresModel.service?.status?.podsPending, loc.pending],
|
||||
[this._postgresModel.service?.status?.podsFailed, loc.failed],
|
||||
[this._postgresModel.service?.status?.podsUnknown, loc.unknown]
|
||||
];
|
||||
|
||||
this.conditionsTable!.data = this._postgresModel.service?.status?.conditions?.map(c => {
|
||||
const healthy = c.type === 'Ready' ? c.status === 'True' : c.status === 'False';
|
||||
|
||||
const image = this.modelView.modelBuilder.image().withProperties<azdata.ImageComponentProperties>({
|
||||
iconPath: healthy ? IconPathHelper.success : IconPathHelper.fail,
|
||||
iconHeight: '20px',
|
||||
iconWidth: '20px',
|
||||
width: '20px',
|
||||
height: '20px'
|
||||
}).component();
|
||||
|
||||
return [
|
||||
c.type,
|
||||
image,
|
||||
c.message,
|
||||
fromNow(c.lastTransitionTime!, true)
|
||||
];
|
||||
}) ?? [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user