mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M5 6H11V3H5V6ZM6 4H10V5H6V4Z" fill="white"/>
|
||||||
|
<path d="M1 0H14V16H1V13H0V12H1V10.023H0V9.023H1V7.039H0V6.039H1V4H0V3H1V0ZM13 15V1H2V3H3V4H2V6.039H3V7.039H2V9.023H3V10.023H2V12H3V13H2V15H13Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 317 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3bb44a;}</style></defs><title>success_16x16</title><path class="cls-1" d="M16,3.16,5.48,13.69,0,8.2l.89-.89,4.6,4.59,9.63-9.62Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 255 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.12 13.9725L15 12.5L9.37927 2H7.61924L1.9985 12.5L2.87852 13.9725H14.12ZM2.87852 12.9725L8.49925 2.47249L14.12 12.9725H2.87852ZM7.98952 6H8.98802V10H7.98952V6ZM7.98952 11H8.98802V12H7.98952V11Z" fill="#FFCC00"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 367 B |
7
extensions/big-data-cluster/resources/light/notebook.svg
Normal file
7
extensions/big-data-cluster/resources/light/notebook.svg
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<title>Artboard 20</title>
|
||||||
|
<g>
|
||||||
|
<path d="M5,6h6V3H5ZM6,4h4V5H6Z"/>
|
||||||
|
<path d="M1,0H14V16H1V13H0V12H1V10.023H0v-1H1V7.039H0v-1H1V4H0V3H1ZM13,15V1H2V3H3V4H2V6.039H3v1H2V9.023H3v1H2V12H3v1H2v2Z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 301 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3bb44a;}</style></defs><title>success_16x16</title><path class="cls-1" d="M16,3.16,5.48,13.69,0,8.2l.89-.89,4.6,4.59,9.63-9.62Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 255 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.12 13.9725L15 12.5L9.37927 2H7.61924L1.9985 12.5L2.87852 13.9725H14.12ZM2.87852 12.9725L8.49925 2.47249L14.12 12.9725H2.87852ZM7.98952 6H8.98802V10H7.98952V6ZM7.98952 11H8.98802V12H7.98952V11Z" fill="#FFCC00"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.12 13.9725L15 12.5L9.37927 2H7.61924L1.9985 12.5L2.87852 13.9725H14.12ZM2.87852 12.9725L8.49925 2.47249L14.12 12.9725H2.87852ZM7.98952 6H8.98802V10H7.98952V6ZM7.98952 11H8.98802V12H7.98952V11Z" fill="#DDB100"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 631 B |
@@ -17,36 +17,56 @@ export enum BdcItemType {
|
|||||||
loadingController = 'bigDataClusters.itemType.loadingControllerNode'
|
loadingController = 'bigDataClusters.itemType.loadingControllerNode'
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IconPath {
|
export interface IconPath {
|
||||||
|
dark: string;
|
||||||
|
light: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IconPathHelper {
|
||||||
private static extensionContext: vscode.ExtensionContext;
|
private static extensionContext: vscode.ExtensionContext;
|
||||||
|
|
||||||
public static controllerNode: { dark: string, light: string };
|
public static controllerNode: IconPath;
|
||||||
public static folderNode: { dark: string, light: string };
|
public static folderNode: IconPath;
|
||||||
public static sqlMasterNode: { dark: string, light: string };
|
public static sqlMasterNode: IconPath;
|
||||||
public static copy: { dark: string, light: string };
|
public static copy: IconPath;
|
||||||
public static refresh: { dark: string, light: string };
|
public static refresh: IconPath;
|
||||||
|
public static status_ok: IconPath;
|
||||||
|
public static status_warning: IconPath;
|
||||||
|
public static notebook: IconPath;
|
||||||
|
|
||||||
public static setExtensionContext(extensionContext: vscode.ExtensionContext) {
|
public static setExtensionContext(extensionContext: vscode.ExtensionContext) {
|
||||||
IconPath.extensionContext = extensionContext;
|
IconPathHelper.extensionContext = extensionContext;
|
||||||
IconPath.controllerNode = {
|
IconPathHelper.controllerNode = {
|
||||||
dark: IconPath.extensionContext.asAbsolutePath('resources/dark/bigDataCluster_controller.svg'),
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/bigDataCluster_controller.svg'),
|
||||||
light: IconPath.extensionContext.asAbsolutePath('resources/light/bigDataCluster_controller.svg')
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/bigDataCluster_controller.svg')
|
||||||
};
|
};
|
||||||
IconPath.folderNode = {
|
IconPathHelper.folderNode = {
|
||||||
dark: IconPath.extensionContext.asAbsolutePath('resources/dark/folder_inverse.svg'),
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/folder_inverse.svg'),
|
||||||
light: IconPath.extensionContext.asAbsolutePath('resources/light/folder.svg')
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/folder.svg')
|
||||||
};
|
};
|
||||||
IconPath.sqlMasterNode = {
|
IconPathHelper.sqlMasterNode = {
|
||||||
dark: IconPath.extensionContext.asAbsolutePath('resources/dark/sql_bigdata_cluster_inverse.svg'),
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/sql_bigdata_cluster_inverse.svg'),
|
||||||
light: IconPath.extensionContext.asAbsolutePath('resources/light/sql_bigdata_cluster.svg')
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/sql_bigdata_cluster.svg')
|
||||||
};
|
};
|
||||||
IconPath.copy = {
|
IconPathHelper.copy = {
|
||||||
light: IconPath.extensionContext.asAbsolutePath('resources/light/copy.svg'),
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/copy.svg'),
|
||||||
dark: IconPath.extensionContext.asAbsolutePath('resources/dark/copy_inverse.svg')
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/copy_inverse.svg')
|
||||||
};
|
};
|
||||||
IconPath.refresh = {
|
IconPathHelper.refresh = {
|
||||||
light: IconPath.extensionContext.asAbsolutePath('resources/light/refresh.svg'),
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/refresh.svg'),
|
||||||
dark: IconPath.extensionContext.asAbsolutePath('resources/dark/refresh_inverse.svg')
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/refresh_inverse.svg')
|
||||||
|
};
|
||||||
|
IconPathHelper.status_ok = {
|
||||||
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/status_ok_light.svg'),
|
||||||
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/status_ok_dark.svg')
|
||||||
|
};
|
||||||
|
IconPathHelper.status_warning = {
|
||||||
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/status_warning_light.svg'),
|
||||||
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/status_warning_dark.svg')
|
||||||
|
};
|
||||||
|
IconPathHelper.notebook = {
|
||||||
|
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/notebook.svg'),
|
||||||
|
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/notebook_inverse.svg')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
import localVarRequest = require('request');
|
import localVarRequest = require('request');
|
||||||
import http = require('http');
|
import http = require('http');
|
||||||
import Promise = require('bluebird');
|
|
||||||
|
|
||||||
let defaultBasePath = 'https://localhost';
|
let defaultBasePath = 'https://localhost';
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { BdcDashboardModel } from './bdcDashboardModel';
|
import { BdcDashboardModel } from './bdcDashboardModel';
|
||||||
import { IconPath } from '../constants';
|
import { IconPathHelper } from '../constants';
|
||||||
import { BdcServiceStatusPage } from './bdcServiceStatusPage';
|
import { BdcServiceStatusPage } from './bdcServiceStatusPage';
|
||||||
import { BdcDashboardOverviewPage } from './bdcDashboardOverviewPage';
|
import { BdcDashboardOverviewPage } from './bdcDashboardOverviewPage';
|
||||||
import { EndpointModel, BdcStatusModel, ServiceStatusModel } from '../controller/apiGenerated';
|
import { EndpointModel, BdcStatusModel, ServiceStatusModel } from '../controller/apiGenerated';
|
||||||
|
import { getHealthStatusDot, getServiceNameDisplayText } from '../utils';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -59,13 +61,30 @@ export class BdcDashboard {
|
|||||||
const refreshButton = modelView.modelBuilder.button()
|
const refreshButton = modelView.modelBuilder.button()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
label: localize('bdc.dashboard.refreshButton', "Refresh"),
|
label: localize('bdc.dashboard.refreshButton', "Refresh"),
|
||||||
iconPath: IconPath.refresh,
|
iconPath: IconPathHelper.refresh,
|
||||||
height: '50'
|
height: '50px'
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
refreshButton.onDidClick(() => this.model.refresh());
|
refreshButton.onDidClick(() => this.model.refresh());
|
||||||
|
|
||||||
const toolbarContainer = modelView.modelBuilder.toolbarContainer().withToolbarItems([{ component: refreshButton }]).component();
|
const openTroubleshootNotebookButton = modelView.modelBuilder.button()
|
||||||
|
.withProperties({
|
||||||
|
label: localize('bdc.dashboard.troubleshootButton', "Troubleshoot"),
|
||||||
|
iconPath: IconPathHelper.notebook,
|
||||||
|
height: '50px'
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
openTroubleshootNotebookButton.onDidClick(() => {
|
||||||
|
vscode.commands.executeCommand('mssqlCluster.task.openNotebook');
|
||||||
|
});
|
||||||
|
|
||||||
|
const toolbarContainer = modelView.modelBuilder.toolbarContainer()
|
||||||
|
.withToolbarItems(
|
||||||
|
[
|
||||||
|
{ component: refreshButton },
|
||||||
|
{ component: openTroubleshootNotebookButton }
|
||||||
|
]
|
||||||
|
).component();
|
||||||
|
|
||||||
rootContainer.addItem(toolbarContainer, { flex: '0 0 auto' });
|
rootContainer.addItem(toolbarContainer, { flex: '0 0 auto' });
|
||||||
|
|
||||||
@@ -143,7 +162,7 @@ export class BdcDashboard {
|
|||||||
if (this.initialized && !this.serviceTabsCreated && services) {
|
if (this.initialized && !this.serviceTabsCreated && services) {
|
||||||
// Add a nav item for each service
|
// Add a nav item for each service
|
||||||
services.forEach(s => {
|
services.forEach(s => {
|
||||||
const navItem = createServiceNavTab(this.modelView.modelBuilder, getFriendlyServiceName(s.serviceName));
|
const navItem = createServiceNavTab(this.modelView.modelBuilder, s);
|
||||||
const serviceStatusPage = new BdcServiceStatusPage(s.serviceName, this.model, this.modelView).container;
|
const serviceStatusPage = new BdcServiceStatusPage(s.serviceName, this.model, this.modelView).container;
|
||||||
navItem.onDidClick(() => {
|
navItem.onDidClick(() => {
|
||||||
this.mainAreaContainer.removeItem(this.currentPage);
|
this.mainAreaContainer.removeItem(this.currentPage);
|
||||||
@@ -157,28 +176,11 @@ export class BdcDashboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createServiceNavTab(modelBuilder: azdata.ModelBuilder, serviceName: string): azdata.DivContainer {
|
function createServiceNavTab(modelBuilder: azdata.ModelBuilder, serviceStatus: ServiceStatusModel): azdata.DivContainer {
|
||||||
const navItem = modelBuilder.divContainer().withLayout({ width: navWidth, height: '30px' }).component();
|
const div = modelBuilder.divContainer().withLayout({ width: navWidth, height: '30px' }).component();
|
||||||
navItem.addItem(modelBuilder.text().withProperties({ value: serviceName }).component(), { CSSStyles: { 'user-select': 'text' } });
|
const innerContainer = modelBuilder.flexContainer().withLayout({ width: navWidth, height: '30px', flexFlow: 'row' }).component();
|
||||||
return navItem;
|
innerContainer.addItem(modelBuilder.text().withProperties({ value: getHealthStatusDot(serviceStatus.healthStatus), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'none', 'color': 'red', 'font-size': '40px', 'width': '20px' } }).component(), { flex: '0 0 auto' });
|
||||||
}
|
innerContainer.addItem(modelBuilder.text().withProperties({ value: getServiceNameDisplayText(serviceStatus.serviceName), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component(), { flex: '0 0 auto' });
|
||||||
|
div.addItem(innerContainer);
|
||||||
function getFriendlyServiceName(serviceName: string): string {
|
return div;
|
||||||
serviceName = serviceName || '';
|
|
||||||
switch (serviceName.toLowerCase()) {
|
|
||||||
case 'sql':
|
|
||||||
return localize('bdc.dashboard.sql', "SQL Server");
|
|
||||||
case 'hdfs':
|
|
||||||
return localize('bdc.dashboard.hdfs', "HDFS");
|
|
||||||
case 'spark':
|
|
||||||
return localize('bdc.dashboard.spark', "Spark");
|
|
||||||
case 'control':
|
|
||||||
return localize('bdc.dashboard.control', "Control");
|
|
||||||
case 'gateway':
|
|
||||||
return localize('bdc.dashboard.gateway', "Gateway");
|
|
||||||
case 'app':
|
|
||||||
return localize('bdc.dashboard.app', "App");
|
|
||||||
default:
|
|
||||||
return serviceName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ export class BdcDashboardModel {
|
|||||||
|
|
||||||
private _bdcStatus: BdcStatusModel;
|
private _bdcStatus: BdcStatusModel;
|
||||||
private _endpoints: EndpointModel[] = [];
|
private _endpoints: EndpointModel[] = [];
|
||||||
|
private _bdcStatusLastUpdated: Date;
|
||||||
|
private _endpointsLastUpdated: Date;
|
||||||
private readonly _onDidUpdateEndpoints = new vscode.EventEmitter<EndpointModel[]>();
|
private readonly _onDidUpdateEndpoints = new vscode.EventEmitter<EndpointModel[]>();
|
||||||
private readonly _onDidUpdateBdcStatus = new vscode.EventEmitter<BdcStatusModel>();
|
private readonly _onDidUpdateBdcStatus = new vscode.EventEmitter<BdcStatusModel>();
|
||||||
public onDidUpdateEndpoints = this._onDidUpdateEndpoints.event;
|
public onDidUpdateEndpoints = this._onDidUpdateEndpoints.event;
|
||||||
@@ -31,40 +33,26 @@ export class BdcDashboardModel {
|
|||||||
return this._endpoints || [];
|
return this._endpoints || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get bdcStatusLastUpdated(): Date {
|
||||||
|
return this._bdcStatusLastUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get endpointsLastUpdated(): Date {
|
||||||
|
return this._endpointsLastUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
public async refresh(): Promise<void> {
|
public async refresh(): Promise<void> {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
getBdcStatus(this.url, this.username, this.password, true).then(response => {
|
getBdcStatus(this.url, this.username, this.password, true).then(response => {
|
||||||
this._bdcStatus = response.bdcStatus;
|
this._bdcStatus = response.bdcStatus;
|
||||||
|
this._bdcStatusLastUpdated = new Date();
|
||||||
this._onDidUpdateBdcStatus.fire(this.bdcStatus);
|
this._onDidUpdateBdcStatus.fire(this.bdcStatus);
|
||||||
}),
|
}),
|
||||||
getEndPoints(this.url, this.username, this.password, true).then(response => {
|
getEndPoints(this.url, this.username, this.password, true).then(response => {
|
||||||
this._endpoints = response.endPoints || [];
|
this._endpoints = response.endPoints || [];
|
||||||
|
this._endpointsLastUpdated = new Date();
|
||||||
this._onDidUpdateEndpoints.fire(this.serviceEndpoints);
|
this._onDidUpdateEndpoints.fire(this.serviceEndpoints);
|
||||||
})
|
})
|
||||||
]).catch(error => showErrorMessage(error));
|
]).catch(error => showErrorMessage(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Endpoint {
|
|
||||||
gateway = 'gateway',
|
|
||||||
sparkHistory = 'spark-history',
|
|
||||||
yarnUi = 'yarn-ui',
|
|
||||||
appProxy = 'app-proxy',
|
|
||||||
mgmtproxy = 'mgmtproxy',
|
|
||||||
managementProxy = 'management-proxy',
|
|
||||||
logsui = 'logsui',
|
|
||||||
metricsui = 'metricsui',
|
|
||||||
controller = 'controller',
|
|
||||||
sqlServerMaster = 'sql-server-master',
|
|
||||||
webhdfs = 'webhdfs',
|
|
||||||
livy = 'livy'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Service {
|
|
||||||
sql = 'sql',
|
|
||||||
hdfs = 'hdfs',
|
|
||||||
spark = 'spark',
|
|
||||||
control = 'control',
|
|
||||||
gateway = 'gateway',
|
|
||||||
app = 'app'
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,51 +7,35 @@
|
|||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { BdcDashboardModel, Endpoint, Service } from './bdcDashboardModel';
|
import { BdcDashboardModel } from './bdcDashboardModel';
|
||||||
import { IconPath } from '../constants';
|
import { IconPathHelper } from '../constants';
|
||||||
|
import { getStateDisplayText, getHealthStatusDisplayText, getHealthStatusIcon, getEndpointDisplayText, getServiceNameDisplayText, Endpoint } from '../utils';
|
||||||
import { EndpointModel, ServiceStatusModel, BdcStatusModel } from '../controller/apiGenerated';
|
import { EndpointModel, ServiceStatusModel, BdcStatusModel } from '../controller/apiGenerated';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
interface IServiceStatusRow {
|
const overviewIconColumnWidth = '50px';
|
||||||
stateLoadingComponent: azdata.LoadingComponent;
|
|
||||||
healthStatusLoadingComponent: azdata.LoadingComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IServiceEndpointRow {
|
|
||||||
endpointLoadingComponent: azdata.LoadingComponent;
|
|
||||||
isHyperlink: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const navWidth = '175px';
|
|
||||||
const overviewServiceNameCellWidth = '100px';
|
const overviewServiceNameCellWidth = '100px';
|
||||||
const overviewStateCellWidth = '75px';
|
const overviewStateCellWidth = '75px';
|
||||||
const overviewHealthStatusCellWidth = '75px';
|
const overviewHealthStatusCellWidth = '100px';
|
||||||
|
|
||||||
const serviceEndpointRowServiceNameCellWidth = '125px';
|
const serviceEndpointRowServiceNameCellWidth = '125px';
|
||||||
const serviceEndpointRowEndpointCellWidth = '350px';
|
const serviceEndpointRowEndpointCellWidth = '350px';
|
||||||
|
|
||||||
|
const hyperlinkedEndpoints = [Endpoint.metricsui, Endpoint.logsui, Endpoint.sparkHistory, Endpoint.yarnUi];
|
||||||
|
|
||||||
export class BdcDashboardOverviewPage {
|
export class BdcDashboardOverviewPage {
|
||||||
|
|
||||||
private initialized: boolean = false;
|
private initialized: boolean = false;
|
||||||
|
private modelBuilder: azdata.ModelBuilder;
|
||||||
|
|
||||||
|
private lastUpdatedLabel: azdata.TextComponent;
|
||||||
private clusterStateLoadingComponent: azdata.LoadingComponent;
|
private clusterStateLoadingComponent: azdata.LoadingComponent;
|
||||||
private clusterHealthStatusLoadingComponent: azdata.LoadingComponent;
|
private clusterHealthStatusLoadingComponent: azdata.LoadingComponent;
|
||||||
|
|
||||||
private sqlServerStatusRow: IServiceStatusRow;
|
private serviceStatusRowContainer: azdata.FlexContainer;
|
||||||
private hdfsStatusRow: IServiceStatusRow;
|
|
||||||
private sparkStatusRow: IServiceStatusRow;
|
|
||||||
private controlStatusRow: IServiceStatusRow;
|
|
||||||
private gatewayStatusRow: IServiceStatusRow;
|
|
||||||
private appStatusRow: IServiceStatusRow;
|
|
||||||
|
|
||||||
private sqlServerEndpointRow: IServiceEndpointRow;
|
private endpointsRowContainer: azdata.FlexContainer;
|
||||||
private controllerEndpointRow: IServiceEndpointRow;
|
|
||||||
private hdfsSparkGatewayEndpointRow: IServiceEndpointRow;
|
|
||||||
private sparkHistoryEndpointRow: IServiceEndpointRow;
|
|
||||||
private yarnHistoryEndpointRow: IServiceEndpointRow;
|
|
||||||
private grafanaDashboardEndpointRow: IServiceEndpointRow;
|
|
||||||
private kibanaDashboardEndpointRow: IServiceEndpointRow;
|
|
||||||
|
|
||||||
constructor(private model: BdcDashboardModel) {
|
constructor(private model: BdcDashboardModel) {
|
||||||
this.model.onDidUpdateEndpoints(endpoints => this.handleEndpointsUpdate(endpoints));
|
this.model.onDidUpdateEndpoints(endpoints => this.handleEndpointsUpdate(endpoints));
|
||||||
@@ -59,6 +43,7 @@ export class BdcDashboardOverviewPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public create(view: azdata.ModelView): azdata.FlexContainer {
|
public create(view: azdata.ModelView): azdata.FlexContainer {
|
||||||
|
this.modelBuilder = view.modelBuilder;
|
||||||
const rootContainer = view.modelBuilder.flexContainer().withLayout(
|
const rootContainer = view.modelBuilder.flexContainer().withLayout(
|
||||||
{
|
{
|
||||||
flexFlow: 'column',
|
flexFlow: 'column',
|
||||||
@@ -109,30 +94,51 @@ export class BdcDashboardOverviewPage {
|
|||||||
// # OVERVIEW #
|
// # OVERVIEW #
|
||||||
// ############
|
// ############
|
||||||
|
|
||||||
|
const overviewHeaderContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '20px' }).component();
|
||||||
|
rootContainer.addItem(overviewHeaderContainer, { CSSStyles: { 'padding-left': '10px', 'padding-top': '15px' } });
|
||||||
|
|
||||||
const overviewLabel = view.modelBuilder.text()
|
const overviewLabel = view.modelBuilder.text()
|
||||||
.withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.overviewHeader', "Cluster Overview"), CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
|
.withProperties<azdata.TextComponentProperties>({
|
||||||
|
value: localize('bdc.dashboard.overviewHeader', "Cluster Overview"),
|
||||||
|
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||||
|
})
|
||||||
.component();
|
.component();
|
||||||
rootContainer.addItem(overviewLabel, { CSSStyles: { 'font-size': '20px', 'font-weight': 'bold', 'padding-left': '10px' } });
|
|
||||||
|
overviewHeaderContainer.addItem(overviewLabel, { CSSStyles: { 'font-size': '20px', 'font-weight': 'bold' } });
|
||||||
|
|
||||||
|
this.lastUpdatedLabel = view.modelBuilder.text()
|
||||||
|
.withProperties({
|
||||||
|
value: localize('bdc.dashboard.lastUpdated', "Last Updated : {0}", '-'),
|
||||||
|
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'color': 'lightgray' }
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
overviewHeaderContainer.addItem(this.lastUpdatedLabel, { CSSStyles: { 'margin-left': '45px' } });
|
||||||
|
|
||||||
const overviewContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component();
|
const overviewContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component();
|
||||||
|
|
||||||
// Service Status header row
|
// Service Status header row
|
||||||
const serviceStatusHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
const serviceStatusHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
||||||
|
const serviceStatusIconHeader = view.modelBuilder.text().component();
|
||||||
|
serviceStatusHeaderRow.addItem(serviceStatusIconHeader, { CSSStyles: { 'width': overviewIconColumnWidth, 'min-width': overviewIconColumnWidth } });
|
||||||
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.serviceNameHeader', "Service Name") }).component();
|
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.serviceNameHeader', "Service Name") }).component();
|
||||||
serviceStatusHeaderRow.addItem(nameCell, { CSSStyles: { 'width': overviewServiceNameCellWidth, 'min-width': overviewServiceNameCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
serviceStatusHeaderRow.addItem(nameCell, { CSSStyles: { 'width': overviewServiceNameCellWidth, 'min-width': overviewServiceNameCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
const stateCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.stateHeader', "State") }).component();
|
const stateCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.stateHeader', "State"), CSSStyles: { 'text-align': 'center', 'font-weight': 'bold' } }).component();
|
||||||
serviceStatusHeaderRow.addItem(stateCell, { CSSStyles: { 'width': overviewStateCellWidth, 'min-width': overviewStateCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
serviceStatusHeaderRow.addItem(stateCell, { CSSStyles: { 'width': overviewStateCellWidth, 'min-width': overviewStateCellWidth, 'user-select': 'text' } });
|
||||||
const healthStatusCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatusHeader', "Health Status") }).component();
|
const healthStatusCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatusHeader', "Health Status"), CSSStyles: { 'text-align': 'center', 'font-weight': 'bold' } }).component();
|
||||||
serviceStatusHeaderRow.addItem(healthStatusCell, { CSSStyles: { 'width': overviewHealthStatusCellWidth, 'min-width': overviewHealthStatusCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
serviceStatusHeaderRow.addItem(healthStatusCell, { CSSStyles: { 'width': overviewHealthStatusCellWidth, 'min-width': overviewHealthStatusCellWidth, 'user-select': 'text' } });
|
||||||
overviewContainer.addItem(serviceStatusHeaderRow, { CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
overviewContainer.addItem(serviceStatusHeaderRow, { CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
this.sqlServerStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.sqlServerLabel', "SQL Server"));
|
// Service Status row container
|
||||||
this.hdfsStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.hdfsLabel', "HDFS"));
|
this.serviceStatusRowContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
||||||
this.sparkStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.sparkLabel', "Spark"));
|
// Note we don't give the rows container as a child of the loading component since in order to align the loading component correctly
|
||||||
this.controlStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.controlLabel', "Control"));
|
// messes up the layout for the row container that we display after loading is finished. Instead we just remove the loading component
|
||||||
this.gatewayStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.gatewayLabel', "Gateway"));
|
// and replace it with the rows directly
|
||||||
this.appStatusRow = createServiceStatusRow(view.modelBuilder, overviewContainer, localize('bdc.dashboard.appLabel', "App"));
|
const serviceStatusRowContainerLoadingComponent = view.modelBuilder.loadingComponent()
|
||||||
|
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
||||||
|
.component();
|
||||||
|
this.serviceStatusRowContainer.addItem(serviceStatusRowContainerLoadingComponent, { flex: '0 0 auto', CSSStyles: { 'padding-left': '150px', width: '30px' } });
|
||||||
|
|
||||||
|
overviewContainer.addItem(this.serviceStatusRowContainer);
|
||||||
rootContainer.addItem(overviewContainer, { flex: '0 0 auto' });
|
rootContainer.addItem(overviewContainer, { flex: '0 0 auto' });
|
||||||
|
|
||||||
// #####################
|
// #####################
|
||||||
@@ -154,13 +160,16 @@ export class BdcDashboardOverviewPage {
|
|||||||
endpointsHeaderRow.addItem(endpointsEndpointHeaderCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
endpointsHeaderRow.addItem(endpointsEndpointHeaderCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
endpointsContainer.addItem(endpointsHeaderRow, { CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
endpointsContainer.addItem(endpointsHeaderRow, { CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
this.sqlServerEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('sql-server'), false);
|
this.endpointsRowContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
||||||
this.controllerEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('controller'), false);
|
// Note we don't give the rows container as a child of the loading component since in order to align the loading component correctly
|
||||||
this.hdfsSparkGatewayEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('gateway'), false);
|
// messes up the layout for the row container that we display after loading is finished. Instead we just remove the loading component
|
||||||
this.sparkHistoryEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('spark-history'), true);
|
// and replace it with the rows directly
|
||||||
this.yarnHistoryEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('yarn-history'), true);
|
const endpointRowContainerLoadingComponent = view.modelBuilder.loadingComponent()
|
||||||
this.grafanaDashboardEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('grafana'), true);
|
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
||||||
this.kibanaDashboardEndpointRow = createServiceEndpointRow(view.modelBuilder, endpointsContainer, getFriendlyEndpointNames('kibana'), true);
|
.component();
|
||||||
|
this.endpointsRowContainer.addItem(endpointRowContainerLoadingComponent, { flex: '0 0 auto', CSSStyles: { 'padding-left': '150px', width: '30px' } });
|
||||||
|
|
||||||
|
endpointsContainer.addItem(this.endpointsRowContainer);
|
||||||
|
|
||||||
rootContainer.addItem(endpointsContainer, { flex: '0 0 auto' });
|
rootContainer.addItem(endpointsContainer, { flex: '0 0 auto' });
|
||||||
|
|
||||||
@@ -177,31 +186,22 @@ export class BdcDashboardOverviewPage {
|
|||||||
if (!this.initialized || !bdcStatus) {
|
if (!this.initialized || !bdcStatus) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.lastUpdatedLabel.value =
|
||||||
|
localize('bdc.dashboard.lastUpdated', "Last Updated : {0}",
|
||||||
|
this.model.bdcStatusLastUpdated ?
|
||||||
|
`${this.model.bdcStatusLastUpdated.toLocaleDateString()} ${this.model.bdcStatusLastUpdated.toLocaleTimeString()}`
|
||||||
|
: '-');
|
||||||
|
|
||||||
this.clusterStateLoadingComponent.loading = false;
|
this.clusterStateLoadingComponent.loading = false;
|
||||||
this.clusterHealthStatusLoadingComponent.loading = false;
|
this.clusterHealthStatusLoadingComponent.loading = false;
|
||||||
this.clusterStateLoadingComponent.component.updateProperty('value', bdcStatus.state);
|
(<azdata.TextComponent>this.clusterStateLoadingComponent.component).value = getStateDisplayText(bdcStatus.state);
|
||||||
this.clusterHealthStatusLoadingComponent.component.updateProperty('value', bdcStatus.healthStatus);
|
(<azdata.TextComponent>this.clusterHealthStatusLoadingComponent.component).value = getHealthStatusDisplayText(bdcStatus.healthStatus);
|
||||||
|
|
||||||
if (bdcStatus.services) {
|
if (bdcStatus.services) {
|
||||||
// Service Status
|
this.serviceStatusRowContainer.clearItems();
|
||||||
const sqlServerServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.sql);
|
bdcStatus.services.forEach((s, i) => {
|
||||||
updateServiceStatusRow(this.sqlServerStatusRow, sqlServerServiceStatus);
|
createServiceStatusRow(this.modelBuilder, this.serviceStatusRowContainer, s, i === bdcStatus.services.length - 1);
|
||||||
|
});
|
||||||
const hdfsServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.hdfs);
|
|
||||||
updateServiceStatusRow(this.hdfsStatusRow, hdfsServiceStatus);
|
|
||||||
|
|
||||||
const sparkServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.spark);
|
|
||||||
updateServiceStatusRow(this.sparkStatusRow, sparkServiceStatus);
|
|
||||||
|
|
||||||
const controlServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.control);
|
|
||||||
updateServiceStatusRow(this.controlStatusRow, controlServiceStatus);
|
|
||||||
|
|
||||||
const gatewayServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.gateway);
|
|
||||||
updateServiceStatusRow(this.gatewayStatusRow, gatewayServiceStatus);
|
|
||||||
|
|
||||||
const appServiceStatus = bdcStatus.services.find(s => s.serviceName === Service.app);
|
|
||||||
updateServiceStatusRow(this.appStatusRow, appServiceStatus);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,105 +210,45 @@ export class BdcDashboardOverviewPage {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service Endpoints
|
this.endpointsRowContainer.clearItems();
|
||||||
const sqlServerEndpoint = endpoints.find(e => e.name === Endpoint.sqlServerMaster);
|
endpoints.forEach((e, i) => {
|
||||||
updateServiceEndpointRow(this.sqlServerEndpointRow, sqlServerEndpoint);
|
createServiceEndpointRow(this.modelBuilder, this.endpointsRowContainer, e, hyperlinkedEndpoints.some(he => he === e.name), i === endpoints.length - 1);
|
||||||
|
});
|
||||||
const controllerEndpoint = endpoints.find(e => e.name === Endpoint.controller);
|
|
||||||
updateServiceEndpointRow(this.controllerEndpointRow, controllerEndpoint);
|
|
||||||
|
|
||||||
const gatewayEndpoint = endpoints.find(e => e.name === Endpoint.gateway);
|
|
||||||
updateServiceEndpointRow(this.hdfsSparkGatewayEndpointRow, gatewayEndpoint);
|
|
||||||
|
|
||||||
const yarnHistoryEndpoint = endpoints.find(e => e.name === Endpoint.yarnUi);
|
|
||||||
updateServiceEndpointRow(this.yarnHistoryEndpointRow, yarnHistoryEndpoint);
|
|
||||||
|
|
||||||
const sparkHistoryEndpoint = endpoints.find(e => e.name === Endpoint.sparkHistory);
|
|
||||||
updateServiceEndpointRow(this.sparkHistoryEndpointRow, sparkHistoryEndpoint);
|
|
||||||
|
|
||||||
const grafanaDashboardEndpoint = endpoints.find(e => e.name === Endpoint.metricsui);
|
|
||||||
updateServiceEndpointRow(this.grafanaDashboardEndpointRow, grafanaDashboardEndpoint);
|
|
||||||
|
|
||||||
const kibanaDashboardEndpoint = endpoints.find(e => e.name === Endpoint.logsui);
|
|
||||||
updateServiceEndpointRow(this.kibanaDashboardEndpointRow, kibanaDashboardEndpoint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateServiceStatusRow(serviceStatusRow: IServiceStatusRow, serviceStatus: ServiceStatusModel) {
|
function createServiceStatusRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, serviceStatus: ServiceStatusModel, isLastRow: boolean): void {
|
||||||
if (serviceStatus) {
|
|
||||||
serviceStatusRow.stateLoadingComponent.loading = false;
|
|
||||||
serviceStatusRow.healthStatusLoadingComponent.loading = false;
|
|
||||||
serviceStatusRow.stateLoadingComponent.component.updateProperty('value', serviceStatus.state);
|
|
||||||
serviceStatusRow.healthStatusLoadingComponent.component.updateProperty('value', serviceStatus.healthStatus);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serviceStatusRow.stateLoadingComponent.loading = true;
|
|
||||||
serviceStatusRow.healthStatusLoadingComponent.loading = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateServiceEndpointRow(serviceEndpointRow: IServiceEndpointRow, endpoint: EndpointModel) {
|
|
||||||
if (endpoint) {
|
|
||||||
serviceEndpointRow.endpointLoadingComponent.loading = false;
|
|
||||||
if (serviceEndpointRow.isHyperlink) {
|
|
||||||
serviceEndpointRow.endpointLoadingComponent.component.updateProperties({ label: endpoint.endpoint, url: endpoint.endpoint });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serviceEndpointRow.endpointLoadingComponent.component.updateProperty('value', endpoint.endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serviceEndpointRow.endpointLoadingComponent.loading = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createServiceStatusRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, name: string): IServiceStatusRow {
|
|
||||||
const serviceStatusRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '30px' }).component();
|
const serviceStatusRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '30px' }).component();
|
||||||
const nameCell = modelBuilder.text().withProperties({ value: name, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
const statusIconCell = modelBuilder.text().withProperties({ value: getHealthStatusIcon(serviceStatus.healthStatus), CSSStyles: { 'user-select': 'none' } }).component();
|
||||||
serviceStatusRow.addItem(nameCell, { CSSStyles: { 'width': '100px', 'min-width': '100px', 'user-select': 'text', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
serviceStatusRow.addItem(statusIconCell, { CSSStyles: { 'width': overviewIconColumnWidth, 'min-width': overviewIconColumnWidth } });
|
||||||
const stateCell = modelBuilder.text().withProperties({ CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
const nameCell = modelBuilder.text().withProperties({ value: getServiceNameDisplayText(serviceStatus.serviceName), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
||||||
const stateLoadingComponent = modelBuilder.loadingComponent()
|
serviceStatusRow.addItem(nameCell, { CSSStyles: { 'width': overviewServiceNameCellWidth, 'min-width': overviewServiceNameCellWidth, 'user-select': 'text', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
||||||
.withItem(stateCell)
|
const stateCell = modelBuilder.text().withProperties({ value: getStateDisplayText(serviceStatus.state), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text', 'text-align': 'center' } }).component();
|
||||||
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
serviceStatusRow.addItem(stateCell, { CSSStyles: { 'width': overviewStateCellWidth, 'min-width': overviewStateCellWidth } });
|
||||||
.component();
|
const healthStatusCell = modelBuilder.text().withProperties({ value: getHealthStatusDisplayText(serviceStatus.healthStatus), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text', 'text-align': 'center' } }).component();
|
||||||
serviceStatusRow.addItem(stateLoadingComponent, { CSSStyles: { 'width': '75px', 'min-width': '75px' } });
|
serviceStatusRow.addItem(healthStatusCell, { CSSStyles: { 'width': overviewHealthStatusCellWidth, 'min-width': overviewHealthStatusCellWidth } });
|
||||||
const healthStatusCell = modelBuilder.text().withProperties({ CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
|
||||||
const healthStatusLoadingComponent = modelBuilder.loadingComponent()
|
|
||||||
.withItem(healthStatusCell)
|
|
||||||
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
|
||||||
.component();
|
|
||||||
serviceStatusRow.addItem(healthStatusLoadingComponent, { CSSStyles: { 'width': '75px', 'min-width': '75px' } });
|
|
||||||
|
|
||||||
container.addItem(serviceStatusRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
container.addItem(serviceStatusRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'border-bottom': isLastRow ? 'solid 1px #ccc' : '', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
return { stateLoadingComponent: stateLoadingComponent, healthStatusLoadingComponent: healthStatusLoadingComponent };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, name: string, isHyperlink: boolean): IServiceEndpointRow {
|
function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, endpoint: EndpointModel, isHyperlink: boolean, isLastRow: boolean): void {
|
||||||
const endPointRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '30px' }).component();
|
const endPointRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '40px' }).component();
|
||||||
const nameCell = modelBuilder.text().withProperties({ value: name, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
const nameCell = modelBuilder.text().withProperties({ value: getEndpointDisplayText(endpoint.name, endpoint.description), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
||||||
endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text' } });
|
endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text', 'text-align': 'center' } });
|
||||||
let retRow: IServiceEndpointRow;
|
|
||||||
if (isHyperlink) {
|
if (isHyperlink) {
|
||||||
const endpointCell = modelBuilder.hyperlink().withProperties({ CSSStyles: { 'height': '15px' } }).component();
|
const endpointCell = modelBuilder.hyperlink()
|
||||||
const endpointLoadingComponent = modelBuilder.loadingComponent()
|
.withProperties({ label: endpoint.endpoint, url: endpoint.endpoint, CSSStyles: { 'height': '15px' } })
|
||||||
.withItem(endpointCell)
|
|
||||||
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
|
||||||
.component();
|
.component();
|
||||||
retRow = { endpointLoadingComponent: endpointLoadingComponent, isHyperlink: true };
|
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden' } });
|
||||||
endPointRow.addItem(endpointLoadingComponent, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden' } });
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const endpointCell = modelBuilder.text().withProperties({ CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
const endpointCell = modelBuilder.text()
|
||||||
const endpointLoadingComponent = modelBuilder.loadingComponent()
|
.withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } })
|
||||||
.withItem(endpointCell)
|
|
||||||
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
|
|
||||||
.component();
|
.component();
|
||||||
retRow = { endpointLoadingComponent: endpointLoadingComponent, isHyperlink: false };
|
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden' } });
|
||||||
endPointRow.addItem(endpointLoadingComponent, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden' } });
|
|
||||||
}
|
}
|
||||||
const copyValueCell = modelBuilder.button().component();
|
const copyValueCell = modelBuilder.button().component();
|
||||||
copyValueCell.iconPath = IconPath.copy;
|
copyValueCell.iconPath = IconPathHelper.copy;
|
||||||
copyValueCell.onDidClick(() => {
|
copyValueCell.onDidClick(() => {
|
||||||
// vscode.env.clipboard.writeText(hyperlink);
|
// vscode.env.clipboard.writeText(hyperlink);
|
||||||
});
|
});
|
||||||
@@ -317,34 +257,5 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container:
|
|||||||
copyValueCell.iconWidth = '14px';
|
copyValueCell.iconWidth = '14px';
|
||||||
endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '50px', 'min-width': '50px', 'padding-left': '10px', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '50px', 'min-width': '50px', 'padding-left': '10px', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
||||||
|
|
||||||
container.addItem(endPointRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
container.addItem(endPointRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'border-bottom': isLastRow ? 'solid 1px #ccc' : '', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
return retRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFriendlyEndpointNames(name: string): string {
|
|
||||||
switch (name) {
|
|
||||||
case 'app-proxy':
|
|
||||||
return localize('bdc.dashboard.appproxy', "Application Proxy");
|
|
||||||
case 'controller':
|
|
||||||
return localize('bdc.dashboard.controller', "Controller");
|
|
||||||
case 'gateway':
|
|
||||||
return localize('bdc.dashboard.gateway', "HDFS/Spark Gateway");
|
|
||||||
case 'management-proxy':
|
|
||||||
return localize('bdc.dashboard.managementproxy', "Management Proxy");
|
|
||||||
case 'mgmtproxy':
|
|
||||||
return localize('bdc.dashboard.mgmtproxy', "Management Proxy");
|
|
||||||
case 'sql-server':
|
|
||||||
return localize('bdc.dashboard.sqlServerEndpoint', "SQL Server Master Instance");
|
|
||||||
case 'grafana':
|
|
||||||
return localize('bdc.dashboard.grafana', "Metrics Dashboard");
|
|
||||||
case 'kibana':
|
|
||||||
return localize('bdc.dashboard.kibana', "Log Search Dashboard");
|
|
||||||
case 'yarn-history':
|
|
||||||
localize('bdc.dashboard.yarnHistory', "Spark Resource Management");
|
|
||||||
case 'spark-history':
|
|
||||||
localize('sparkHistory', "Spark Job Monitoring");
|
|
||||||
default:
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { BdcDashboardModel } from './bdcDashboardModel';
|
import { BdcDashboardModel } from './bdcDashboardModel';
|
||||||
import { BdcStatusModel, InstanceStatusModel } from '../controller/apiGenerated';
|
import { BdcStatusModel, InstanceStatusModel } from '../controller/apiGenerated';
|
||||||
|
import { getHealthStatusDisplayText, getHealthStatusIcon, getStateDisplayText } from '../utils';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
@@ -22,9 +23,14 @@ export interface IInstanceStatus {
|
|||||||
healthStatus: string;
|
healthStatus: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const metricsAndLogsInstanceNameCellWidth = '100px';
|
const healthAndStatusIconColumnWidth = '50px';
|
||||||
const metricsAndLogsMetricsCellWidth = '75px';
|
const healthAndStatusInstanceNameColumnWidth = '100px';
|
||||||
const metricsAndLogsLogsCellWidth = '75px';
|
const healthAndStatusStateColumnWidth = '75px';
|
||||||
|
const healthAndStatusHealthColumnWidth = '75px';
|
||||||
|
|
||||||
|
const metricsAndLogsInstanceNameColumnWidth = '100px';
|
||||||
|
const metricsAndLogsMetricsColumnWidth = '75px';
|
||||||
|
const metricsAndLogsLogsColumnWidth = '75px';
|
||||||
|
|
||||||
|
|
||||||
export class BdcDashboardResourceStatusPage {
|
export class BdcDashboardResourceStatusPage {
|
||||||
@@ -32,7 +38,7 @@ export class BdcDashboardResourceStatusPage {
|
|||||||
private rootContainer: azdata.FlexContainer;
|
private rootContainer: azdata.FlexContainer;
|
||||||
private instanceHealthStatusRowsContainer: azdata.FlexContainer;
|
private instanceHealthStatusRowsContainer: azdata.FlexContainer;
|
||||||
private metricsAndLogsRowsContainer: azdata.FlexContainer;
|
private metricsAndLogsRowsContainer: azdata.FlexContainer;
|
||||||
|
private lastUpdatedLabel: azdata.TextComponent;
|
||||||
private initialized: boolean = false;
|
private initialized: boolean = false;
|
||||||
|
|
||||||
constructor(private model: BdcDashboardModel, private modelView: azdata.ModelView, private serviceName: string, private resourceName: string) {
|
constructor(private model: BdcDashboardModel, private modelView: azdata.ModelView, private serviceName: string, private resourceName: string) {
|
||||||
@@ -57,20 +63,41 @@ export class BdcDashboardResourceStatusPage {
|
|||||||
// # INSTANCE HEALTH AND STATUS #
|
// # INSTANCE HEALTH AND STATUS #
|
||||||
// ##############################
|
// ##############################
|
||||||
|
|
||||||
// Instance Health Label label
|
const healthStatusHeaderContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '20px' }).component();
|
||||||
const propertiesLabel = view.modelBuilder.text()
|
rootContainer.addItem(healthStatusHeaderContainer, { CSSStyles: { 'padding-left': '10px', 'padding-top': '15px' } });
|
||||||
.withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatusDetailsHeader', "Health Status Details"), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '10px' } })
|
|
||||||
|
// Header label
|
||||||
|
const healthStatusHeaderLabel = view.modelBuilder.text()
|
||||||
|
.withProperties<azdata.TextComponentProperties>({
|
||||||
|
value: localize('bdc.dashboard.healthStatusDetailsHeader', "Health Status Details"),
|
||||||
|
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '10px' }
|
||||||
|
})
|
||||||
.component();
|
.component();
|
||||||
rootContainer.addItem(propertiesLabel, { CSSStyles: { 'margin-top': '15px', 'font-size': '20px', 'font-weight': 'bold', 'padding-left': '10px' } });
|
|
||||||
|
healthStatusHeaderContainer.addItem(healthStatusHeaderLabel, { CSSStyles: { 'font-size': '20px', 'font-weight': 'bold' } });
|
||||||
|
|
||||||
|
// Last updated label
|
||||||
|
this.lastUpdatedLabel = view.modelBuilder.text()
|
||||||
|
.withProperties({
|
||||||
|
value: localize('bdc.dashboard.lastUpdated', "Last Updated : {0}", '-'),
|
||||||
|
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'color': 'lightgray' }
|
||||||
|
}).component();
|
||||||
|
|
||||||
|
healthStatusHeaderContainer.addItem(this.lastUpdatedLabel, { CSSStyles: { 'margin-left': '45px' } });
|
||||||
|
|
||||||
|
|
||||||
|
healthStatusHeaderContainer.addItem(healthStatusHeaderLabel, { CSSStyles: { 'font-size': '20px', 'font-weight': 'bold' } });
|
||||||
|
|
||||||
// Header row
|
// Header row
|
||||||
const instanceHealthStatusHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
const instanceHealthStatusHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
||||||
const instanceHealthAndStatusNameHeaderRow = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.metricsAndLogsHeader', "Metrics and Logs") }).component();
|
const instanceHealthAndStatusIconHeader = view.modelBuilder.text().component();
|
||||||
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusNameHeaderRow, { CSSStyles: { 'width': metricsAndLogsInstanceNameCellWidth, 'min-width': metricsAndLogsInstanceNameCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusIconHeader, { CSSStyles: { 'width': healthAndStatusIconColumnWidth, 'min-width': healthAndStatusIconColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
const instanceHealthAndStatusStateRow = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.stateHeader', "State") }).component();
|
const instanceHealthAndStatusNameHeader = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.instanceHeader', "Instance") }).component();
|
||||||
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusStateRow, { CSSStyles: { 'width': metricsAndLogsMetricsCellWidth, 'min-width': metricsAndLogsMetricsCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusNameHeader, { CSSStyles: { 'width': healthAndStatusInstanceNameColumnWidth, 'min-width': healthAndStatusInstanceNameColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
const instanceHealthAndStatusHealthStatusRow = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatusHeader', "Health Status") }).component();
|
const instanceHealthAndStatusState = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.stateHeader', "State") }).component();
|
||||||
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusHealthStatusRow, { CSSStyles: { 'width': metricsAndLogsLogsCellWidth, 'min-width': metricsAndLogsLogsCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusState, { CSSStyles: { 'width': healthAndStatusStateColumnWidth, 'min-width': healthAndStatusStateColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
|
const instanceHealthAndStatusHealthStatus = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatusHeader', "Health Status") }).component();
|
||||||
|
instanceHealthStatusHeaderRow.addItem(instanceHealthAndStatusHealthStatus, { CSSStyles: { 'width': healthAndStatusHealthColumnWidth, 'min-width': healthAndStatusHealthColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
rootContainer.addItem(instanceHealthStatusHeaderRow, { flex: '0 0 auto', CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
rootContainer.addItem(instanceHealthStatusHeaderRow, { flex: '0 0 auto', CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
this.instanceHealthStatusRowsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
this.instanceHealthStatusRowsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
||||||
@@ -88,12 +115,12 @@ export class BdcDashboardResourceStatusPage {
|
|||||||
|
|
||||||
// Header row
|
// Header row
|
||||||
const metricsAndLogsHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
const metricsAndLogsHeaderRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
||||||
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.metricsAndLogsHeader', "Metrics and Logs") }).component();
|
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.instanceHeader', "Instance") }).component();
|
||||||
metricsAndLogsHeaderRow.addItem(nameCell, { CSSStyles: { 'width': metricsAndLogsInstanceNameCellWidth, 'min-width': metricsAndLogsInstanceNameCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
metricsAndLogsHeaderRow.addItem(nameCell, { CSSStyles: { 'width': metricsAndLogsInstanceNameColumnWidth, 'min-width': metricsAndLogsInstanceNameColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
const metricsCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.metricsHeader', "Metrics") }).component();
|
const metricsCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.metricsHeader', "Metrics") }).component();
|
||||||
metricsAndLogsHeaderRow.addItem(metricsCell, { CSSStyles: { 'width': metricsAndLogsMetricsCellWidth, 'min-width': metricsAndLogsMetricsCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
metricsAndLogsHeaderRow.addItem(metricsCell, { CSSStyles: { 'width': metricsAndLogsMetricsColumnWidth, 'min-width': metricsAndLogsMetricsColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
const healthStatusCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.logsHeader', "Logs") }).component();
|
const healthStatusCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.logsHeader', "Logs") }).component();
|
||||||
metricsAndLogsHeaderRow.addItem(healthStatusCell, { CSSStyles: { 'width': metricsAndLogsLogsCellWidth, 'min-width': metricsAndLogsLogsCellWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
metricsAndLogsHeaderRow.addItem(healthStatusCell, { CSSStyles: { 'width': metricsAndLogsLogsColumnWidth, 'min-width': metricsAndLogsLogsColumnWidth, 'font-weight': 'bold', 'user-select': 'text' } });
|
||||||
rootContainer.addItem(metricsAndLogsHeaderRow, { flex: '0 0 auto', CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
rootContainer.addItem(metricsAndLogsHeaderRow, { flex: '0 0 auto', CSSStyles: { 'padding-left': '10px', 'box-sizing': 'border-box', 'user-select': 'text' } });
|
||||||
|
|
||||||
this.metricsAndLogsRowsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
this.metricsAndLogsRowsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
|
||||||
@@ -113,6 +140,12 @@ export class BdcDashboardResourceStatusPage {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.lastUpdatedLabel.value =
|
||||||
|
localize('bdc.dashboard.lastUpdated', "Last Updated : {0}",
|
||||||
|
this.model.bdcStatusLastUpdated ?
|
||||||
|
`${this.model.bdcStatusLastUpdated.toLocaleDateString()} ${this.model.bdcStatusLastUpdated.toLocaleTimeString()}`
|
||||||
|
: '-');
|
||||||
|
|
||||||
this.instanceHealthStatusRowsContainer.clearItems();
|
this.instanceHealthStatusRowsContainer.clearItems();
|
||||||
this.metricsAndLogsRowsContainer.clearItems();
|
this.metricsAndLogsRowsContainer.clearItems();
|
||||||
|
|
||||||
@@ -134,12 +167,18 @@ export class BdcDashboardResourceStatusPage {
|
|||||||
*/
|
*/
|
||||||
function createInstanceHealthStatusRow(modelBuilder: azdata.ModelBuilder, instanceStatus: InstanceStatusModel): azdata.FlexContainer {
|
function createInstanceHealthStatusRow(modelBuilder: azdata.ModelBuilder, instanceStatus: InstanceStatusModel): azdata.FlexContainer {
|
||||||
const instanceHealthStatusRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '30px' }).component();
|
const instanceHealthStatusRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '30px' }).component();
|
||||||
|
const statusIconCell = modelBuilder.text()
|
||||||
|
.withProperties<azdata.TextComponentProperties>({
|
||||||
|
value: getHealthStatusIcon(instanceStatus.healthStatus),
|
||||||
|
CSSStyles: { 'user-select': 'none' }
|
||||||
|
}).component();
|
||||||
|
instanceHealthStatusRow.addItem(statusIconCell, { CSSStyles: { 'width': healthAndStatusIconColumnWidth, 'min-width': healthAndStatusIconColumnWidth } });
|
||||||
const nameCell = modelBuilder.text().withProperties({ value: instanceStatus.instanceName, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
const nameCell = modelBuilder.text().withProperties({ value: instanceStatus.instanceName, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
||||||
instanceHealthStatusRow.addItem(nameCell, { CSSStyles: { 'width': '100px', 'min-width': '100px', 'user-select': 'text', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
instanceHealthStatusRow.addItem(nameCell, { CSSStyles: { 'width': healthAndStatusInstanceNameColumnWidth, 'min-width': healthAndStatusInstanceNameColumnWidth, 'user-select': 'text', 'margin-block-start': '0px', 'margin-block-end': '0px' } });
|
||||||
const stateCell = modelBuilder.text().withProperties({ value: instanceStatus.state, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
const stateCell = modelBuilder.text().withProperties({ value: getStateDisplayText(instanceStatus.state), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
||||||
instanceHealthStatusRow.addItem(stateCell, { CSSStyles: { 'width': '75px', 'min-width': '75px' } });
|
instanceHealthStatusRow.addItem(stateCell, { CSSStyles: { 'width': healthAndStatusStateColumnWidth, 'min-width': healthAndStatusStateColumnWidth } });
|
||||||
const healthStatusCell = modelBuilder.text().withProperties({ value: instanceStatus.healthStatus, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
const healthStatusCell = modelBuilder.text().withProperties({ value: getHealthStatusDisplayText(instanceStatus.healthStatus), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }).component();
|
||||||
instanceHealthStatusRow.addItem(healthStatusCell, { CSSStyles: { 'width': '75px', 'min-width': '75px' } });
|
instanceHealthStatusRow.addItem(healthStatusCell, { CSSStyles: { 'width': healthAndStatusHealthColumnWidth, 'min-width': healthAndStatusHealthColumnWidth } });
|
||||||
|
|
||||||
return instanceHealthStatusRow;
|
return instanceHealthStatusRow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import * as azdata from 'azdata';
|
|||||||
import { BdcStatusModel, ResourceStatusModel } from '../controller/apiGenerated';
|
import { BdcStatusModel, ResourceStatusModel } from '../controller/apiGenerated';
|
||||||
import { BdcDashboardResourceStatusPage } from './bdcDashboardResourceStatusPage';
|
import { BdcDashboardResourceStatusPage } from './bdcDashboardResourceStatusPage';
|
||||||
import { BdcDashboardModel } from './bdcDashboardModel';
|
import { BdcDashboardModel } from './bdcDashboardModel';
|
||||||
|
import { getHealthStatusDot } from '../utils';
|
||||||
|
|
||||||
export class BdcServiceStatusPage {
|
export class BdcServiceStatusPage {
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ export class BdcServiceStatusPage {
|
|||||||
private createResourceNavTabs(resources: ResourceStatusModel[]) {
|
private createResourceNavTabs(resources: ResourceStatusModel[]) {
|
||||||
if (this.initialized && !this.resourceTabsCreated) {
|
if (this.initialized && !this.resourceTabsCreated) {
|
||||||
resources.forEach(resource => {
|
resources.forEach(resource => {
|
||||||
const resourceHeaderTab = createResourceHeaderTab(this.modelView, resource.resourceName);
|
const resourceHeaderTab = createResourceHeaderTab(this.modelView.modelBuilder, resource);
|
||||||
const resourceStatusPage: azdata.FlexContainer = new BdcDashboardResourceStatusPage(this.model, this.modelView, this.serviceName, resource.resourceName).container;
|
const resourceStatusPage: azdata.FlexContainer = new BdcDashboardResourceStatusPage(this.model, this.modelView, this.serviceName, resource.resourceName).container;
|
||||||
resourceHeaderTab.onDidClick(() => {
|
resourceHeaderTab.onDidClick(() => {
|
||||||
this.changeSelectedTabPage(resourceStatusPage);
|
this.changeSelectedTabPage(resourceStatusPage);
|
||||||
@@ -92,12 +93,15 @@ export class BdcServiceStatusPage {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a single resource header tab
|
* Creates a single resource header tab
|
||||||
* @param view TheModelView used to construct the object
|
* @param modelBuilder The ModelBuilder used to construct the object
|
||||||
* @param title The text to display in the tab
|
* @param title The text to display in the tab
|
||||||
*/
|
*/
|
||||||
function createResourceHeaderTab(view: azdata.ModelView, title: string): azdata.DivContainer {
|
function createResourceHeaderTab(modelBuilder: azdata.ModelBuilder, resourceStatus: ResourceStatusModel): azdata.DivContainer {
|
||||||
const resourceHeaderTab = view.modelBuilder.divContainer().withLayout({ width: '100px', height: '25px' }).withProperties({ CSSStyles: { 'text-align': 'center' } }).component();
|
const resourceHeaderTab = modelBuilder.divContainer().withLayout({ width: '100px', height: '25px' }).component();
|
||||||
const resourceHeaderLabel = view.modelBuilder.text().withProperties({ value: title, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
|
const innerContainer = modelBuilder.flexContainer().withLayout({ width: '100px', height: '25px', flexFlow: 'row' }).component();
|
||||||
resourceHeaderTab.addItem(resourceHeaderLabel);
|
innerContainer.addItem(modelBuilder.text().withProperties({ value: getHealthStatusDot(resourceStatus.healthStatus), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'none', 'color': 'red', 'font-size': '40px', 'width': '20px', 'text-align': 'right' } }).component(), { flex: '0 0 auto' });
|
||||||
|
const resourceHeaderLabel = modelBuilder.text().withProperties({ value: resourceStatus.resourceName, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'text-align': 'left' } }).component();
|
||||||
|
innerContainer.addItem(resourceHeaderLabel);
|
||||||
|
resourceHeaderTab.addItem(innerContainer);
|
||||||
return resourceHeaderTab;
|
return resourceHeaderTab;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { IControllerTreeChangeHandler } from './controllerTreeChangeHandler';
|
import { IControllerTreeChangeHandler } from './controllerTreeChangeHandler';
|
||||||
import { TreeNode } from './treeNode';
|
import { TreeNode } from './treeNode';
|
||||||
import { IconPath, BdcItemType } from '../constants';
|
import { IconPathHelper, BdcItemType, IconPath } from '../constants';
|
||||||
import { getEndPoints } from '../controller/clusterControllerApi';
|
import { getEndPoints } from '../controller/clusterControllerApi';
|
||||||
import { showErrorMessage } from '../utils';
|
import { showErrorMessage } from '../utils';
|
||||||
import { EndpointModel } from '../controller/apiGenerated';
|
import { EndpointModel } from '../controller/apiGenerated';
|
||||||
@@ -25,7 +25,7 @@ export abstract class ControllerTreeNode extends TreeNode {
|
|||||||
private _treeChangeHandler: IControllerTreeChangeHandler,
|
private _treeChangeHandler: IControllerTreeChangeHandler,
|
||||||
private _description?: string,
|
private _description?: string,
|
||||||
private _nodeType?: string,
|
private _nodeType?: string,
|
||||||
private _iconPath?: { dark: string, light: string }
|
private _iconPath?: IconPath
|
||||||
) {
|
) {
|
||||||
super(label, parent);
|
super(label, parent);
|
||||||
this._description = this._description || this.label;
|
this._description = this._description || this.label;
|
||||||
@@ -84,11 +84,11 @@ export abstract class ControllerTreeNode extends TreeNode {
|
|||||||
this._nodeType = nodeType;
|
this._nodeType = nodeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set iconPath(iconPath: { dark: string, light: string }) {
|
public set iconPath(iconPath: IconPath) {
|
||||||
this._iconPath = iconPath;
|
this._iconPath = iconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get iconPath(): { dark: string, light: string } {
|
public get iconPath(): IconPath {
|
||||||
return this._iconPath;
|
return this._iconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ export class ControllerNode extends ControllerTreeNode {
|
|||||||
treeChangeHandler: IControllerTreeChangeHandler,
|
treeChangeHandler: IControllerTreeChangeHandler,
|
||||||
description?: string,
|
description?: string,
|
||||||
) {
|
) {
|
||||||
super(label, parent, treeChangeHandler, description, BdcItemType.controller, IconPath.controllerNode);
|
super(label, parent, treeChangeHandler, description, BdcItemType.controller, IconPathHelper.controllerNode);
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
|
||||||
@@ -297,7 +297,7 @@ export class FolderNode extends ControllerTreeNode {
|
|||||||
parent: ControllerTreeNode,
|
parent: ControllerTreeNode,
|
||||||
treeChangeHandler: IControllerTreeChangeHandler
|
treeChangeHandler: IControllerTreeChangeHandler
|
||||||
) {
|
) {
|
||||||
super(label, parent, treeChangeHandler, label, BdcItemType.folder, IconPath.folderNode);
|
super(label, parent, treeChangeHandler, label, BdcItemType.folder, IconPathHelper.folderNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ export class SqlMasterNode extends ControllerTreeNode {
|
|||||||
treeChangeHandler: IControllerTreeChangeHandler,
|
treeChangeHandler: IControllerTreeChangeHandler,
|
||||||
description?: string,
|
description?: string,
|
||||||
) {
|
) {
|
||||||
super(label, parent, treeChangeHandler, description, BdcItemType.sqlMaster, IconPath.sqlMasterNode);
|
super(label, parent, treeChangeHandler, description, BdcItemType.sqlMaster, IconPathHelper.sqlMasterNode);
|
||||||
this._username = 'sa';
|
this._username = 'sa';
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
|||||||
@@ -6,6 +6,33 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
import * as nls from 'vscode-nls';
|
||||||
|
|
||||||
|
const localize = nls.loadMessageBundle();
|
||||||
|
|
||||||
|
export enum Endpoint {
|
||||||
|
gateway = 'gateway',
|
||||||
|
sparkHistory = 'spark-history',
|
||||||
|
yarnUi = 'yarn-ui',
|
||||||
|
appProxy = 'app-proxy',
|
||||||
|
mgmtproxy = 'mgmtproxy',
|
||||||
|
managementProxy = 'management-proxy',
|
||||||
|
logsui = 'logsui',
|
||||||
|
metricsui = 'metricsui',
|
||||||
|
controller = 'controller',
|
||||||
|
sqlServerMaster = 'sql-server-master',
|
||||||
|
webhdfs = 'webhdfs',
|
||||||
|
livy = 'livy'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Service {
|
||||||
|
sql = 'sql',
|
||||||
|
hdfs = 'hdfs',
|
||||||
|
spark = 'spark',
|
||||||
|
control = 'control',
|
||||||
|
gateway = 'gateway',
|
||||||
|
app = 'app'
|
||||||
|
}
|
||||||
|
|
||||||
export function generateGuid(): string {
|
export function generateGuid(): string {
|
||||||
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
|
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
|
||||||
@@ -41,3 +68,144 @@ export function showErrorMessage(error: any, prefixText?: string): void {
|
|||||||
vscode.window.showErrorMessage(text);
|
vscode.window.showErrorMessage(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the localized text to display for a corresponding state
|
||||||
|
* @param state The state to get the display text for
|
||||||
|
*/
|
||||||
|
export function getStateDisplayText(state?: string): string {
|
||||||
|
state = state || '';
|
||||||
|
switch (state.toLowerCase()) {
|
||||||
|
case 'creating':
|
||||||
|
return localize('state.creating', "Creating");
|
||||||
|
case 'waiting':
|
||||||
|
return localize('state.waiting', "Waiting");
|
||||||
|
case 'ready':
|
||||||
|
return localize('state.ready', "Ready");
|
||||||
|
case 'deleting':
|
||||||
|
return localize('state.deleting', "Deleting");
|
||||||
|
case 'waitingfordeletion':
|
||||||
|
return localize('state.waitingForDeletion', "Waiting For Deletion");
|
||||||
|
case 'deleted':
|
||||||
|
return localize('state.deleted', "Deleted");
|
||||||
|
case 'upgrading':
|
||||||
|
return localize('state.upgrading', "Upgrading");
|
||||||
|
case 'waitingforupgrade':
|
||||||
|
return localize('state.waitingForUpgrade', "Waiting For Upgrade");
|
||||||
|
case 'error':
|
||||||
|
return localize('state.error', "Error");
|
||||||
|
case 'running':
|
||||||
|
return localize('state.running', "Running");
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the localized text to display for a corresponding endpoint
|
||||||
|
* @param serviceName The endpoint name to get the display text for
|
||||||
|
* @param description The backup description to use if we don't have our own
|
||||||
|
*/
|
||||||
|
export function getEndpointDisplayText(endpointName?: string, description?: string): string {
|
||||||
|
endpointName = endpointName || '';
|
||||||
|
switch (endpointName.toLowerCase()) {
|
||||||
|
case Endpoint.appProxy:
|
||||||
|
return localize('endpoint.appproxy', "Application Proxy");
|
||||||
|
case Endpoint.controller:
|
||||||
|
return localize('endpoint.controller', "Controller");
|
||||||
|
case Endpoint.gateway:
|
||||||
|
return localize('endpoint.gateway', "HDFS/Spark Gateway");
|
||||||
|
case Endpoint.managementProxy:
|
||||||
|
return localize('endpoint.managementproxy', "Management Proxy");
|
||||||
|
case Endpoint.mgmtproxy:
|
||||||
|
return localize('endpoint.mgmtproxy', "Management Proxy");
|
||||||
|
case Endpoint.sqlServerMaster:
|
||||||
|
return localize('endpoint.sqlServerEndpoint', "SQL Server Master Instance");
|
||||||
|
case Endpoint.metricsui:
|
||||||
|
return localize('endpoint.grafana', "Metrics Dashboard");
|
||||||
|
case Endpoint.logsui:
|
||||||
|
return localize('endpoint.kibana', "Log Search Dashboard");
|
||||||
|
case Endpoint.yarnUi:
|
||||||
|
return localize('endpoint.yarnHistory', "Spark Resource Management");
|
||||||
|
case Endpoint.sparkHistory:
|
||||||
|
return localize('endpoint.sparkHistory', "Spark Job Monitoring");
|
||||||
|
case Endpoint.webhdfs:
|
||||||
|
return localize('endpoint.webhdfs', "HDFS File System Proxy");
|
||||||
|
case Endpoint.livy:
|
||||||
|
return localize('endpoint.livy', "Spark Proxy");
|
||||||
|
default:
|
||||||
|
// Default is to use the description if one was given, otherwise worst case just fall back to using the
|
||||||
|
// original service name
|
||||||
|
return description && description.length > 0 ? description : endpointName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the localized text to display for a corresponding service
|
||||||
|
* @param serviceName The service name to get the display text for
|
||||||
|
*/
|
||||||
|
export function getServiceNameDisplayText(serviceName?: string): string {
|
||||||
|
serviceName = serviceName || '';
|
||||||
|
switch (serviceName.toLowerCase()) {
|
||||||
|
case Service.sql:
|
||||||
|
return localize('service.sql', "SQL Server");
|
||||||
|
case Service.hdfs:
|
||||||
|
return localize('service.hdfs', "HDFS");
|
||||||
|
case Service.spark:
|
||||||
|
return localize('service.spark', "Spark");
|
||||||
|
case Service.control:
|
||||||
|
return localize('service.control', "Control");
|
||||||
|
case Service.gateway:
|
||||||
|
return localize('service.gateway', "Gateway");
|
||||||
|
case Service.app:
|
||||||
|
return localize('service.app', "App");
|
||||||
|
default:
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the localized text to display for a corresponding health status
|
||||||
|
* @param healthStatus The health status to get the display text for
|
||||||
|
*/
|
||||||
|
export function getHealthStatusDisplayText(healthStatus?: string) {
|
||||||
|
healthStatus = healthStatus || '';
|
||||||
|
switch (healthStatus.toLowerCase()) {
|
||||||
|
case 'healthy':
|
||||||
|
return localize('bdc.healthy', "Healthy");
|
||||||
|
case 'unhealthy':
|
||||||
|
return localize('bdc.unhealthy', "Unhealthy");
|
||||||
|
default:
|
||||||
|
return healthStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status icon for the corresponding health status
|
||||||
|
* @param healthStatus The status to check
|
||||||
|
*/
|
||||||
|
export function getHealthStatusIcon(healthStatus?: string): string {
|
||||||
|
healthStatus = healthStatus || '';
|
||||||
|
switch (healthStatus.toLowerCase()) {
|
||||||
|
case 'healthy':
|
||||||
|
return '✔️';
|
||||||
|
default:
|
||||||
|
// Consider all non-healthy status' as errors
|
||||||
|
return '⚠️';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status dot string which will be a • for all non-healthy states
|
||||||
|
* @param healthStatus The status to check
|
||||||
|
*/
|
||||||
|
export function getHealthStatusDot(healthStatus?: string): string {
|
||||||
|
healthStatus = healthStatus || '';
|
||||||
|
switch (healthStatus.toLowerCase()) {
|
||||||
|
case 'healthy':
|
||||||
|
return '';
|
||||||
|
default:
|
||||||
|
// Display status dot for all non-healthy status'
|
||||||
|
return '•';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { ControllerTreeDataProvider } from './bigDataCluster/tree/controllerTreeDataProvider';
|
import { ControllerTreeDataProvider } from './bigDataCluster/tree/controllerTreeDataProvider';
|
||||||
import { IconPath } from './bigDataCluster/constants';
|
import { IconPathHelper } from './bigDataCluster/constants';
|
||||||
import { TreeNode } from './bigDataCluster/tree/treeNode';
|
import { TreeNode } from './bigDataCluster/tree/treeNode';
|
||||||
import { AddControllerDialogModel, AddControllerDialog } from './bigDataCluster/dialog/addControllerDialog';
|
import { AddControllerDialogModel, AddControllerDialog } from './bigDataCluster/dialog/addControllerDialog';
|
||||||
import { ControllerNode } from './bigDataCluster/tree/controllerTreeNode';
|
import { ControllerNode } from './bigDataCluster/tree/controllerTreeNode';
|
||||||
@@ -25,7 +25,7 @@ const ManageControllerCommand = 'bigDataClusters.command.manageController';
|
|||||||
let throttleTimers: { [key: string]: any } = {};
|
let throttleTimers: { [key: string]: any } = {};
|
||||||
|
|
||||||
export function activate(extensionContext: vscode.ExtensionContext) {
|
export function activate(extensionContext: vscode.ExtensionContext) {
|
||||||
IconPath.setExtensionContext(extensionContext);
|
IconPathHelper.setExtensionContext(extensionContext);
|
||||||
let treeDataProvider = new ControllerTreeDataProvider(extensionContext.globalState);
|
let treeDataProvider = new ControllerTreeDataProvider(extensionContext.globalState);
|
||||||
registerTreeDataProvider(treeDataProvider);
|
registerTreeDataProvider(treeDataProvider);
|
||||||
registerCommands(extensionContext, treeDataProvider);
|
registerCommands(extensionContext, treeDataProvider);
|
||||||
|
|||||||
Reference in New Issue
Block a user