diff --git a/extensions/big-data-cluster/resources/status_circle_blank.svg b/extensions/big-data-cluster/resources/status_circle_blank.svg
new file mode 100644
index 0000000000..af5badbac8
--- /dev/null
+++ b/extensions/big-data-cluster/resources/status_circle_blank.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/extensions/big-data-cluster/resources/status_circle_red.svg b/extensions/big-data-cluster/resources/status_circle_red.svg
new file mode 100644
index 0000000000..f73edde71c
--- /dev/null
+++ b/extensions/big-data-cluster/resources/status_circle_red.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/extensions/big-data-cluster/src/bigDataCluster/constants.ts b/extensions/big-data-cluster/src/bigDataCluster/constants.ts
index dfe2569e2c..20d1f69f84 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/constants.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/constants.ts
@@ -26,6 +26,8 @@ export class IconPathHelper {
public static status_ok: IconPath;
public static status_warning: IconPath;
public static notebook: IconPath;
+ public static status_circle_red: IconPath;
+ public static status_circle_blank: IconPath;
public static setExtensionContext(extensionContext: vscode.ExtensionContext) {
IconPathHelper.extensionContext = extensionContext;
@@ -53,6 +55,14 @@ export class IconPathHelper {
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/notebook.svg'),
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/notebook_inverse.svg')
};
+ IconPathHelper.status_circle_red = {
+ light: IconPathHelper.extensionContext.asAbsolutePath('resources/status_circle_red.svg'),
+ dark: IconPathHelper.extensionContext.asAbsolutePath('resources/status_circle_red.svg')
+ };
+ IconPathHelper.status_circle_blank = {
+ light: IconPathHelper.extensionContext.asAbsolutePath('resources/status_circle_blank.svg'),
+ dark: IconPathHelper.extensionContext.asAbsolutePath('resources/status_circle_blank.svg')
+ };
}
}
@@ -60,13 +70,6 @@ export namespace cssStyles {
export const title = { 'font-size': '14px', 'font-weight': '600' };
export const tableHeader = { 'text-align': 'left', 'font-weight': 'bold', 'text-transform': 'uppercase', 'font-size': '10px', 'user-select': 'text' };
export const text = { 'margin-block-start': '0px', 'margin-block-end': '0px' };
- export const overflowEllipsisText = { ...text, 'overflow': 'hidden', 'text-overflow': 'ellipsis' };
- export const nonSelectableText = { ...cssStyles.text, 'user-select': 'none' };
- export const tabHeaderText = { 'margin-block-start': '2px', 'margin-block-end': '0px', 'user-select': 'none' };
- export const selectedResourceHeaderTab = { 'font-weight': 'bold', 'color': '' };
- export const unselectedResourceHeaderTab = { 'font-weight': '', 'color': '#0078d4' };
- export const selectedTabDiv = { 'border-bottom': '2px solid #000' };
- export const unselectedTabDiv = { 'border-bottom': '1px solid #ccc' };
export const lastUpdatedText = { ...text, 'color': '#595959' };
export const errorText = { ...text, 'color': 'red' };
}
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboard.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboard.ts
index 0d6d80154a..ea4a94c5c1 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboard.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboard.ts
@@ -4,176 +4,62 @@
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
-import * as vscode from 'vscode';
-import { BdcDashboardModel, getTroubleshootNotebookUrl, BdcErrorEvent } from './bdcDashboardModel';
-import { IconPathHelper, cssStyles } from '../constants';
+import { BdcDashboardModel, BdcErrorEvent } from './bdcDashboardModel';
import { BdcServiceStatusPage } from './bdcServiceStatusPage';
import { BdcDashboardOverviewPage } from './bdcDashboardOverviewPage';
import { BdcStatusModel, ServiceStatusModel } from '../controller/apiGenerated';
-import { getHealthStatusDot, getServiceNameDisplayText, showErrorMessage } from '../utils';
+import { getServiceNameDisplayText, showErrorMessage, getHealthStatusDotIcon } from '../utils';
import { HdfsDialogCancelledError } from './hdfsDialogBase';
-import { BdcDashboardPage } from './bdcDashboardPage';
+import { InitializingComponent } from './intializingComponent';
import * as loc from '../localizedConstants';
-const navWidth = '200px';
+export class BdcDashboard extends InitializingComponent {
-const selectedTabCss = { 'font-weight': 'bold' };
-const unselectedTabCss = { 'font-weight': '' };
-
-type NavTab = { serviceName: string, div: azdata.DivContainer, dot: azdata.TextComponent, text: azdata.TextComponent };
-
-export class BdcDashboard extends BdcDashboardPage {
-
- private dashboard: azdata.workspace.ModelViewEditor;
+ private dashboard: azdata.window.ModelViewDashboard;
private modelView: azdata.ModelView;
- private mainAreaContainer: azdata.FlexContainer;
- private navContainer: azdata.FlexContainer;
- private overviewPage: BdcDashboardOverviewPage;
- private currentTab: NavTab;
- private currentPageContainer: azdata.FlexContainer;
-
- private refreshButton: azdata.ButtonComponent;
-
- private serviceTabPageMapping = new Map();
+ private createdServicePages: Map = new Map();
+ private overviewTab: azdata.DashboardTab;
constructor(private title: string, private model: BdcDashboardModel) {
super();
- this.model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
- this.model.onBdcError(errorEvent => this.eventuallyRunOnInitialized(() => this.handleError(errorEvent)));
+ model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
+ model.onBdcError(errorEvent => this.eventuallyRunOnInitialized(() => this.handleError(errorEvent)));
}
- public showDashboard(): void {
- this.createDashboard();
- this.dashboard.openEditor();
+ public async showDashboard(): Promise {
+ await this.createDashboard();
+ await this.dashboard.open();
}
- private createDashboard(): void {
- this.dashboard = azdata.workspace.createModelViewEditor(this.title, { retainContextWhenHidden: true, supportsSave: false });
- this.dashboard.registerContent(async (modelView: azdata.ModelView) => {
+ private async createDashboard(): Promise {
+ this.dashboard = azdata.window.createModelViewDashboard(this.title, { alwaysShowTabs: true });
+ this.dashboard.registerTabs(async (modelView: azdata.ModelView) => {
this.modelView = modelView;
- const rootContainer = modelView.modelBuilder.flexContainer().withLayout(
- {
- flexFlow: 'column',
- width: '100%',
- height: '100%'
- }).component();
- // ###########
- // # TOOLBAR #
- // ###########
-
- // Refresh button
- this.refreshButton = modelView.modelBuilder.button()
- .withProperties({
- label: loc.refresh,
- iconPath: IconPathHelper.refresh
- }).component();
-
- this.refreshButton.onDidClick(async () => {
- this.overviewPage.onRefreshStarted();
- await this.doRefresh();
- });
-
- const openTroubleshootNotebookButton = modelView.modelBuilder.button()
- .withProperties({
- label: loc.troubleshoot,
- iconPath: IconPathHelper.notebook
- }).component();
-
- openTroubleshootNotebookButton.onDidClick(() => {
- vscode.commands.executeCommand('books.sqlserver2019', getTroubleshootNotebookUrl(this.currentTab.serviceName));
- });
-
- const toolbarContainer = modelView.modelBuilder.toolbarContainer()
- .withToolbarItems(
- [
- { component: this.refreshButton },
- { component: openTroubleshootNotebookButton }
- ]
- ).component();
-
- rootContainer.addItem(toolbarContainer, { flex: '0 0 auto' });
-
- // #############
- // # MAIN AREA #
- // #############
-
- this.mainAreaContainer = modelView.modelBuilder.flexContainer().withLayout(
- {
- flexFlow: 'row',
- width: '100%',
- height: '100%'
- }).component();
-
- rootContainer.addItem(this.mainAreaContainer, { flex: '0 0 100%' });
-
- // #################
- // # NAV CONTAINER #
- // #################
-
- this.navContainer = modelView.modelBuilder.flexContainer().withLayout(
- {
- flexFlow: 'column',
- width: navWidth,
- height: '100%'
- }
- ).withProperties({
- ariaRole: 'tablist'
- }).component();
-
- this.mainAreaContainer.addItem(this.navContainer, { flex: `0 0 ${navWidth}`, CSSStyles: { 'padding': '0 20px 0 20px', 'border-right': 'solid 1px #ccc' } });
-
- // Overview nav item - this will be the initial page
- const overviewNavItemDiv = modelView.modelBuilder
- .divContainer()
- .withLayout({ width: navWidth, height: '30px' })
- .withProperties({
- clickable: true,
- ariaRole: 'tab',
- ariaSelected: true
- }).component();
- const overviewNavItemText = modelView.modelBuilder.text().withProperties({ value: loc.bdcOverview }).component();
- overviewNavItemText.updateCssStyles(selectedTabCss);
- overviewNavItemDiv.addItem(overviewNavItemText, { CSSStyles: { 'user-select': 'text' } });
- this.overviewPage = new BdcDashboardOverviewPage(this, this.model);
- const overviewContainer: azdata.FlexContainer = this.overviewPage.create(modelView);
- this.currentPageContainer = overviewContainer;
- this.currentTab = { serviceName: undefined, div: overviewNavItemDiv, dot: undefined, text: overviewNavItemText };
- this.mainAreaContainer.addItem(overviewContainer, { flex: '0 0 100%', CSSStyles: { 'margin': '0 20px 0 20px' } });
-
- overviewNavItemDiv.onDidClick(() => {
- if (this.currentTab) {
- this.currentTab.text.updateCssStyles(unselectedTabCss);
- this.currentTab.div.ariaSelected = false;
- }
- this.mainAreaContainer.removeItem(this.currentPageContainer);
- this.mainAreaContainer.addItem(overviewContainer, { flex: '0 0 100%', CSSStyles: { 'margin': '0 20px 0 20px' } });
- this.currentPageContainer = overviewContainer;
- this.currentTab = { serviceName: undefined, div: overviewNavItemDiv, dot: undefined, text: overviewNavItemText };
- this.currentTab.text.updateCssStyles(selectedTabCss);
- this.currentTab.div.ariaSelected = true;
- });
- this.navContainer.addItem(overviewNavItemDiv, { flex: '0 0 auto' });
-
- const clusterDetailsHeader = modelView.modelBuilder.text().withProperties({ value: loc.clusterDetails, CSSStyles: { 'margin-block-end': '0px' } }).component();
- this.navContainer.addItem(clusterDetailsHeader, { CSSStyles: { 'user-select': 'none', 'font-weight': 'bold', 'border-bottom': 'solid 1px #ccc', 'margin-bottom': '10px' } });
-
- await modelView.initializeModel(rootContainer);
-
- this.initialized = true;
-
- // Now that we've created the UI load data from the model in case it already had data
- this.handleBdcStatusUpdate(this.model.bdcStatus);
+ const overviewPage = new BdcDashboardOverviewPage(this.model, modelView);
+ this.overviewTab = {
+ title: loc.bdcOverview,
+ id: 'overview-tab',
+ content: overviewPage.container,
+ toolbar: overviewPage.toolbarContainer
+ };
+ return [
+ this.overviewTab
+ ];
});
+ this.initialized = true;
+
+ // Now that we've created the UI load data from the model in case it already had data
+ this.handleBdcStatusUpdate(this.model.bdcStatus);
}
private handleBdcStatusUpdate(bdcStatus?: BdcStatusModel): void {
if (!bdcStatus) {
return;
}
- this.updateServiceNavTabs(bdcStatus.services);
+ this.updateServicePages(bdcStatus.services);
}
private handleError(errorEvent: BdcErrorEvent): void {
@@ -187,77 +73,34 @@ export class BdcDashboard extends BdcDashboardPage {
}
}
- private async doRefresh(): Promise {
- try {
- this.refreshButton.enabled = false;
- await this.model.refresh();
- } finally {
- this.refreshButton.enabled = true;
- }
- }
-
/**
- * Switches the current navigation tab to the one corresponding to the specified service
- * @param serviceName The name of the service to switch to the tab of
+ * Update the service tab pages, creating any new ones as necessary
*/
- public switchToServiceTab(serviceName: string): void {
- const tabPageMapping = this.serviceTabPageMapping.get(serviceName);
- if (!tabPageMapping) {
- return;
- }
- if (this.currentTab) {
- this.currentTab.text.updateCssStyles(unselectedTabCss);
- this.currentTab.div.ariaSelected = false;
- }
- this.mainAreaContainer.removeItem(this.currentPageContainer);
- this.mainAreaContainer.addItem(tabPageMapping.servicePage.container, { CSSStyles: { 'margin': '0 20px 0 20px' } });
- this.currentPageContainer = tabPageMapping.servicePage.container;
- this.currentTab = tabPageMapping.navTab;
- this.currentTab.text.updateCssStyles(selectedTabCss);
- this.currentTab.div.ariaSelected = true;
- }
-
- /**
- * Helper to update the navigation tabs for the services when we get a status update
- */
- private updateServiceNavTabs(services?: ServiceStatusModel[]): void {
+ private updateServicePages(services?: ServiceStatusModel[]): void {
if (services) {
- // Add a nav item for each service
+ // Create a service page for each new service. We currently don't support services being removed.
services.forEach(s => {
- const existingTabPage = this.serviceTabPageMapping.get(s.serviceName);
- if (existingTabPage) {
- // We've already created the tab and page for this service, just update the tab health status dot
- existingTabPage.navTab.dot.value = getHealthStatusDot(s.healthStatus);
+ const existingPage = this.createdServicePages.get(s.serviceName);
+ if (existingPage) {
+ existingPage.icon = getHealthStatusDotIcon(s.healthStatus);
} else {
- // New service - create the page and tab
- const navItem = createServiceNavTab(this.modelView.modelBuilder, s);
const serviceStatusPage = new BdcServiceStatusPage(s.serviceName, this.model, this.modelView);
- this.serviceTabPageMapping.set(s.serviceName, { navTab: navItem, servicePage: serviceStatusPage });
- navItem.div.onDidClick(() => {
- this.switchToServiceTab(s.serviceName);
- });
- this.navContainer.addItem(navItem.div, { flex: '0 0 auto' });
+ const newTab = {
+ title: getServiceNameDisplayText(s.serviceName),
+ id: s.serviceName,
+ icon: getHealthStatusDotIcon(s.healthStatus),
+ content: serviceStatusPage.container,
+ toolbar: serviceStatusPage.toolbarContainer
+ };
+ this.createdServicePages.set(s.serviceName, newTab);
}
});
+ this.dashboard.updateTabs([
+ this.overviewTab,
+ {
+ title: loc.clusterDetails,
+ tabs: Array.from(this.createdServicePages.values())
+ }]);
}
}
}
-
-function createServiceNavTab(modelBuilder: azdata.ModelBuilder, serviceStatus: ServiceStatusModel): NavTab {
- const div = modelBuilder.divContainer()
- .withLayout({
- width: navWidth,
- height: '30px',
- })
- .withProperties({
- clickable: true,
- ariaRole: 'tab'
- }).component();
- const innerContainer = modelBuilder.flexContainer().withLayout({ width: navWidth, height: '30px', flexFlow: 'row' }).component();
- const dot = modelBuilder.text().withProperties({ value: getHealthStatusDot(serviceStatus.healthStatus), CSSStyles: { 'color': 'red', 'font-size': '40px', 'width': '20px', ...cssStyles.nonSelectableText } }).component();
- innerContainer.addItem(dot, { flex: '0 0 auto' });
- const text = modelBuilder.text().withProperties({ value: getServiceNameDisplayText(serviceStatus.serviceName), CSSStyles: { ...cssStyles.tabHeaderText } }).component();
- innerContainer.addItem(text, { flex: '0 0 auto' });
- div.addItem(innerContainer);
- return { serviceName: serviceStatus.serviceName, div: div, dot: dot, text: text };
-}
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts
index e4052cdc0e..bf9583cfb7 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts
@@ -34,8 +34,7 @@ export class BdcDashboardModel {
constructor(private _options: BdcDashboardOptions, private _treeDataProvider: ControllerTreeDataProvider) {
try {
this._clusterController = new ClusterController(_options.url, _options.auth, _options.username, _options.password);
- // tslint:disable-next-line:no-floating-promises
- this.refresh();
+ this.refresh().catch(e => console.log(`Unexpected error refreshing BdcModel ${e instanceof Error ? e.message : e}`));
} catch {
this.promptReconnect().then(async () => {
await this.refresh();
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts
index 6fdfe2d95e..df50b587e7 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts
@@ -9,26 +9,17 @@ import { BdcDashboardModel, BdcErrorEvent } from './bdcDashboardModel';
import { IconPathHelper, cssStyles } from '../constants';
import { getStateDisplayText, getHealthStatusDisplayText, getEndpointDisplayText, getHealthStatusIcon, getServiceNameDisplayText, Endpoint, getBdcStatusErrorMessage } from '../utils';
import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated';
-import { BdcDashboard } from './bdcDashboard';
import { createViewDetailsButton } from './commonControls';
import { HdfsDialogCancelledError } from './hdfsDialogBase';
import { BdcDashboardPage } from './bdcDashboardPage';
import * as loc from '../localizedConstants';
-const clusterStateLabelColumnWidth = 100;
-const clusterStateValueColumnWidth = 225;
-const healthStatusColumnWidth = 125;
-
const hyperlinkedEndpoints = [Endpoint.metricsui, Endpoint.logsui, Endpoint.sparkHistory, Endpoint.yarnUi];
export class BdcDashboardOverviewPage extends BdcDashboardPage {
-
- private modelBuilder: azdata.ModelBuilder;
-
+ private rootContainer: azdata.FlexContainer;
private lastUpdatedLabel: azdata.TextComponent;
- private propertiesContainer: azdata.DivContainer;
- private clusterStateLoadingComponent: azdata.LoadingComponent;
- private clusterHealthStatusLoadingComponent: azdata.LoadingComponent;
+ private propertiesContainerLoadingComponent: azdata.LoadingComponent;
private serviceStatusTable: azdata.DeclarativeTableComponent;
private endpointsTable: azdata.DeclarativeTableComponent;
@@ -40,16 +31,23 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
private endpointsErrorMessage: azdata.TextComponent;
private serviceStatusErrorMessage: azdata.TextComponent;
- constructor(private dashboard: BdcDashboard, private model: BdcDashboardModel) {
- super();
+ constructor(model: BdcDashboardModel, modelView: azdata.ModelView) {
+ super(model, modelView);
this.model.onDidUpdateEndpoints(endpoints => this.eventuallyRunOnInitialized(() => this.handleEndpointsUpdate(endpoints)));
this.model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
this.model.onBdcError(error => this.eventuallyRunOnInitialized(() => this.handleBdcError(error)));
}
- public create(view: azdata.ModelView): azdata.FlexContainer {
- this.modelBuilder = view.modelBuilder;
- const rootContainer = view.modelBuilder.flexContainer().withLayout(
+ public get container(): azdata.FlexContainer {
+ // Lazily create the container only when needed
+ if (!this.rootContainer) {
+ this.rootContainer = this.createContainer();
+ }
+ return this.rootContainer;
+ }
+
+ public createContainer(): azdata.FlexContainer {
+ const rootContainer = this.modelView.modelBuilder.flexContainer().withLayout(
{
flexFlow: 'column',
width: '100%',
@@ -60,51 +58,24 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
// # PROPERTIES #
// ##############
- const propertiesLabel = view.modelBuilder.text()
+ const propertiesLabel = this.modelView.modelBuilder.text()
.withProperties({ value: loc.clusterProperties, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '10px' } })
.component();
rootContainer.addItem(propertiesLabel, { CSSStyles: { 'margin-top': '15px', 'padding-left': '10px', ...cssStyles.title } });
- this.propertiesErrorMessage = view.modelBuilder.text().withProperties({ display: 'none', CSSStyles: { ...cssStyles.errorText } }).component();
- rootContainer.addItem(this.propertiesErrorMessage, { flex: '0 0 auto' });
+ const propertiesContainer = this.modelView.modelBuilder.propertiesContainer().component();
- this.propertiesContainer = view.modelBuilder.divContainer().withProperties({ clickable: false }).component();
-
- // Row 1
- const row1 = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '30px', alignItems: 'center' }).component();
-
- // Cluster State
- const clusterStateLabel = view.modelBuilder.text().withProperties({ value: loc.clusterState }).component();
- const clusterStateValue = view.modelBuilder.text().component();
- this.clusterStateLoadingComponent = view.modelBuilder.loadingComponent()
- .withItem(clusterStateValue)
- .withProperties({ loadingCompletedText: loc.loadingClusterStateCompleted })
- .component();
- row1.addItem(clusterStateLabel, { CSSStyles: { 'width': `${clusterStateLabelColumnWidth}px`, 'min-width': `${clusterStateLabelColumnWidth}px`, 'user-select': 'none', 'font-weight': 'bold' } });
- row1.addItem(this.clusterStateLoadingComponent, { CSSStyles: { 'width': `${clusterStateValueColumnWidth}px`, 'min-width': `${clusterStateValueColumnWidth}px` } });
-
- // Health Status
- const healthStatusLabel = view.modelBuilder.text().withProperties({ value: loc.healthStatusWithColon }).component();
- const healthStatusValue = view.modelBuilder.text().component();
- this.clusterHealthStatusLoadingComponent = view.modelBuilder.loadingComponent()
- .withItem(healthStatusValue)
- .withProperties({ loadingCompletedText: loc.loadingHealthStatusCompleted })
- .component();
- row1.addItem(healthStatusLabel, { CSSStyles: { 'width': `${healthStatusColumnWidth}px`, 'min-width': `${healthStatusColumnWidth}px`, 'user-select': 'none', 'font-weight': 'bold' } });
- row1.addItem(this.clusterHealthStatusLoadingComponent, { CSSStyles: { 'width': `${healthStatusColumnWidth}px`, 'min-width': `${healthStatusColumnWidth}px` } });
-
- this.propertiesContainer.addItem(row1, { CSSStyles: { 'padding-left': '10px', 'border-bottom': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
-
- rootContainer.addItem(this.propertiesContainer, { flex: '0 0 auto' });
+ this.propertiesContainerLoadingComponent = this.modelView.modelBuilder.loadingComponent().withItem(propertiesContainer).component();
+ rootContainer.addItem(this.propertiesContainerLoadingComponent, { flex: '0 0 auto', CSSStyles: { 'padding-left': '10px' } });
// ############
// # OVERVIEW #
// ############
- const overviewHeaderContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '20px' }).component();
+ const overviewHeaderContainer = this.modelView.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 = this.modelView.modelBuilder.text()
.withProperties({
value: loc.clusterOverview,
CSSStyles: { ...cssStyles.text }
@@ -113,7 +84,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
overviewHeaderContainer.addItem(overviewLabel, { CSSStyles: { ...cssStyles.title } });
- this.lastUpdatedLabel = view.modelBuilder.text()
+ this.lastUpdatedLabel = this.modelView.modelBuilder.text()
.withProperties({
value: loc.lastUpdated(),
CSSStyles: { ...cssStyles.lastUpdatedText }
@@ -121,9 +92,9 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
overviewHeaderContainer.addItem(this.lastUpdatedLabel, { CSSStyles: { 'margin-left': '45px' } });
- const overviewContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%' }).component();
+ const overviewContainer = this.modelView.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%' }).component();
- this.serviceStatusTable = view.modelBuilder.declarativeTable()
+ this.serviceStatusTable = this.modelView.modelBuilder.declarativeTable()
.withProperties(
{
columns: [
@@ -214,19 +185,19 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
})
.component();
- this.serviceStatusDisplayContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
+ this.serviceStatusDisplayContainer = this.modelView.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
this.serviceStatusDisplayContainer.addItem(this.serviceStatusTable);
// Note we don't make the table a child of the loading component since making the loading component align correctly
// messes up the layout for the table that we display after loading is finished. Instead we'll just remove the loading
// component once it's finished loading the content
- this.serviceStatusLoadingComponent = view.modelBuilder.loadingComponent()
+ this.serviceStatusLoadingComponent = this.modelView.modelBuilder.loadingComponent()
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
.component();
this.serviceStatusDisplayContainer.addItem(this.serviceStatusLoadingComponent, { flex: '0 0 auto', CSSStyles: { 'padding-left': '150px', width: '30px' } });
- this.serviceStatusErrorMessage = view.modelBuilder.text().withProperties({ display: 'none', CSSStyles: { ...cssStyles.errorText } }).component();
+ this.serviceStatusErrorMessage = this.modelView.modelBuilder.text().withProperties({ display: 'none', CSSStyles: { ...cssStyles.errorText } }).component();
overviewContainer.addItem(this.serviceStatusErrorMessage);
overviewContainer.addItem(this.serviceStatusDisplayContainer);
@@ -237,16 +208,16 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
// # SERVICE ENDPOINTS #
// #####################
- const endpointsLabel = view.modelBuilder.text()
+ const endpointsLabel = this.modelView.modelBuilder.text()
.withProperties({ value: loc.serviceEndpoints, CSSStyles: { 'margin-block-start': '20px', 'margin-block-end': '0px' } })
.component();
rootContainer.addItem(endpointsLabel, { CSSStyles: { 'padding-left': '10px', ...cssStyles.title } });
- this.endpointsErrorMessage = view.modelBuilder.text().withProperties({ display: 'none', CSSStyles: { ...cssStyles.errorText } }).component();
+ this.endpointsErrorMessage = this.modelView.modelBuilder.text().withProperties({ display: 'none', CSSStyles: { ...cssStyles.errorText } }).component();
- const endpointsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%' }).component();
+ const endpointsContainer = this.modelView.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%' }).component();
- this.endpointsTable = view.modelBuilder.declarativeTable()
+ this.endpointsTable = this.modelView.modelBuilder.declarativeTable()
.withProperties(
{
columns: [
@@ -305,13 +276,13 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
ariaLabel: loc.serviceEndpoints
}).component();
- this.endpointsDisplayContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
+ this.endpointsDisplayContainer = this.modelView.modelBuilder.flexContainer().withLayout({ flexFlow: 'column' }).component();
this.endpointsDisplayContainer.addItem(this.endpointsTable);
// Note we don't make the table a child of the loading component since making the loading component align correctly
// messes up the layout for the table that we display after loading is finished. Instead we'll just remove the loading
// component once it's finished loading the content
- this.endpointsLoadingComponent = view.modelBuilder.loadingComponent()
+ this.endpointsLoadingComponent = this.modelView.modelBuilder.loadingComponent()
.withProperties({ CSSStyles: { 'padding-top': '0px', 'padding-bottom': '0px' } })
.component();
this.endpointsDisplayContainer.addItem(this.endpointsLoadingComponent, { flex: '0 0 auto', CSSStyles: { 'padding-left': '150px', width: '30px' } });
@@ -335,7 +306,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
this.endpointsErrorMessage.display = 'none';
this.serviceStatusDisplayContainer.display = undefined;
- this.propertiesContainer.display = undefined;
+ this.propertiesContainerLoadingComponent.display = undefined;
this.endpointsDisplayContainer.display = undefined;
}
@@ -345,31 +316,33 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
}
this.lastUpdatedLabel.value = loc.lastUpdated(this.model.bdcStatusLastUpdated);
- this.clusterStateLoadingComponent.loading = false;
- this.clusterHealthStatusLoadingComponent.loading = false;
- (this.clusterStateLoadingComponent.component).value = getStateDisplayText(bdcStatus.state);
- (this.clusterHealthStatusLoadingComponent.component).value = getHealthStatusDisplayText(bdcStatus.healthStatus);
+ this.propertiesContainerLoadingComponent.loading = false;
+
+ (this.propertiesContainerLoadingComponent.component).propertyItems = [
+ { displayName: loc.clusterState, value: getStateDisplayText(bdcStatus.state) },
+ { displayName: loc.healthStatus, value: getHealthStatusDisplayText(bdcStatus.healthStatus) }
+ ];
if (bdcStatus.services) {
this.serviceStatusTable.data = bdcStatus.services.map(serviceStatus => {
- const statusIconCell = this.modelBuilder.text()
+ const statusIconCell = this.modelView.modelBuilder.text()
.withProperties({
value: getHealthStatusIcon(serviceStatus.healthStatus),
ariaRole: 'img',
title: getHealthStatusDisplayText(serviceStatus.healthStatus),
CSSStyles: { 'user-select': 'none', ...cssStyles.text }
}).component();
- const nameCell = this.modelBuilder.hyperlink()
+ const nameCell = this.modelView.modelBuilder.hyperlink()
.withProperties({
label: getServiceNameDisplayText(serviceStatus.serviceName),
url: '',
CSSStyles: { ...cssStyles.text }
}).component();
nameCell.onDidClick(() => {
- this.dashboard.switchToServiceTab(serviceStatus.serviceName);
+ //this.dashboard.switchToServiceTab(serviceStatus.serviceName); TODO: Enable direct link to tab page
});
- const viewDetailsButton = serviceStatus.healthStatus !== 'healthy' && serviceStatus.details && serviceStatus.details.length > 0 ? createViewDetailsButton(this.modelBuilder, serviceStatus.details) : undefined;
+ const viewDetailsButton = serviceStatus.healthStatus !== 'healthy' && serviceStatus.details && serviceStatus.details.length > 0 ? createViewDetailsButton(this.modelView.modelBuilder, serviceStatus.details) : undefined;
return [
statusIconCell,
nameCell,
@@ -397,7 +370,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
endpoints.unshift(...sqlServerMasterEndpoints);
this.endpointsTable.data = endpoints.map(e => {
- const copyValueCell = this.modelBuilder.button().withProperties({ title: loc.copy }).component();
+ const copyValueCell = this.modelView.modelBuilder.button().withProperties({ title: loc.copy }).component();
copyValueCell.iconPath = IconPathHelper.copy;
copyValueCell.onDidClick(() => {
vscode.env.clipboard.writeText(e.endpoint);
@@ -406,7 +379,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
copyValueCell.iconHeight = '14px';
copyValueCell.iconWidth = '14px';
return [getEndpointDisplayText(e.name, e.description),
- createEndpointComponent(this.modelBuilder, e, this.model, hyperlinkedEndpoints.some(he => he === e.name)),
+ createEndpointComponent(this.modelView.modelBuilder, e, this.model, hyperlinkedEndpoints.some(he => he === e.name)),
copyValueCell];
});
@@ -426,7 +399,7 @@ export class BdcDashboardOverviewPage extends BdcDashboardPage {
private showBdcStatusError(errorMessage: string): void {
this.serviceStatusDisplayContainer.display = 'none';
- this.propertiesContainer.display = 'none';
+ this.propertiesContainerLoadingComponent.display = 'none';
this.serviceStatusErrorMessage.value = errorMessage;
this.serviceStatusErrorMessage.display = undefined;
this.propertiesErrorMessage.value = errorMessage;
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardPage.ts
index 22a09faf2b..382ed95a3b 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardPage.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardPage.ts
@@ -3,37 +3,67 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { Deferred } from '../../common/promise';
+import { IconPathHelper } from '../constants';
+import { BdcDashboardModel, getTroubleshootNotebookUrl } from './bdcDashboardModel';
+import * as loc from '../localizedConstants';
+import * as azdata from 'azdata';
+import * as vscode from 'vscode';
+import { InitializingComponent } from './intializingComponent';
-export abstract class BdcDashboardPage {
+export abstract class BdcDashboardPage extends InitializingComponent {
- private _initialized: boolean = false;
+ private _toolbarContainer: azdata.ToolbarContainer;
+ private _refreshButton: azdata.ButtonComponent;
- private onInitializedPromise: Deferred = new Deferred();
-
- constructor() { }
-
- protected get initialized(): boolean {
- return this._initialized;
+ constructor(protected model: BdcDashboardModel, protected modelView: azdata.ModelView, protected serviceName?: string) {
+ super();
}
- protected set initialized(value: boolean) {
- if (!this._initialized && value) {
- this._initialized = true;
- this.onInitializedPromise.resolve();
+ public get toolbarContainer(): azdata.ToolbarContainer {
+ // Lazily create the container only when needed
+ if (!this._toolbarContainer) {
+ this._toolbarContainer = this.createToolbarContainer();
}
+ return this._toolbarContainer;
}
- /**
- * Runs the specified action when the component is initialized. If already initialized just runs
- * the action immediately.
- * @param action The action to be ran when the page is initialized
- */
- protected eventuallyRunOnInitialized(action: () => void): void {
- if (!this._initialized) {
- this.onInitializedPromise.promise.then(() => action()).catch(error => console.error(`Unexpected error running onInitialized action for BDC Page : ${error}`));
- } else {
- action();
+ protected createToolbarContainer(): azdata.ToolbarContainer {
+ // Refresh button
+ this._refreshButton = this.modelView.modelBuilder.button()
+ .withProperties({
+ label: loc.refresh,
+ iconPath: IconPathHelper.refresh
+ }).component();
+
+ this._refreshButton.onDidClick(async () => {
+ await this.doRefresh();
+ });
+
+ const openTroubleshootNotebookButton = this.modelView.modelBuilder.button()
+ .withProperties({
+ label: loc.troubleshoot,
+ iconPath: IconPathHelper.notebook
+ }).component();
+
+ openTroubleshootNotebookButton.onDidClick(() => {
+ vscode.commands.executeCommand('books.sqlserver2019', getTroubleshootNotebookUrl(this.serviceName));
+ });
+
+ return this.modelView.modelBuilder.toolbarContainer()
+ .withToolbarItems(
+ [
+ { component: this._refreshButton },
+ { component: openTroubleshootNotebookButton }
+ ]
+ ).component();
+ }
+
+ private async doRefresh(): Promise {
+ try {
+ this._refreshButton.enabled = false;
+ await this.model.refresh();
+ } finally {
+ this._refreshButton.enabled = true;
}
}
}
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts
index 736f735f3e..1edd813576 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardResourceStatusPage.ts
@@ -21,8 +21,8 @@ export class BdcDashboardResourceStatusPage extends BdcDashboardPage {
private metricsAndLogsRowsTable: azdata.DeclarativeTableComponent;
private lastUpdatedLabel: azdata.TextComponent;
- constructor(private model: BdcDashboardModel, private modelView: azdata.ModelView, private serviceName: string, private resourceName: string) {
- super();
+ constructor(model: BdcDashboardModel, modelView: azdata.ModelView, serviceName: string, private resourceName: string) {
+ super(model, modelView, serviceName);
this.model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
}
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcServiceStatusPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcServiceStatusPage.ts
index 86f1effee1..118c2ab3de 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcServiceStatusPage.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcServiceStatusPage.ts
@@ -7,57 +7,35 @@ import * as azdata from 'azdata';
import { BdcStatusModel, ResourceStatusModel } from '../controller/apiGenerated';
import { BdcDashboardResourceStatusPage } from './bdcDashboardResourceStatusPage';
import { BdcDashboardModel } from './bdcDashboardModel';
-import { getHealthStatusDot } from '../utils';
-import { cssStyles } from '../constants';
import { BdcDashboardPage } from './bdcDashboardPage';
-
-type ServiceTab = { div: azdata.DivContainer, dot: azdata.TextComponent, text: azdata.TextComponent };
+import { getHealthStatusDotIcon } from '../utils';
export class BdcServiceStatusPage extends BdcDashboardPage {
- private currentTab: { tab: ServiceTab, index: number };
- private currentTabPage: BdcDashboardResourceStatusPage;
- private rootContainer: azdata.FlexContainer;
- private resourceHeader: azdata.FlexContainer;
+ private createdResourceTabs: Map = new Map();
+ private tabbedPanel: azdata.TabbedPanelComponent;
- private createdTabs: Map = new Map();
-
- constructor(private serviceName: string, private model: BdcDashboardModel, private modelView: azdata.ModelView) {
- super();
+ constructor(serviceName: string, model: BdcDashboardModel, modelView: azdata.ModelView) {
+ super(model, modelView, serviceName);
this.model.onDidUpdateBdcStatus(bdcStatus => this.eventuallyRunOnInitialized(() => this.handleBdcStatusUpdate(bdcStatus)));
}
- public get container(): azdata.FlexContainer {
+ public get container(): azdata.TabbedPanelComponent {
// Lazily create the container only when needed
- if (!this.rootContainer) {
+ if (!this.tabbedPanel) {
this.createPage();
}
- return this.rootContainer;
+ return this.tabbedPanel;
}
private createPage(): void {
- this.rootContainer = this.modelView.modelBuilder.flexContainer().withLayout(
- {
- flexFlow: 'column',
- width: '100%',
- height: '100%'
- }).component();
+ this.tabbedPanel = this.modelView.modelBuilder.tabbedPanel()
+ .withLayout({ showIcon: true, alwaysShowTabs: true }).component();
- this.resourceHeader = this.modelView.modelBuilder.flexContainer().withLayout(
- {
- flexFlow: 'row',
- width: '100%',
- height: '25px'
- }
- ).withProperties({
- ariaRole: 'tablist'
- }).component();
-
- this.rootContainer.addItem(this.resourceHeader, { CSSStyles: { 'padding-top': '15px' } });
+ // Initialize our set of tab pages
+ this.handleBdcStatusUpdate(this.model.bdcStatus);
this.initialized = true;
-
- this.handleBdcStatusUpdate(this.model.bdcStatus);
}
private handleBdcStatusUpdate(bdcStatus: BdcStatusModel): void {
@@ -66,90 +44,29 @@ export class BdcServiceStatusPage extends BdcDashboardPage {
}
const service = bdcStatus.services.find(s => s.serviceName === this.serviceName);
if (service && service.resources) {
- this.createResourceNavTabs(service.resources);
+ this.updateResourcePages(service.resources);
}
}
- private changeSelectedTabPage(newPage: BdcDashboardResourceStatusPage): void {
- if (this.currentTabPage) {
- this.rootContainer.removeItem(this.currentTabPage.container);
- }
- this.rootContainer.addItem(newPage.container);
- this.currentTabPage = newPage;
- }
-
/**
- * Helper to create the navigation tabs for the resources
+ * Update the resource tab pages, creating any new ones as necessary
*/
- private createResourceNavTabs(resources: ResourceStatusModel[]) {
- let tabIndex = this.createdTabs.size;
+ private updateResourcePages(resources: ResourceStatusModel[]): void {
resources.forEach(resource => {
- const existingTab: ServiceTab = this.createdTabs.get(resource.resourceName);
+ const existingTab = this.createdResourceTabs.get(resource.resourceName);
if (existingTab) {
- // We already created this tab so just update the status
- existingTab.dot.value = getHealthStatusDot(resource.healthStatus);
+ existingTab.icon = getHealthStatusDotIcon(resource.healthStatus);
} else {
- // New tab - create and add to the end of the container
- const currentIndex = tabIndex++;
- const resourceHeaderTab = createResourceHeaderTab(this.modelView.modelBuilder, resource);
- this.createdTabs.set(resource.resourceName, resourceHeaderTab);
const resourceStatusPage = new BdcDashboardResourceStatusPage(this.model, this.modelView, this.serviceName, resource.resourceName);
- resourceHeaderTab.div.onDidClick(() => {
- // Don't need to do anything if this is already the currently selected tab
- if (this.currentTab.index === currentIndex) {
- return;
- }
- if (this.currentTab) {
- this.currentTab.tab.text.updateCssStyles(cssStyles.unselectedResourceHeaderTab);
- this.currentTab.tab.div.ariaSelected = false;
- this.resourceHeader.removeItem(this.currentTab.tab.div);
- this.resourceHeader.insertItem(this.currentTab.tab.div, this.currentTab.index, { flex: '0 0 auto', CSSStyles: cssStyles.unselectedTabDiv });
- }
- this.changeSelectedTabPage(resourceStatusPage);
- this.currentTab = { tab: resourceHeaderTab, index: currentIndex };
- this.currentTab.tab.text.updateCssStyles(cssStyles.selectedResourceHeaderTab);
- this.currentTab.tab.div.ariaSelected = true;
- this.resourceHeader.removeItem(this.currentTab.tab.div);
- this.resourceHeader.insertItem(this.currentTab.tab.div, this.currentTab.index, { flex: '0 0 auto', CSSStyles: cssStyles.selectedTabDiv });
- });
- // Set initial page
- if (!this.currentTabPage) {
- this.changeSelectedTabPage(resourceStatusPage);
- this.currentTab = { tab: resourceHeaderTab, index: currentIndex };
- this.currentTab.tab.text.updateCssStyles(cssStyles.selectedResourceHeaderTab);
- this.currentTab.tab.div.ariaSelected = true;
- this.resourceHeader.addItem(resourceHeaderTab.div, { flex: '0 0 auto', CSSStyles: cssStyles.selectedTabDiv });
- }
- else {
- resourceHeaderTab.text.updateCssStyles(cssStyles.unselectedResourceHeaderTab);
- this.resourceHeader.addItem(resourceHeaderTab.div, { flex: '0 0 auto', CSSStyles: cssStyles.unselectedTabDiv });
- }
+ const newTab: azdata.Tab = {
+ title: resource.resourceName,
+ id: resource.resourceName,
+ content: resourceStatusPage.container,
+ icon: getHealthStatusDotIcon(resource.healthStatus)
+ };
+ this.createdResourceTabs.set(resource.resourceName, newTab);
}
});
+ this.tabbedPanel.updateTabs(Array.from(this.createdResourceTabs.values()));
}
}
-
-/**
- * Creates a single resource header tab
- * @param modelBuilder The ModelBuilder used to construct the object
- * @param resourceStatus The status of the resource we're creating
- */
-function createResourceHeaderTab(modelBuilder: azdata.ModelBuilder, resourceStatus: ResourceStatusModel): ServiceTab {
- const resourceHeaderTab = modelBuilder
- .divContainer()
- .withLayout({
- width: '100px',
- height: '25px'
- })
- .withProperties({
- clickable: true,
- ariaRole: 'tab'
- }).component();
- const innerContainer = modelBuilder.flexContainer().withLayout({ width: '100px', height: '25px', flexFlow: 'row' }).component();
- const statusDot = modelBuilder.text().withProperties({ value: getHealthStatusDot(resourceStatus.healthStatus), CSSStyles: { 'color': 'red', 'font-size': '40px', 'width': '20px', 'text-align': 'right', ...cssStyles.nonSelectableText } }).component();
- innerContainer.addItem(statusDot, { flex: '0 0 auto' });
- const resourceHeaderLabel = modelBuilder.text().withProperties({ value: resourceStatus.resourceName, CSSStyles: { 'text-align': 'left', ...cssStyles.tabHeaderText } }).component();
- innerContainer.addItem(resourceHeaderLabel);
- resourceHeaderTab.addItem(innerContainer);
- return { div: resourceHeaderTab, text: resourceHeaderLabel, dot: statusDot };
-}
diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/intializingComponent.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/intializingComponent.ts
new file mode 100644
index 0000000000..046ebe7cf8
--- /dev/null
+++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/intializingComponent.ts
@@ -0,0 +1,40 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the Source EULA. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { Deferred } from '../../common/promise';
+
+export abstract class InitializingComponent {
+
+ private _initialized: boolean = false;
+
+ private _onInitializedPromise: Deferred = new Deferred();
+
+ constructor() { }
+
+ protected get initialized(): boolean {
+ return this._initialized;
+ }
+
+ protected set initialized(value: boolean) {
+ if (!this._initialized && value) {
+ this._initialized = true;
+ this._onInitializedPromise.resolve();
+ }
+ }
+
+ /**
+ * Runs the specified action when the component is initialized. If already initialized just runs
+ * the action immediately.
+ * @param action The action to be ran when the page is initialized
+ */
+ protected eventuallyRunOnInitialized(action: () => void): void {
+ if (!this._initialized) {
+ this._onInitializedPromise.promise.then(() => action()).catch(error => console.error(`Unexpected error running onInitialized action for BDC Page : ${error}`));
+ } else {
+ action();
+ }
+ }
+}
+
diff --git a/extensions/big-data-cluster/src/bigDataCluster/localizedConstants.ts b/extensions/big-data-cluster/src/bigDataCluster/localizedConstants.ts
index 2d73827565..902764f285 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/localizedConstants.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/localizedConstants.ts
@@ -48,8 +48,7 @@ export const clusterDetails = localize('bdc.dashboard.clusterDetails', "Cluster
export const clusterOverview = localize('bdc.dashboard.clusterOverview', "Cluster Overview");
export const serviceEndpoints = localize('bdc.dashboard.serviceEndpoints', "Service Endpoints");
export const clusterProperties = localize('bdc.dashboard.clusterProperties', "Cluster Properties");
-export const clusterState = localize('bdc.dashboard.clusterState', "Cluster State :");
-export const healthStatusWithColon = localize('bdc.dashboard.healthStatusWithColon', "Health Status :");
+export const clusterState = localize('bdc.dashboard.clusterState', "Cluster State");
export const serviceName = localize('bdc.dashboard.serviceName', "Service Name");
export const service = localize('bdc.dashboard.service', "Service");
export const endpoint = localize('bdc.dashboard.endpoint', "Endpoint");
diff --git a/extensions/big-data-cluster/src/bigDataCluster/utils.ts b/extensions/big-data-cluster/src/bigDataCluster/utils.ts
index de33e24295..21622650f2 100644
--- a/extensions/big-data-cluster/src/bigDataCluster/utils.ts
+++ b/extensions/big-data-cluster/src/bigDataCluster/utils.ts
@@ -210,17 +210,17 @@ export function getHealthStatusIcon(healthStatus?: string): string {
}
/**
- * Returns the status dot string which will be a • for all non-healthy states
+ * Returns the status dot icon which will be a • for all non-healthy states
* @param healthStatus The status to check
*/
-export function getHealthStatusDot(healthStatus?: string): string {
+export function getHealthStatusDotIcon(healthStatus?: string): constants.IconPath {
healthStatus = healthStatus || '';
switch (healthStatus.toLowerCase()) {
case 'healthy':
- return '';
+ return constants.IconPathHelper.status_circle_blank;
default:
// Display status dot for all non-healthy status'
- return '•';
+ return constants.IconPathHelper.status_circle_red;
}
}
diff --git a/extensions/big-data-cluster/src/extension.ts b/extensions/big-data-cluster/src/extension.ts
index 9072190dd9..96390c5e6f 100644
--- a/extensions/big-data-cluster/src/extension.ts
+++ b/extensions/big-data-cluster/src/extension.ts
@@ -68,7 +68,7 @@ function registerCommands(context: vscode.ExtensionContext, treeDataProvider: Co
await treeDataProvider.saveControllers();
}
const dashboard: BdcDashboard = new BdcDashboard(title, new BdcDashboardModel(info, treeDataProvider));
- dashboard.showDashboard();
+ await dashboard.showDashboard();
});
vscode.commands.registerCommand(commands.MountHdfsCommand, e => mountHdfs(e).catch(error => {