mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-25 01:25:36 -05:00
Handle error when loading the dashboard (#862)
* add error tab when the tab cannot be loaded * formatting * changing the look for error message per Smitha request
This commit is contained in:
@@ -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 {
|
||||
|
||||
1
src/sql/media/icons/globalerror.svg
Normal file
1
src/sql/media/icons/globalerror.svg
Normal file
@@ -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:#fff;}</style></defs><title>globalerror</title><path class="cls-1" d="M8,0a7.92,7.92,0,0,1,4,1.09A8.15,8.15,0,0,1,14.91,4a8,8,0,0,1,0,8.07A8.15,8.15,0,0,1,12,14.91a8,8,0,0,1-8.07,0A8.15,8.15,0,0,1,1.09,12,8,8,0,0,1,1.09,4,8.15,8.15,0,0,1,4,1.09,7.92,7.92,0,0,1,8,0ZM8,15a6.88,6.88,0,0,0,1.86-.25,7,7,0,0,0,4.89-4.89,7.07,7.07,0,0,0,0-3.73A7,7,0,0,0,9.86,1.25a7.07,7.07,0,0,0-3.73,0A7,7,0,0,0,1.25,6.14a7.07,7.07,0,0,0,0,3.73,7,7,0,0,0,4.89,4.89A6.88,6.88,0,0,0,8,15Zm3.46-9.76L8.71,8l2.75,2.76-.7.7L8,8.71,5.24,11.46l-.7-.7L7.29,8,4.54,5.24l.7-.7L8,7.29l2.76-2.75Z"/></svg>
|
||||
|
After Width: | Height: | Size: 691 B |
@@ -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;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
</dashboard-nav-section>
|
||||
<dashboard-grid-container *ngIf="getContentType(tab) === 'grid-container'" [tab]="tab">
|
||||
</dashboard-grid-container>
|
||||
<dashboard-error-container *ngIf="getContentType(tab) === 'error-container'" [tab]="tab">
|
||||
</dashboard-error-container>
|
||||
</ng-template>
|
||||
</tab>
|
||||
</panel>
|
||||
|
||||
@@ -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 = <WidgetConfig[]>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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: `
|
||||
<div class="error-container">
|
||||
<div class="icon globalError">
|
||||
</div>
|
||||
<div class="error-message" #errorMessage>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class DashboardErrorContainer extends DashboardTab implements AfterViewInit {
|
||||
@Input() private tab: TabConfig;
|
||||
private _onResize = new Emitter<void>();
|
||||
public readonly onResize: Event<void> = 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 {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -12,5 +12,7 @@
|
||||
</dashboard-widget-container>
|
||||
<dashboard-grid-container *ngIf="getContentType(tab) === 'grid-container'" [tab]="tab">
|
||||
</dashboard-grid-container>
|
||||
<dashboard-error-container *ngIf="getContentType(tab) === 'error-container'" [tab]="tab">
|
||||
</dashboard-error-container>
|
||||
</tab>
|
||||
</panel>
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user