mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Update dashboard properties widget style for Reflow (#9976)
* layout properties in 2 columns * fix height after collapsing * update with reflow values * set height better * cleanup * fix crashing when resizing while properties widget is loading * Switch to grid layout * Only two columns max * Update comment * Undo color change * Cleanup * Fix test Co-authored-by: chgagnon <chgagnon@microsoft.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import 'vs/css!./dashboardHomeContainer';
|
import 'vs/css!./dashboardHomeContainer';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
|
||||||
import { Component, forwardRef, Input, ChangeDetectorRef, Inject, ViewChild, ElementRef } from '@angular/core';
|
import { Component, forwardRef, Input, ChangeDetectorRef, Inject, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
@@ -22,6 +23,7 @@ import { DASHBOARD_BORDER } from 'vs/workbench/common/theme';
|
|||||||
import { IColorTheme } from 'vs/platform/theme/common/themeService';
|
import { IColorTheme } from 'vs/platform/theme/common/themeService';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
import { PropertiesWidgetComponent } from 'sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'dashboard-home-container',
|
selector: 'dashboard-home-container',
|
||||||
@@ -31,7 +33,7 @@ import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
|||||||
<div scrollable [horizontalScroll]="${ScrollbarVisibility.Hidden}" [verticalScroll]="${ScrollbarVisibility.Auto}">
|
<div scrollable [horizontalScroll]="${ScrollbarVisibility.Hidden}" [verticalScroll]="${ScrollbarVisibility.Auto}">
|
||||||
<div #propertiesContainer>
|
<div #propertiesContainer>
|
||||||
<dashboard-widget-wrapper #propertiesClass *ngIf="properties" [collapsable]="true" [bottomCollapse]="true" [toggleMore]="false" [_config]="properties"
|
<dashboard-widget-wrapper #propertiesClass *ngIf="properties" [collapsable]="true" [bottomCollapse]="true" [toggleMore]="false" [_config]="properties"
|
||||||
class="properties" [style.height.px]="_propertiesClass?.collapsed ? '30' : '75'">
|
class="properties" [style.height.px]="_propertiesClass?.collapsed ? '30' : getHeight()">
|
||||||
</dashboard-widget-wrapper>
|
</dashboard-widget-wrapper>
|
||||||
</div>
|
</div>
|
||||||
<widget-content style="flex: 1" [scrollContent]="false" [widgets]="widgets" [originalConfig]="tab.originalConfig" [context]="tab.context">
|
<widget-content style="flex: 1" [scrollContent]="false" [widgets]="widgets" [originalConfig]="tab.originalConfig" [context]="tab.context">
|
||||||
@@ -46,6 +48,8 @@ export class DashboardHomeContainer extends DashboardWidgetContainer {
|
|||||||
@ViewChild('propertiesContainer') private _propertiesContainer: ElementRef;
|
@ViewChild('propertiesContainer') private _propertiesContainer: ElementRef;
|
||||||
@ViewChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
@ViewChild(ScrollableDirective) private _scrollable: ScrollableDirective;
|
||||||
|
|
||||||
|
private height = 75; // default initial height
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
@Inject(forwardRef(() => ChangeDetectorRef)) _cd: ChangeDetectorRef,
|
||||||
@Inject(forwardRef(() => CommonServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
@Inject(forwardRef(() => CommonServiceInterface)) protected dashboardService: DashboardServiceInterface,
|
||||||
@@ -78,6 +82,18 @@ export class DashboardHomeContainer extends DashboardWidgetContainer {
|
|||||||
this._propertiesClass.collapsed ? 'collapsed' : true, ConfigurationTarget.USER);
|
this._propertiesClass.collapsed ? 'collapsed' : true, ConfigurationTarget.USER);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, e => {
|
||||||
|
this._cd.detectChanges();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHeight(): number {
|
||||||
|
if (this._propertiesClass && (<PropertiesWidgetComponent>this._propertiesClass.component).height) {
|
||||||
|
this.height = (<PropertiesWidgetComponent>this._propertiesClass.component).height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout() {
|
public layout() {
|
||||||
|
|||||||
@@ -165,6 +165,10 @@ export class DashboardWidgetWrapper extends AngularDisposable implements OnInit
|
|||||||
this._actionbar.pull(this._actionbar.length() - 1);
|
this._actionbar.pull(this._actionbar.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get component(): IDashboardWidget {
|
||||||
|
return this._component;
|
||||||
|
}
|
||||||
|
|
||||||
private loadWidget(): void {
|
private loadWidget(): void {
|
||||||
if (Object.keys(this._config.widget).length !== 1) {
|
if (Object.keys(this._config.widget).length !== 1) {
|
||||||
this.logService.error('Exactly 1 widget must be defined per space');
|
this.logService.error('Exactly 1 widget must be defined per space');
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||||||
// tab label
|
// tab label
|
||||||
const tabLabelColor = theme.getColor(TAB_LABEL);
|
const tabLabelColor = theme.getColor(TAB_LABEL);
|
||||||
if (tabLabelColor) {
|
if (tabLabelColor) {
|
||||||
collector.addRule(`properties-widget .propertiesValue {
|
collector.addRule(`properties-widget .propertyValue {
|
||||||
color: ${tabLabelColor}
|
color: ${tabLabelColor}
|
||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
@@ -32,11 +32,11 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
|||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// properties name
|
// property name
|
||||||
const propertiesName = theme.getColor(DASHBOARD_PROPERTIES_NAME);
|
const propertyName = theme.getColor(DASHBOARD_PROPERTIES_NAME);
|
||||||
if (propertiesName) {
|
if (propertyName) {
|
||||||
collector.addRule(`properties-widget .propertiesName {
|
collector.addRule(`properties-widget .propertyName {
|
||||||
color: ${propertiesName}
|
color: ${propertyName}
|
||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,18 +6,12 @@
|
|||||||
-->
|
-->
|
||||||
<loading-spinner [loading]="_loading" [loadingMessage]="_loadingMessage"
|
<loading-spinner [loading]="_loading" [loadingMessage]="_loadingMessage"
|
||||||
[loadingCompletedMessage]="_loadingCompletedMessage"></loading-spinner>
|
[loadingCompletedMessage]="_loadingCompletedMessage"></loading-spinner>
|
||||||
<div #parent style="position: absolute; height: 100%; width: 100%;" [style.display]="_loading ? 'none':'block'">
|
<div class="grid-container {{gridDisplayLayout}}" style="position: absolute; height: 100%; width: 100%;" [style.display]="_loading ? 'none':'grid'">
|
||||||
<div #container [style.margin-right.px]="_clipped ? 30 : 0" [style.width]="_clipped ? 94 + '%' : '100%'" style="overflow: hidden; padding-bottom: 10px">
|
<ng-template ngFor let-item [ngForOf]="_properties">
|
||||||
<span #child style="white-space : nowrap; width: fit-content">
|
<div class="property {{propertyLayout}}" style="display:flex">
|
||||||
<ng-template ngFor let-item [ngForOf]="properties">
|
<div class="propertyName">{{item.displayName}}</div>
|
||||||
<span style="margin-left: 10px; display: inline-block;">
|
<div class="splitter">:</div>
|
||||||
<div class="propertiesName" style="font-size: 11px;">{{item.displayName}}</div>
|
<div class="propertyValue">{{item.value}}</div>
|
||||||
<div class="propertiesValue">{{item.value}}</div>
|
</div>
|
||||||
</span>
|
</ng-template>
|
||||||
</ng-template>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span *ngIf="_clipped" style="position: absolute; right: 0; top: 0; padding-top: 5px; padding-right: 14px; z-index: 2">
|
|
||||||
...
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import 'vs/css!./propertiesWidget';
|
import 'vs/css!./propertiesWidget';
|
||||||
|
|
||||||
import { Component, Inject, forwardRef, ChangeDetectorRef, OnInit, ElementRef, ViewChild } from '@angular/core';
|
import { Component, Inject, forwardRef, ChangeDetectorRef, OnInit, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
|
||||||
import { CommonServiceInterface } from 'sql/workbench/services/bootstrap/browser/commonServiceInterface.service';
|
import { CommonServiceInterface } from 'sql/workbench/services/bootstrap/browser/commonServiceInterface.service';
|
||||||
@@ -57,6 +57,21 @@ export interface DisplayProperty {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GridDisplayLayout {
|
||||||
|
twoColumns = 'twoColumns',
|
||||||
|
oneColumn = 'oneColumn'
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PropertyLayoutDirection {
|
||||||
|
row = 'rowLayout',
|
||||||
|
column = 'columnLayout'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const collapseHeight = 25;
|
||||||
|
const horizontalPropertyHeight = 28;
|
||||||
|
const verticalPropertyHeight = 46;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'properties-widget',
|
selector: 'properties-widget',
|
||||||
templateUrl: decodeURI(require.toUrl('./propertiesWidget.component.html'))
|
templateUrl: decodeURI(require.toUrl('./propertiesWidget.component.html'))
|
||||||
@@ -64,11 +79,10 @@ export interface DisplayProperty {
|
|||||||
export class PropertiesWidgetComponent extends DashboardWidget implements IDashboardWidget, OnInit {
|
export class PropertiesWidgetComponent extends DashboardWidget implements IDashboardWidget, OnInit {
|
||||||
private _connection: ConnectionManagementInfo;
|
private _connection: ConnectionManagementInfo;
|
||||||
private _databaseInfo: DatabaseInfo;
|
private _databaseInfo: DatabaseInfo;
|
||||||
public _clipped: boolean;
|
private _properties: Array<DisplayProperty>;
|
||||||
private properties: Array<DisplayProperty>;
|
public gridDisplayLayout: GridDisplayLayout;
|
||||||
|
public propertyLayout: PropertyLayoutDirection;
|
||||||
@ViewChild('child', { read: ElementRef }) private _child: ElementRef;
|
public height: number;
|
||||||
@ViewChild('parent', { read: ElementRef }) private _parent: ElementRef;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface,
|
||||||
@@ -85,7 +99,7 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this._inited = true;
|
this._inited = true;
|
||||||
this._register(addDisposableListener(window, EventType.RESIZE, () => this.handleClipping()));
|
this._register(addDisposableListener(window, EventType.RESIZE, () => this.layoutProperties()));
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,23 +114,36 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
|||||||
this._databaseInfo = data;
|
this._databaseInfo = data;
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
this.parseProperties();
|
this.parseProperties();
|
||||||
if (this._inited) {
|
|
||||||
this.handleClipping();
|
|
||||||
}
|
|
||||||
this.setLoadingStatus(false);
|
this.setLoadingStatus(false);
|
||||||
|
this.layoutProperties();
|
||||||
}, error => {
|
}, error => {
|
||||||
this.setLoadingStatus(false);
|
this.setLoadingStatus(false);
|
||||||
(<HTMLElement>this._el.nativeElement).innerText = nls.localize('dashboard.properties.error', "Unable to load dashboard properties");
|
(<HTMLElement>this._el.nativeElement).innerText = nls.localize('dashboard.properties.error', "Unable to load dashboard properties");
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleClipping(): void {
|
private layoutProperties(): void {
|
||||||
if (this._child.nativeElement.offsetWidth > this._parent.nativeElement.offsetWidth) {
|
// Reflow:
|
||||||
this._clipped = true;
|
// 2 columns w/ horizontal alignment : 1366px and above
|
||||||
} else {
|
// 2 columns w/ vertical alignment : 1024 - 1365px
|
||||||
this._clipped = false;
|
// 1 column w/ vertical alignment : 1024px or less
|
||||||
|
if (!this._loading) {
|
||||||
|
if (window.innerWidth >= 1366) {
|
||||||
|
this.gridDisplayLayout = GridDisplayLayout.twoColumns;
|
||||||
|
this.propertyLayout = PropertyLayoutDirection.row;
|
||||||
|
this.height = Math.ceil(this._properties.length / 2) * horizontalPropertyHeight + collapseHeight;
|
||||||
|
} else if (window.innerWidth < 1366 && window.innerWidth >= 1024) {
|
||||||
|
this.gridDisplayLayout = GridDisplayLayout.twoColumns;
|
||||||
|
this.propertyLayout = PropertyLayoutDirection.column;
|
||||||
|
this.height = Math.ceil(this._properties.length / 2) * verticalPropertyHeight + collapseHeight;
|
||||||
|
} else if (window.innerWidth < 1024) {
|
||||||
|
this.gridDisplayLayout = GridDisplayLayout.oneColumn;
|
||||||
|
this.propertyLayout = PropertyLayoutDirection.column;
|
||||||
|
this.height = this._properties.length * verticalPropertyHeight + collapseHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._changeRef.detectChanges();
|
||||||
}
|
}
|
||||||
this._changeRef.detectChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseProperties() {
|
private parseProperties() {
|
||||||
@@ -208,11 +235,7 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
|||||||
infoObject = this._connection.serverInfo;
|
infoObject = this._connection.serverInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over properties and display them
|
this._properties = propertyArray.map(property => {
|
||||||
this.properties = [];
|
|
||||||
for (let i = 0; i < propertyArray.length; i++) {
|
|
||||||
const property = propertyArray[i];
|
|
||||||
const assignProperty = {};
|
|
||||||
let propertyObject = this.getValueOrDefault<string>(infoObject, property.value, property.default || '--');
|
let propertyObject = this.getValueOrDefault<string>(infoObject, property.value, property.default || '--');
|
||||||
|
|
||||||
// make sure the value we got shouldn't be ignored
|
// make sure the value we got shouldn't be ignored
|
||||||
@@ -225,10 +248,11 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assignProperty['displayName'] = property.displayName;
|
return {
|
||||||
assignProperty['value'] = propertyObject;
|
displayName: property.displayName,
|
||||||
this.properties.push(<DisplayProperty>assignProperty);
|
value: propertyObject
|
||||||
}
|
};
|
||||||
|
});
|
||||||
|
|
||||||
if (this._inited) {
|
if (this._inited) {
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
|
|||||||
@@ -3,11 +3,43 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
.propertiesName {
|
properties-widget .twoColumns.grid-container {
|
||||||
opacity: 0.6;
|
grid-template-columns: 50% 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs-dark .propertiesName,
|
properties-widget .oneColumn.grid-container {
|
||||||
.hc-black .propertiesName {
|
grid-template-columns: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties-widget .columnLayout.property {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties-widget .propertyName {
|
||||||
|
opacity: 0.6;
|
||||||
|
font-size: 12px;
|
||||||
|
flex: 0 0 auto
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark properties-widget .propertyName,
|
||||||
|
.hc-black properties-widget .propertyName {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
properties-widget .propertyValue {
|
||||||
|
font-size: 12px;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-right: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties-widget .splitter {
|
||||||
|
flex: 0 0 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties-widget .columnLayout .splitter {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ suite('Dashboard Properties Widget Tests', () => {
|
|||||||
// because config parsing is done async we need to put our asserts on the thread stack
|
// because config parsing is done async we need to put our asserts on the thread stack
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
// because properties is private we need to do some work arounds to access it.
|
// because properties is private we need to do some work arounds to access it.
|
||||||
assert.equal((<any>testComponent).properties.length, 1);
|
assert.equal((<any>testComponent)._properties.length, 1);
|
||||||
assert.equal((<any>testComponent).properties[0].displayName, 'Test');
|
assert.equal((<any>testComponent)._properties[0].displayName, 'Test');
|
||||||
assert.equal((<any>testComponent).properties[0].value, 'Test Property');
|
assert.equal((<any>testComponent)._properties[0].value, 'Test Property');
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user