Files
azuredatastudio/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts
nasc17 b472539646 Switch withProperties to be withProps (#16380)
* Transition to withProps in arc

* Transition to withProps inputbox

* Transition to withProps in checkbox

* Transition to withProps text

* Transition to withProps in declarative table

* Transition to withProps hyperlink

* Transition to withProps in button

* Transition to withProps radiobutton

* Transition to withProps in input

* Transition to withProps button

* Transition to withProps in text

* Transition to withProps image

* Transition to withProps declare table

* Transition to withProps in table

* Transition to withProps radio button

* Transition to withProps in image

* Transition to withProps radio button

* Transition to withProps in commit

* Transition to withProps div cont

* Transition to withProps in comp

* Transition to withProps radio card

* Transition to withProps in comp icon

* Transition to withProps card

* Transition to withProps list
2021-07-21 11:12:47 -07:00

359 lines
12 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* 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 { BdcDashboardModel } from './bdcDashboardModel';
import { BdcStatusModel, InstanceStatusModel, ResourceStatusModel } from '../controller/apiGenerated';
import { getHealthStatusDisplayText, getHealthStatusIcon, getStateDisplayText, Service } from '../utils';
import { cssStyles } from '../constants';
import { isNullOrUndefined } from 'util';
import { createViewDetailsButton } from './commonControls';
import { BdcDashboardPage } from './bdcDashboardPage';
import * as loc from '../localizedConstants';
export class BdcDashboardResourceStatusPage extends BdcDashboardPage {
private resourceStatusModel: ResourceStatusModel;
private rootContainer: azdata.FlexContainer;
private instanceHealthStatusTable: azdata.DeclarativeTableComponent;
private metricsAndLogsRowsTable: azdata.DeclarativeTableComponent;
private lastUpdatedLabel: azdata.TextComponent;
constructor(model: BdcDashboardModel, modelView: azdata.ModelView, serviceName: string, private resourceName: string) {
super(model, modelView, serviceName);
this.model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
}
public get container(): azdata.FlexContainer {
// Lazily create the container only when needed
if (!this.rootContainer) {
// We do this here so that we can have the resource model to use for populating the data
// in the tables. This is to get around a timing issue with ModelView tables
this.updateResourceStatusModel(this.model.bdcStatus);
this.createContainer();
}
return this.rootContainer;
}
private createContainer(): void {
this.rootContainer = this.modelView.modelBuilder.flexContainer().withLayout(
{
flexFlow: 'column',
width: '100%',
height: '100%'
}).component();
// ##############################
// # INSTANCE HEALTH AND STATUS #
// ##############################
const healthStatusHeaderContainer = this.modelView.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '20px' }).component();
this.rootContainer.addItem(healthStatusHeaderContainer, { CSSStyles: { 'padding-left': '10px', 'padding-top': '15px' } });
// Header label
const healthStatusHeaderLabel = this.modelView.modelBuilder.text()
.withProps({
value: loc.healthStatusDetails,
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '10px' }
})
.component();
healthStatusHeaderContainer.addItem(healthStatusHeaderLabel, { CSSStyles: { ...cssStyles.title } });
// Last updated label
this.lastUpdatedLabel = this.modelView.modelBuilder.text()
.withProps({
value: loc.lastUpdated(this.model.bdcStatusLastUpdated),
CSSStyles: { ...cssStyles.lastUpdatedText }
}).component();
healthStatusHeaderContainer.addItem(this.lastUpdatedLabel, { CSSStyles: { 'margin-left': '45px' } });
this.instanceHealthStatusTable = this.modelView.modelBuilder.declarativeTable()
.withProps(
{
columns: [
{ // status icon
displayName: '',
ariaLabel: loc.statusIcon,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 25,
headerCssStyles: {
'border': 'none'
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
},
},
{ // instance
displayName: loc.instance,
valueType: azdata.DeclarativeDataType.string,
isReadOnly: true,
width: 100,
headerCssStyles: {
'border': 'none',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
},
},
{ // state
displayName: loc.state,
valueType: azdata.DeclarativeDataType.string,
isReadOnly: true,
width: 150,
headerCssStyles: {
'border': 'none',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
},
},
{ // health status
displayName: loc.healthStatus,
valueType: azdata.DeclarativeDataType.string,
isReadOnly: true,
width: 100,
headerCssStyles: {
'border': 'none',
'text-align': 'left',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
}
},
{ // view details button
displayName: '',
ariaLabel: loc.viewErrorDetails,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 150,
headerCssStyles: {
'border': 'none'
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
},
},
],
data: this.createHealthStatusRows(),
ariaLabel: loc.healthStatusDetails
}).component();
this.rootContainer.addItem(this.instanceHealthStatusTable, { flex: '0 0 auto' });
// ####################
// # METRICS AND LOGS #
// ####################
// Title label
const endpointsLabel = this.modelView.modelBuilder.text()
.withProps({ value: loc.metricsAndLogs, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.component();
this.rootContainer.addItem(endpointsLabel, { CSSStyles: { 'padding-left': '10px', ...cssStyles.title } });
let metricsAndLogsColumns: azdata.DeclarativeTableColumn[] =
[
{ // instance
displayName: loc.instance,
valueType: azdata.DeclarativeDataType.string,
isReadOnly: true,
width: 125,
headerCssStyles: {
'border': 'none',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
}
},
{ // node metrics
displayName: loc.nodeMetrics,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 100,
headerCssStyles: {
'border': 'none',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
}
}
];
// Only show SQL metrics column for SQL resource instances
if (this.serviceName.toLowerCase() === Service.sql) {
metricsAndLogsColumns.push(
{ // sql metrics
displayName: loc.sqlMetrics,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 100,
headerCssStyles: {
'border': 'none',
'text-align': 'left',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
}
});
}
metricsAndLogsColumns.push(
{ // logs
displayName: loc.logs,
valueType: azdata.DeclarativeDataType.component,
isReadOnly: true,
width: 100,
headerCssStyles: {
'border': 'none',
'text-align': 'left',
...cssStyles.tableHeader
},
rowCssStyles: {
'border-top': 'solid 1px #ccc',
'border-bottom': 'solid 1px #ccc',
'border-left': 'none',
'border-right': 'none'
}
});
this.metricsAndLogsRowsTable = this.modelView.modelBuilder.declarativeTable()
.withProps(
{
columns: metricsAndLogsColumns,
data: this.createMetricsAndLogsRows(),
ariaLabel: loc.metricsAndLogs
}).component();
this.rootContainer.addItem(this.metricsAndLogsRowsTable, { flex: '0 0 auto' });
this.initialized = true;
}
private updateResourceStatusModel(bdcStatus?: BdcStatusModel): void {
// If we can't find the resource model for this resource then just
// default to keeping what we had originally
if (!bdcStatus) {
return;
}
const service = bdcStatus.services ? bdcStatus.services.find(s => s.serviceName === this.serviceName) : undefined;
this.resourceStatusModel = service ? service.resources.find(r => r.resourceName === this.resourceName) : this.resourceStatusModel;
}
private handleBdcStatusUpdate(bdcStatus?: BdcStatusModel): void {
this.updateResourceStatusModel(bdcStatus);
if (!this.resourceStatusModel || isNullOrUndefined(this.resourceStatusModel.instances)) {
return;
}
this.lastUpdatedLabel.value = loc.lastUpdated(this.model.bdcStatusLastUpdated);
this.instanceHealthStatusTable.data = this.createHealthStatusRows();
this.metricsAndLogsRowsTable.data = this.createMetricsAndLogsRows();
}
private createMetricsAndLogsRows(): any[][] {
return this.resourceStatusModel ? this.resourceStatusModel.instances.map(instanceStatus => this.createMetricsAndLogsRow(instanceStatus)) : [];
}
private createHealthStatusRows(): any[][] {
return this.resourceStatusModel ? this.resourceStatusModel.instances.map(instanceStatus => this.createHealthStatusRow(instanceStatus)) : [];
}
private createMetricsAndLogsRow(instanceStatus: InstanceStatusModel): any[] {
const row: any[] = [instanceStatus.instanceName];
// Not all instances have all logs available - in that case just display N/A instead of a link
if (isNullOrUndefined(instanceStatus.dashboards) || isNullOrUndefined(instanceStatus.dashboards.nodeMetricsUrl)) {
row.push(this.modelView.modelBuilder.text().withProps({ value: loc.notAvailable, CSSStyles: { ...cssStyles.text } }).component());
} else {
row.push(this.modelView.modelBuilder.hyperlink().withProps({
label: loc.view,
url: instanceStatus.dashboards.nodeMetricsUrl,
title: instanceStatus.dashboards.nodeMetricsUrl,
ariaLabel: loc.viewNodeMetrics(instanceStatus.dashboards.nodeMetricsUrl),
CSSStyles: { ...cssStyles.text }
}).component());
}
// Only show SQL metrics column for SQL resource instances
if (this.serviceName === Service.sql) {
// Not all instances have all logs available - in that case just display N/A instead of a link
if (isNullOrUndefined(instanceStatus.dashboards) || isNullOrUndefined(instanceStatus.dashboards.sqlMetricsUrl)) {
row.push(this.modelView.modelBuilder.text().withProps({ value: loc.notAvailable, CSSStyles: { ...cssStyles.text } }).component());
} else {
row.push(this.modelView.modelBuilder.hyperlink().withProps({
label: loc.view,
url: instanceStatus.dashboards.sqlMetricsUrl,
title: instanceStatus.dashboards.sqlMetricsUrl,
ariaLabel: loc.viewSqlMetrics(instanceStatus.dashboards.sqlMetricsUrl),
CSSStyles: { ...cssStyles.text }
}).component());
}
}
if (isNullOrUndefined(instanceStatus.dashboards) || isNullOrUndefined(instanceStatus.dashboards.logsUrl)) {
row.push(this.modelView.modelBuilder.text().withProps({ value: loc.notAvailable, CSSStyles: { ...cssStyles.text } }).component());
} else {
row.push(this.modelView.modelBuilder.hyperlink().withProps({
label: loc.view,
url: instanceStatus.dashboards.logsUrl,
title: instanceStatus.dashboards.logsUrl,
ariaLabel: loc.viewLogs(instanceStatus.dashboards.logsUrl),
CSSStyles: { ...cssStyles.text }
}).component());
}
return row;
}
private createHealthStatusRow(instanceStatus: InstanceStatusModel): any[] {
const statusIconCell = this.modelView.modelBuilder.text()
.withProps({
value: getHealthStatusIcon(instanceStatus.healthStatus),
ariaRole: 'img',
title: getHealthStatusDisplayText(instanceStatus.healthStatus),
CSSStyles: { 'user-select': 'none', ...cssStyles.text }
}).component();
const viewDetailsButton = instanceStatus.healthStatus !== 'healthy' && instanceStatus.details && instanceStatus.details.length > 0 ? createViewDetailsButton(this.modelView.modelBuilder, instanceStatus.details) : undefined;
return [
statusIconCell,
instanceStatus.instanceName,
getStateDisplayText(instanceStatus.state),
getHealthStatusDisplayText(instanceStatus.healthStatus),
viewDetailsButton];
}
}