diff --git a/src/sql/media/icons/common-icons.css b/src/sql/media/icons/common-icons.css
index 6d2b78484a..1a93df7c1a 100644
--- a/src/sql/media/icons/common-icons.css
+++ b/src/sql/media/icons/common-icons.css
@@ -57,6 +57,12 @@
background: url("server_page_inverse.svg") center center no-repeat;
}
+.vs .icon.globalError,
+.vs-dark .icon.globalError,
+.hc-black .icon.globalError {
+ background: url("globalerror.svg") center center no-repeat;
+}
+
.vs .icon.error,
.vs-dark .icon.error,
.hc-black .icon.error {
diff --git a/src/sql/media/icons/globalerror.svg b/src/sql/media/icons/globalerror.svg
new file mode 100644
index 0000000000..271117e28b
--- /dev/null
+++ b/src/sql/media/icons/globalerror.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/sql/parts/dashboard/common/dashboardHelper.ts b/src/sql/parts/dashboard/common/dashboardHelper.ts
index f6bb49f585..6c61bd1657 100644
--- a/src/sql/parts/dashboard/common/dashboardHelper.ts
+++ b/src/sql/parts/dashboard/common/dashboardHelper.ts
@@ -178,8 +178,9 @@ export function getDashboardContainer(container: object): { result: boolean, mes
if (!containerTypeFound) {
let dashboardContainer = dashboardcontainerRegistry.getRegisteredContainer(key);
if (!dashboardContainer) {
- let error = nls.localize('unknownDashboardContainerError', '{0} is an unknown container.', key);
- return { result: false, message: error, container: null };
+ let errorMessage = nls.localize('unknownDashboardContainerError', '{0} is an unknown container.', key);
+ error(errorMessage);
+ return { result: false, message: errorMessage, container: null };
} else {
container = dashboardContainer.container;
}
diff --git a/src/sql/parts/dashboard/common/dashboardPage.component.html b/src/sql/parts/dashboard/common/dashboardPage.component.html
index 5ec536b133..b883819988 100644
--- a/src/sql/parts/dashboard/common/dashboardPage.component.html
+++ b/src/sql/parts/dashboard/common/dashboardPage.component.html
@@ -17,6 +17,8 @@
+
+
diff --git a/src/sql/parts/dashboard/common/dashboardPage.component.ts b/src/sql/parts/dashboard/common/dashboardPage.component.ts
index 4838824ab5..7c70e70586 100644
--- a/src/sql/parts/dashboard/common/dashboardPage.component.ts
+++ b/src/sql/parts/dashboard/common/dashboardPage.component.ts
@@ -20,7 +20,6 @@ import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { AngularEventType } from 'sql/services/angularEventing/angularEventingService';
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
-import { error } from 'sql/base/common/log';
import * as dashboardHelper from 'sql/parts/dashboard/common/dashboardHelper';
import { WIDGETS_CONTAINER } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.contribution';
import { GRID_CONTAINER } from 'sql/parts/dashboard/containers/dashboardGridContainer.contribution';
@@ -191,12 +190,10 @@ export abstract class DashboardPage extends Disposable implements OnDestroy {
let selectedTabs = dashboardTabs.map(v => {
let containerResult = dashboardHelper.getDashboardContainer(v.container);
if (!containerResult.result) {
- let errorTitle = nls.localize('dashboardPage_loadTabError', 'Cannot open {0}. ', v.title);
- this.dashboardService.messageService.show(Severity.Error, errorTitle + containerResult.message);
- return null;
+ return { id: v.id, title: v.title, container: { 'error-container': undefined }, alwaysShow: v.alwaysShow };
}
- let key = Object.keys(containerResult.container)[0];
+ let key = Object.keys(containerResult.container)[0];
if (key === WIDGETS_CONTAINER || key === GRID_CONTAINER) {
let configs = Object.values(containerResult.container)[0];
this._configModifiers.forEach(cb => {
@@ -214,31 +211,26 @@ export abstract class DashboardPage extends Disposable implements OnDestroy {
}
return { id: v.id, title: v.title, container: containerResult.container, alwaysShow: v.alwaysShow };
}).map(v => {
- if (v) {
- let actions = [];
- if (!v.alwaysShow) {
- let pinnedTab = this._pinnedTabs.find(i => i.tabId === v.id);
- actions.push(this.dashboardService.instantiationService.createInstance(PinUnpinTabAction, v.id, this.dashboardService.getUnderlyingUri(), !!pinnedTab));
- }
-
- let config = v as TabConfig;
- config.context = this.context;
- config.editable = false;
- config.canClose = true;
- config.actions = actions;
- this.addNewTab(config);
- return config;
+ let actions = [];
+ if (!v.alwaysShow) {
+ let pinnedTab = this._pinnedTabs.find(i => i.tabId === v.id);
+ actions.push(this.dashboardService.instantiationService.createInstance(PinUnpinTabAction, v.id, this.dashboardService.getUnderlyingUri(), !!pinnedTab));
}
- return null;
+
+ let config = v as TabConfig;
+ config.context = this.context;
+ config.editable = false;
+ config.canClose = true;
+ config.actions = actions;
+ this.addNewTab(config);
+ return config;
});
if (openLastTab) {
// put this immediately on the stack so that is ran *after* the tab is rendered
setTimeout(() => {
let selectedLastTab = selectedTabs.pop();
- if (selectedLastTab) {
- this._panel.selectTab(selectedLastTab.id);
- }
+ this._panel.selectTab(selectedLastTab.id);
});
}
}
diff --git a/src/sql/parts/dashboard/containers/dashboardErrorContainer.component.ts b/src/sql/parts/dashboard/containers/dashboardErrorContainer.component.ts
new file mode 100644
index 0000000000..ecc49c4fe4
--- /dev/null
+++ b/src/sql/parts/dashboard/containers/dashboardErrorContainer.component.ts
@@ -0,0 +1,58 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the Source EULA. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import 'vs/css!./dashboardErrorContainer';
+
+import { Component, Inject, Input, forwardRef, ViewChild, ElementRef, ChangeDetectorRef, AfterViewInit } from '@angular/core';
+
+import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget';
+import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
+
+import Event, { Emitter } from 'vs/base/common/event';
+import * as nls from 'vs/nls';
+
+@Component({
+ selector: 'dashboard-error-container',
+ providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardErrorContainer) }],
+ template: `
+
+ `
+})
+export class DashboardErrorContainer extends DashboardTab implements AfterViewInit {
+ @Input() private tab: TabConfig;
+ private _onResize = new Emitter();
+ public readonly onResize: Event = this._onResize.event;
+
+ @ViewChild('errorMessage', { read: ElementRef }) private _errorMessageContainer: ElementRef;
+ constructor(
+ @Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
+ ) {
+ super();
+ }
+
+ ngAfterViewInit() {
+ let errorMessage = this._errorMessageContainer.nativeElement as HTMLElement;
+ errorMessage.innerHTML = nls.localize('dashboardNavSection_loadTabError', 'The {0} has an invalid content. Please contact extension owner.', this.tab.title);
+ }
+
+ public get id(): string {
+ return this.tab.id;
+ }
+
+ public get editable(): boolean {
+ return false;
+ }
+
+ public layout() {
+ }
+
+ public refresh(): void {
+ }
+}
diff --git a/src/sql/parts/dashboard/containers/dashboardErrorContainer.css b/src/sql/parts/dashboard/containers/dashboardErrorContainer.css
new file mode 100644
index 0000000000..57b27a0534
--- /dev/null
+++ b/src/sql/parts/dashboard/containers/dashboardErrorContainer.css
@@ -0,0 +1,23 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the Source EULA. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+dashboard-error-container {
+ height: 100%;
+ width: 100%;
+}
+
+dashboard-error-container .error-container {
+ padding: 6px;
+ background: #D02E00;
+ color: white;
+}
+
+dashboard-error-container .error-container .icon.globalError {
+ height: 16px;
+ width: 16px;
+ float: left;
+ padding-right: 15px;
+}
+
diff --git a/src/sql/parts/dashboard/containers/dashboardNavSection.component.html b/src/sql/parts/dashboard/containers/dashboardNavSection.component.html
index 0f94fbd803..3a887ba105 100644
--- a/src/sql/parts/dashboard/containers/dashboardNavSection.component.html
+++ b/src/sql/parts/dashboard/containers/dashboardNavSection.component.html
@@ -12,5 +12,7 @@
+
+
\ No newline at end of file
diff --git a/src/sql/parts/dashboard/containers/dashboardNavSection.component.ts b/src/sql/parts/dashboard/containers/dashboardNavSection.component.ts
index e5534364ab..1a8478957c 100644
--- a/src/sql/parts/dashboard/containers/dashboardNavSection.component.ts
+++ b/src/sql/parts/dashboard/containers/dashboardNavSection.component.ts
@@ -12,14 +12,12 @@ import { WidgetConfig, TabConfig, NavSectionConfig } from 'sql/parts/dashboard/c
import { PanelComponent, IPanelOptions, NavigationBarLayout } from 'sql/base/browser/ui/panel/panel.component';
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
-import { error } from 'sql/base/common/log';
import { WIDGETS_CONTAINER } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.contribution';
import { GRID_CONTAINER } from 'sql/parts/dashboard/containers/dashboardGridContainer.contribution';
import * as dashboardHelper from 'sql/parts/dashboard/common/dashboardHelper';
import { Registry } from 'vs/platform/registry/common/platform';
import Event, { Emitter } from 'vs/base/common/event';
-import Severity from 'vs/base/common/severity';
import * as nls from 'vs/nls';
@Component({
@@ -90,9 +88,7 @@ export class DashboardNavSection extends DashboardTab implements OnDestroy, OnCh
let containerResult = dashboardHelper.getDashboardContainer(v.container);
if (!containerResult.result) {
- let errorTitle = nls.localize('dashboardNavSection_loadTabError', 'There is an error while loading {0} section. ', v.title);
- this.dashboardService.messageService.show(Severity.Error, errorTitle + containerResult.message);
- return null;
+ return { id: v.id, title: v.title, container: { 'error-container': undefined } };
}
let key = Object.keys(containerResult.container)[0];
@@ -113,23 +109,18 @@ export class DashboardNavSection extends DashboardTab implements OnDestroy, OnCh
}
return { id: v.id, title: v.title, container: containerResult.container };
}).map(v => {
- if (v) {
- let config = v as TabConfig;
- config.context = this.tab.context;
- config.editable = false;
- config.canClose = false;
- this.addNewTab(config);
- return config;
- }
- return null;
+ let config = v as TabConfig;
+ config.context = this.tab.context;
+ config.editable = false;
+ config.canClose = false;
+ this.addNewTab(config);
+ return config;
});
- if (selectedTabs && selectedTabs[0]) {
- // put this immediately on the stack so that is ran *after* the tab is rendered
- setTimeout(() => {
- this._panel.selectTab(selectedTabs[0].id);
- });
- }
+ // put this immediately on the stack so that is ran *after* the tab is rendered
+ setTimeout(() => {
+ this._panel.selectTab(selectedTabs[0].id);
+ });
}
}
diff --git a/src/sql/parts/dashboard/dashboard.module.ts b/src/sql/parts/dashboard/dashboard.module.ts
index 06ec40d0f4..dc42c7f84e 100644
--- a/src/sql/parts/dashboard/dashboard.module.ts
+++ b/src/sql/parts/dashboard/dashboard.module.ts
@@ -30,6 +30,7 @@ import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWi
import { DashboardWidgetContainer } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.component';
import { DashboardGridContainer } from 'sql/parts/dashboard/containers/dashboardGridContainer.component';
import { DashboardWebviewContainer } from 'sql/parts/dashboard/containers/dashboardWebviewContainer.component';
+import { DashboardErrorContainer } from 'sql/parts/dashboard/containers/dashboardErrorContainer.component';
import { DashboardNavSection } from 'sql/parts/dashboard/containers/dashboardNavSection.component';
import { WidgetContent } from 'sql/parts/dashboard/contents/widgetContent.component';
import { WebviewContent } from 'sql/parts/dashboard/contents/webviewContent.component';
@@ -37,7 +38,7 @@ import { BreadcrumbComponent } from 'sql/base/browser/ui/breadcrumb/breadcrumb.c
import { IBreadcrumbService } from 'sql/base/browser/ui/breadcrumb/interfaces';
import { DashboardHomeContainer } from 'sql/parts/dashboard/containers/dashboardHomeContainer.component';
-let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer, DashboardWidgetContainer, DashboardGridContainer, DashboardNavSection, WidgetContent, WebviewContent, ComponentHostDirective, BreadcrumbComponent];
+let baseComponents = [DashboardHomeContainer, DashboardComponent, DashboardWidgetWrapper, DashboardWebviewContainer, DashboardWidgetContainer, DashboardGridContainer, DashboardErrorContainer, DashboardNavSection, WidgetContent, WebviewContent, ComponentHostDirective, BreadcrumbComponent];
/* Panel */
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';