Collapsible properties (#771)

* started moving properties to home tab

* moved properties

* refactored panel in dashboard

* fix errors

* fix miss-naming

* added collapsable properties

* revert unnecessary change

* add icon for collapsing properties
This commit is contained in:
Anthony Dresser
2018-03-05 10:06:18 -08:00
committed by GitHub
parent 2e67d03b56
commit 692ed02df8
14 changed files with 146 additions and 24 deletions

View File

@@ -197,3 +197,36 @@ export class AddFeatureTabAction extends Action {
}
}
}
export class CollapseWidgetAction extends Action {
private static readonly ID = 'collapseWidget';
private static readonly COLLPASE_LABEL = nls.localize('collapseWidget', "Collapse");
private static readonly EXPAND_LABEL = nls.localize('expandWidget', "Expand");
private static readonly COLLAPSE_ICON = 'maximize-panel-action';
private static readonly EXPAND_ICON = 'minimize-panel-action';
constructor(
private _uri: string,
private _widgetUuid: string,
private collpasedState: boolean,
@IAngularEventingService private _angularEventService: IAngularEventingService
) {
super(
CollapseWidgetAction.ID,
collpasedState ? CollapseWidgetAction.EXPAND_LABEL : CollapseWidgetAction.COLLPASE_LABEL,
collpasedState ? CollapseWidgetAction.EXPAND_ICON : CollapseWidgetAction.COLLAPSE_ICON
);
}
run(): TPromise<boolean> {
this._toggleState();
this._angularEventService.sendAngularEvent(this._uri, AngularEventType.COLLAPSE_WIDGET, this._widgetUuid);
return TPromise.as(true);
}
private _toggleState(): void {
this.collpasedState = !this.collpasedState;
this._setClass(this.collpasedState ? CollapseWidgetAction.EXPAND_ICON : CollapseWidgetAction.COLLAPSE_ICON);
this._setLabel(this.collpasedState ? CollapseWidgetAction.EXPAND_LABEL : CollapseWidgetAction.COLLPASE_LABEL);
}
}

View File

@@ -89,7 +89,6 @@ export abstract class DashboardPage extends Disposable implements OnDestroy {
constructor(
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
@Inject(BOOTSTRAP_SERVICE_ID) protected bootstrapService: IBootstrapService,
@Inject(forwardRef(() => ElementRef)) protected _el: ElementRef,
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef
) {
@@ -252,12 +251,14 @@ export abstract class DashboardPage extends Disposable implements OnDestroy {
}
private getProperties(): Array<WidgetConfig> {
let properties = this.dashboardService.getSettings<IPropertiesConfig[]>([this.context, 'properties'].join('.'));
let properties = this.dashboardService.getSettings<IPropertiesConfig[] | string | boolean>([this.context, 'properties'].join('.'));
this._propertiesConfigLocation = 'default';
if (types.isUndefinedOrNull(properties)) {
return [this.propertiesWidget];
} else if (types.isBoolean(properties)) {
return properties ? [this.propertiesWidget] : [];
} else if (types.isString(properties) && properties === 'collapsed') {
return [this.propertiesWidget];
} else if (types.isArray(properties)) {
return properties.map((item) => {
let retVal = Object.assign({}, this.propertiesWidget);
@@ -302,6 +303,6 @@ export abstract class DashboardPage extends Disposable implements OnDestroy {
let index = this.tabs.findIndex(i => i.id === tab.identifier);
this.tabs.splice(index, 1);
this._cd.detectChanges();
this.bootstrapService.angularEventingService.sendAngularEvent(this.dashboardService.getUnderlyingUri(), AngularEventType.CLOSE_TAB, { id: tab.identifier });
this.dashboardService.angularEventingService.sendAngularEvent(this.dashboardService.getUnderlyingUri(), AngularEventType.CLOSE_TAB, { id: tab.identifier });
}
}

View File

@@ -5,11 +5,15 @@
import 'vs/css!./dashboardHomeContainer';
import { Component, forwardRef, Input } from '@angular/core';
import { Component, forwardRef, Input, ChangeDetectorRef, Inject, ViewChild } from '@angular/core';
import { DashboardWidgetContainer } from 'sql/parts/dashboard/containers/dashboardWidgetContainer.component';
import { DashboardTab } from 'sql/parts/dashboard/common/interfaces';
import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import { AngularEventType } from '../../../services/angularEventing/angularEventingService';
import { DashboardWidgetWrapper } from 'sql/parts/dashboard/contents/dashboardWidgetWrapper.component';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
@Component({
selector: 'dashboard-home-container',
@@ -17,7 +21,8 @@ import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
template: `
<div class="scroll-container" #scrollContainer>
<div class="scrollable" #scrollable>
<dashboard-widget-wrapper *ngIf="properties" [_config]="properties" style="padding-left: 10px; padding-right: 10px; height: 90px; display: block">
<dashboard-widget-wrapper #propertiesClass *ngIf="properties" [collapsable]="true" [_config]="properties"
style="padding-left: 10px; padding-right: 10px; display: block" [style.height.px]="_propertiesClass?.collapsed ? '30' : '90'">
</dashboard-widget-wrapper>
<widget-content [widgets]="widgets" [originalConfig]="tab.originalConfig" [context]="tab.context">
</widget-content>
@@ -27,4 +32,30 @@ import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
})
export class DashboardHomeContainer extends DashboardWidgetContainer {
@Input() private properties: WidgetConfig;
@ViewChild('propertiesClass') private _propertiesClass: DashboardWidgetWrapper;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
@Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface,
) {
super(_cd);
}
ngAfterContentInit() {
let collapsedVal = this.dashboardService.getSettings<string>(`${this.properties.context}.properties`);
if (collapsedVal === 'collapsed') {
this._propertiesClass.collapsed = true;
}
this.dashboardService.angularEventingService.onAngularEvent(this.dashboardService.getUnderlyingUri(), event => {
if (event.event === AngularEventType.COLLAPSE_WIDGET && this._propertiesClass && event.payload === this._propertiesClass.guid) {
this._propertiesClass.collapsed = !this._propertiesClass.collapsed;
this._cd.detectChanges();
this.dashboardService.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, {
key: `dashboard.${this.properties.context}.properties`,
value: this._propertiesClass.collapsed ? 'collapsed' : true
});
}
});
}
}

View File

@@ -43,7 +43,7 @@ export class DashboardWidgetContainer extends DashboardTab implements OnDestroy,
private _scrollableElement: ScrollableElement;
@ViewChild(WidgetContent) private _widgetContent: WidgetContent;
@ViewChild(WidgetContent) protected _widgetContent: WidgetContent;
@ViewChild('scrollable', { read: ElementRef }) private _scrollable: ElementRef;
@ViewChild('scrollContainer', { read: ElementRef }) private _scrollContainer: ElementRef;

View File

@@ -13,6 +13,8 @@
<span *ngIf="_config.icon" [ngClass]="['icon', _config.icon]" style="display: inline-block; padding: 10px; margin-left: 5px"></span>
</div>
</div>
<ng-template component-host>
<ng-template [ngIf]="!collapsed">
<ng-template component-host>
</ng-template>
</ng-template>
</div>

View File

@@ -14,7 +14,7 @@ import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost
import { WidgetConfig, WIDGET_CONFIG, IDashboardWidget } from 'sql/parts/dashboard/common/dashboardWidget';
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
import { error } from 'sql/base/common/log';
import { RefreshWidgetAction, ToggleMoreWidgetAction, DeleteWidgetAction } from 'sql/parts/dashboard/common/actions';
import { RefreshWidgetAction, ToggleMoreWidgetAction, DeleteWidgetAction, CollapseWidgetAction } from 'sql/parts/dashboard/common/actions';
/* Widgets */
import { PropertiesWidgetComponent } from 'sql/parts/dashboard/widgets/properties/propertiesWidget.component';
@@ -32,6 +32,8 @@ import * as themeColors from 'vs/workbench/common/theme';
import { Action } from 'vs/base/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { memoize } from 'vs/base/common/decorators';
import { generateUuid } from 'vs/base/common/uuid';
const componentMap: { [x: string]: Type<IDashboardWidget> } = {
'properties-widget': PropertiesWidgetComponent,
@@ -45,8 +47,32 @@ const componentMap: { [x: string]: Type<IDashboardWidget> } = {
selector: 'dashboard-widget-wrapper',
templateUrl: decodeURI(require.toUrl('sql/parts/dashboard/contents/dashboardWidgetWrapper.component.html'))
})
export class DashboardWidgetWrapper implements AfterContentInit, OnInit, OnDestroy {
export class DashboardWidgetWrapper implements OnInit, OnDestroy {
@Input() private _config: WidgetConfig;
@Input() private collapsable = false;
private _collapsed = false;
public get collapsed(): boolean {
return this._collapsed;
}
public set collapsed(val: boolean) {
if (val === this._collapsed) {
return;
}
this._collapsed = val;
this._changeref.detectChanges();
if (!val) {
this.loadWidget();
}
}
@memoize
public get guid(): string {
return generateUuid();
}
private _themeDispose: IDisposable;
private _actions: Array<Action>;
private _component: IDashboardWidget;
@@ -71,12 +97,17 @@ export class DashboardWidgetWrapper implements AfterContentInit, OnInit, OnDestr
});
}
ngAfterContentInit() {
ngAfterViewInit() {
this.updateTheme(this._bootstrap.themeService.getColorTheme());
this.loadWidget();
if (this.componentHost) {
this.loadWidget();
}
this._changeref.detectChanges();
this._actionbar = new ActionBar(this._actionbarRef.nativeElement);
if (this._actions) {
if (this.collapsable) {
this._actionbar.push(this._bootstrap.instantiationService.createInstance(CollapseWidgetAction, this._bootstrap.getUnderlyingUri(), this.guid, this.collapsed), { icon: true, label: false });
}
this._actionbar.push(this._bootstrap.instantiationService.createInstance(ToggleMoreWidgetAction, this._actions, this._component.actionsContext), { icon: true, label: false });
}
this.layout();

View File

@@ -35,12 +35,11 @@ export class DatabaseDashboardPage extends DashboardPage implements OnInit {
constructor(
@Inject(forwardRef(() => IBreadcrumbService)) private _breadcrumbService: IBreadcrumbService,
@Inject(BOOTSTRAP_SERVICE_ID) bootstrapService: IBootstrapService,
@Inject(forwardRef(() => DashboardServiceInterface)) dashboardService: DashboardServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(dashboardService, bootstrapService, el, _cd);
super(dashboardService, el, _cd);
this._register(dashboardService.onUpdatePage(() => {
this.refresh(true);
this._cd.detectChanges();

View File

@@ -12,6 +12,10 @@ export const databaseDashboardPropertiesSchema: IJSONSchema = {
default: true,
oneOf: <IJSONSchema[]>[
{ type: 'boolean' },
{
type: 'string',
enum: ['collapsed']
},
{
type: 'array',
items: {

View File

@@ -36,12 +36,11 @@ export class ServerDashboardPage extends DashboardPage implements OnInit {
constructor(
@Inject(forwardRef(() => IBreadcrumbService)) private breadcrumbService: IBreadcrumbService,
@Inject(BOOTSTRAP_SERVICE_ID) bootstrapService: IBootstrapService,
@Inject(forwardRef(() => DashboardServiceInterface)) dashboardService: DashboardServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(dashboardService, bootstrapService, el, _cd);
super(dashboardService, el, _cd);
// revert back to default database
this._letDashboardPromise = this.dashboardService.connectionManagementService.changeDatabase('master');
}

View File

@@ -20,6 +20,10 @@ export const serverDashboardPropertiesSchema: IJSONSchema = {
default: true,
oneOf: [
{ type: 'boolean' },
{
type: 'string',
enum: ['collapsed']
},
{
type: 'object',
properties: {

View File

@@ -20,7 +20,7 @@ import { toDisposableSubscription } from 'sql/parts/common/rxjsUtils';
import { IInsightsDialogService } from 'sql/parts/insights/common/interfaces';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { AngularEventType, IAngularEvent } from 'sql/services/angularEventing/angularEventingService';
import { AngularEventType, IAngularEvent, IAngularEventingService } from 'sql/services/angularEventing/angularEventingService';
import { IDashboardTab } from 'sql/platform/dashboard/common/dashboardRegistry';
import { PinConfig } from 'sql/parts/dashboard/common/dashboardWidget';
@@ -137,6 +137,7 @@ export class DashboardServiceInterface implements OnDestroy {
private _commandService: ICommandService;
private _dashboardWebviewService: IDashboardWebviewService;
private _partService: IPartService;
private _angularEventingService: IAngularEventingService;
private _updatePage = new Emitter<void>();
public readonly onUpdatePage: Event<void> = this._updatePage.event;
@@ -171,6 +172,7 @@ export class DashboardServiceInterface implements OnDestroy {
this._commandService = this._bootstrapService.commandService;
this._dashboardWebviewService = this._bootstrapService.dashboardWebviewService;
this._partService = this._bootstrapService.partService;
this._angularEventingService = this._bootstrapService.angularEventingService;
}
ngOnDestroy() {
@@ -241,6 +243,10 @@ export class DashboardServiceInterface implements OnDestroy {
return this._capabilitiesService;
}
public get angularEventingService(): IAngularEventingService {
return this._angularEventingService;
}
/**
* Set the selector for this dashboard instance, should only be set once
*/

View File

@@ -43,6 +43,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
private _treeDataSource = new ExplorerDataSource();
private _treeFilter = new ExplorerFilter();
private _inited = false;
@ViewChild('input') private _inputContainer: ElementRef;
@ViewChild('table') private _tableContainer: ElementRef;
@@ -58,6 +60,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
}
ngOnInit() {
this._inited = true;
let inputOptions: IInputOptions = {
placeholder: this._config.context === 'database' ? nls.localize('seachObjects', 'Search by name of type (a:, t:, v:, f:, or sp:)') : nls.localize('searchDatabases', 'Search databases')
};
@@ -120,6 +124,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
}
public layout(): void {
this._tree.layout(getContentHeight(this._tableContainer.nativeElement));
if (this._inited) {
this._tree.layout(getContentHeight(this._tableContainer.nativeElement));
}
}
}

View File

@@ -46,6 +46,8 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
private _scrollableElement: ScrollableElement;
private $container: Builder;
private _inited = false;
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
constructor(
@@ -67,6 +69,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
}
ngOnInit() {
this._inited = true;
this._register(registerThemingParticipant(this.registerThemeing));
this._computeContainer();
@@ -137,11 +140,13 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
}
public layout(): void {
this._computeContainer();
// Update scrollbar
this._scrollableElement.setScrollDimensions({
width: DOM.getContentWidth(this._container.nativeElement),
scrollWidth: DOM.getContentWidth(this.$container.getHTMLElement()) + 18 // right padding
});
if (this._inited) {
this._computeContainer();
// Update scrollbar
this._scrollableElement.setScrollDimensions({
width: DOM.getContentWidth(this._container.nativeElement),
scrollWidth: DOM.getContentWidth(this.$container.getHTMLElement()) + 18 // right padding
});
}
}
}

View File

@@ -17,7 +17,8 @@ export enum AngularEventType {
DELETE_WIDGET,
PINUNPIN_TAB,
NEW_TABS,
CLOSE_TAB
CLOSE_TAB,
COLLAPSE_WIDGET
}
export interface IDeleteWidgetPayload {