Browse Source

UI: Sys admin home page responsive layout.

pull/8359/head
Igor Kulikov 4 years ago
parent
commit
1ca6c1acb7
  1. 2
      ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.scss
  2. 10
      ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts
  3. 2
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.html
  4. 33
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.scss
  5. 37
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.ts
  6. 2
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html
  7. 33
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.scss
  8. 38
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.ts
  9. 3
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-doc-links-dialog.component.scss
  10. 10
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/version-info.component.html
  11. 58
      ui-ngx/src/app/modules/home/components/widget/lib/home-page/version-info.component.scss
  12. 19
      ui-ngx/src/app/modules/home/models/dashboard-component.models.ts
  13. 115
      ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw

2
ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.scss

@ -14,6 +14,8 @@
* limitations under the License.
*/
:host {
display: block;
height: 100%;
button.tb-add-new-widget {
height: auto;
padding-right: 12px;

10
ui-ngx/src/app/modules/home/components/dashboard/dashboard.component.ts

@ -510,7 +510,12 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
}
private updateMobileOpts(parentHeight?: number) {
this.isMobileSize = this.checkIsMobileSize();
let updateWidgetRowsAndSort = false;
const isMobileSize = this.checkIsMobileSize();
if (this.isMobileSize !== isMobileSize) {
this.isMobileSize = isMobileSize;
updateWidgetRowsAndSort = true;
}
const autofillHeight = this.isAutofillHeight();
if (autofillHeight) {
this.gridsterOpts.gridType = this.isMobileSize ? GridType.Fixed : GridType.Fit;
@ -523,6 +528,9 @@ export class DashboardComponent extends PageComponent implements IDashboardCompo
if (this.gridsterOpts.fixedRowHeight !== rowSize) {
this.gridsterOpts.fixedRowHeight = rowSize;
}
if (updateWidgetRowsAndSort) {
this.dashboardWidgets.updateRowsAndSort();
}
}
private onGridsterParentResize() {

2
ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.html

@ -22,7 +22,7 @@
matTooltipPosition="above"
class="tb-info-icon">info</mat-icon>
</div>
<mat-grid-list class="tb-features-list" fxFlex cols="6" rowHeight="48.5px" gutterSize="12px">
<mat-grid-list class="tb-features-list" fxFlex cols="6" [rowHeight]="rowHeight" [gutterSize]="gutterSize">
<mat-grid-tile class="tb-feature-tile" colspan="3">
<a class="tb-feature-button" fxFlex
[matTooltip]="featureTooltip(featuresInfo?.emailEnabled)"

33
ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.scss

@ -27,6 +27,10 @@
line-height: 20px;
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.54);
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 12px;
line-height: 16px;
}
}
.tb-info-icon {
@ -49,6 +53,7 @@
.tb-feature-button {
height: 48.5px;
display: flex;
overflow: hidden;
flex-direction: column;
justify-content: center;
padding: 12px;
@ -56,6 +61,10 @@
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.04);
border-radius: 10px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
height: 21.5px;
padding: 0 8px;
}
&:hover {
border: 1px solid rgba(0, 0, 0, 0.12);
box-shadow: 0 4px 10px rgba(23, 33, 90, 0.08);
@ -65,20 +74,36 @@
font-size: 14px;
line-height: 20px;
color: rgba(0, 0, 0, 0.87);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 11px;
line-height: 16px;
}
&:before {
content: "close";
display: inline-block;
font-family: 'Material Icons Round';
font-size: 20px;
line-height: 1;
line-height: 20px;
color: rgba(0, 0, 0, 0.12);
font-weight: 600;
position: relative;
background: #F4F4F4;
border-radius: 4px;
width: 24px;
height: 24px;
width: 20px;
height: 20px;
padding: 2px;
margin-right: 8px;
vertical-align: bottom;
vertical-align: middle;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 14px;
line-height: 14px;
width: 14px;
height: 14px;
margin-right: 4px;
}
}
}
&.configured {

37
ui-ngx/src/app/modules/home/components/widget/lib/home-page/configured-features.component.ts

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -22,25 +22,47 @@ import { AdminService } from '@core/http/admin.service';
import { FeaturesInfo } from '@shared/models/settings.models';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
import { of } from 'rxjs';
import { of, Subscription } from 'rxjs';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
@Component({
selector: 'tb-configured-features',
templateUrl: './configured-features.component.html',
styleUrls: ['./configured-features.component.scss']
})
export class ConfiguredFeaturesComponent extends PageComponent implements OnInit {
export class ConfiguredFeaturesComponent extends PageComponent implements OnInit, OnDestroy {
authUser = getCurrentAuthUser(this.store);
featuresInfo: FeaturesInfo;
rowHeight = '48.5px';
gutterSize = '12px';
private observeBreakpointSubscription: Subscription;
constructor(protected store: Store<AppState>,
private cd: ChangeDetectorRef,
private adminService: AdminService) {
private adminService: AdminService,
private breakpointObserver: BreakpointObserver) {
super(store);
}
ngOnInit() {
const isMdLg = this.breakpointObserver.isMatched('screen and (min-width: 960px) and (max-width: 1819px)');
this.rowHeight = isMdLg ? '21.5px' : '48.5px';
this.gutterSize = isMdLg ? '8px' : '12px';
this.observeBreakpointSubscription = this.breakpointObserver
.observe('screen and (min-width: 960px) and (max-width: 1819px)')
.subscribe((state: BreakpointState) => {
if (state.matches) {
this.rowHeight = '21.5px';
this.gutterSize = '8px';
} else {
this.rowHeight = '48.5px';
this.gutterSize = '12px';
}
this.cd.markForCheck();
}
);
(this.authUser.authority === Authority.SYS_ADMIN ?
this.adminService.getFeaturesInfo() : of(null)).subscribe(
(featuresInfo) => {
@ -50,6 +72,13 @@ export class ConfiguredFeaturesComponent extends PageComponent implements OnInit
);
}
ngOnDestroy() {
if (this.observeBreakpointSubscription) {
this.observeBreakpointSubscription.unsubscribe();
}
super.ngOnDestroy();
}
featureTooltip(configured: boolean): string {
if (configured) {
return 'Feature is configured.\nClick to setup';

2
ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html

@ -26,7 +26,7 @@
<mat-icon>edit</mat-icon>
</button>
</div>
<mat-grid-list class="tb-docs-list" fxFlex [cols]="columns" rowHeight="55px" gutterSize="12px">
<mat-grid-list class="tb-docs-list" fxFlex [cols]="columns" [rowHeight]="rowHeight" [gutterSize]="gutterSize">
<mat-grid-tile class="tb-docs-tile" *ngFor="let docLink of documentationLinks?.links">
<a fxFlex class="tb-doc-button"
[href]="docLink.link" target="_blank">

33
ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.scss

@ -35,21 +35,24 @@
color: rgba(0, 0, 0, 0.54);
position: relative;
border-bottom: none;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 12px;
line-height: 16px;
}
&:hover, &:focus {
border-bottom: none;
}
&::after {
content: 'arrow_forward';
display: inline-block;
position: absolute;
top: -2px;
right: -28px;
transform: rotate(315deg);
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 18px;
color: rgba(0, 0, 0, 0.12);
vertical-align: bottom;
margin-left: 6px;
}
&:hover::after {
color: inherit;
@ -74,6 +77,7 @@
.tb-doc-button {
height: 55px;
display: flex;
overflow: hidden;
flex-direction: column;
justify-content: center;
padding: 8px;
@ -81,6 +85,10 @@
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.04);
border-radius: 10px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
height: 18px;
padding: 0 8px;
}
&:hover {
border: 1px solid rgba(0, 0, 0, 0.12);
box-shadow: 0 4px 10px rgba(23, 33, 90, 0.08);
@ -95,6 +103,9 @@
background: #F3F6FA;
border-radius: 6px;
margin-right: 8px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
display: none;
}
}
.tb-doc-text {
font-weight: 400;
@ -102,6 +113,13 @@
line-height: 20px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.87);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 11px;
line-height: 16px;
}
}
}
}
@ -117,6 +135,15 @@
padding: 8px;
border: 2px dashed rgba(0, 0, 0, 0.08);
border-radius: 10px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
height: 18px;
padding: 0 8px;
.tb-add-icon {
height: 12px;
width: 12px;
font-size: 12px;
}
}
.tb-add-icon {
color: rgba(0, 0, 0, 0.12);
}

38
ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.ts

@ -14,12 +14,12 @@
/// limitations under the License.
///
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Authority } from '@shared/models/authority.enum';
import { map } from 'rxjs';
import { map, Subscription } from 'rxjs';
import { DocumentationLink, DocumentationLinks } from '@shared/models/user-settings.models';
import { UserSettingsService } from '@core/http/user-settings.service';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
@ -34,6 +34,8 @@ import {
EditDocLinksDialogComponent,
EditDocLinksDialogData
} from '@home/components/widget/lib/home-page/edit-doc-links-dialog.component';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { MediaBreakpoints } from '@shared/models/constants';
const defaultDocLinksMap = new Map<Authority, DocumentationLinks>(
[
@ -100,30 +102,58 @@ interface DocLinksWidgetSettings {
templateUrl: './doc-links-widget.component.html',
styleUrls: ['./doc-links-widget.component.scss']
})
export class DocLinksWidgetComponent extends PageComponent implements OnInit {
export class DocLinksWidgetComponent extends PageComponent implements OnInit, OnDestroy {
@Input()
ctx: WidgetContext;
settings: DocLinksWidgetSettings;
columns: number;
rowHeight = '55px';
gutterSize = '12px';
documentationLinks: DocumentationLinks;
authUser = getCurrentAuthUser(this.store);
private observeBreakpointSubscription: Subscription;
constructor(protected store: Store<AppState>,
private cd: ChangeDetectorRef,
private userSettingsService: UserSettingsService,
private dialog: MatDialog) {
private dialog: MatDialog,
private breakpointObserver: BreakpointObserver) {
super(store);
}
ngOnInit() {
this.settings = this.ctx.settings;
this.columns = this.settings.columns || 3;
const isMdLg = this.breakpointObserver.isMatched('screen and (min-width: 960px) and (max-width: 1819px)');
this.rowHeight = isMdLg ? '18px' : '55px';
this.gutterSize = isMdLg ? '8px' : '12px';
this.observeBreakpointSubscription = this.breakpointObserver
.observe('screen and (min-width: 960px) and (max-width: 1819px)')
.subscribe((state: BreakpointState) => {
if (state.matches) {
this.rowHeight = '18px';
this.gutterSize = '8px';
} else {
this.rowHeight = '55px';
this.gutterSize = '12px';
}
this.cd.markForCheck();
}
);
this.loadDocLinks();
}
ngOnDestroy() {
if (this.observeBreakpointSubscription) {
this.observeBreakpointSubscription.unsubscribe();
}
super.ngOnDestroy();
}
private loadDocLinks() {
this.userSettingsService.getDocumentationLinks().pipe(
map((documentationLinks) => {

3
ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-doc-links-dialog.component.scss

@ -16,6 +16,9 @@
:host {
.tb-edit-doc-links-dialog {
width: 480px;
.mat-mdc-dialog-content {
max-height: 50vh;
}
.mat-toolbar-single-row {
padding: 0 24px;
}

10
ui-ngx/src/app/modules/home/components/widget/lib/home-page/version-info.component.html

@ -15,12 +15,12 @@
limitations under the License.
-->
<div class="tb-card-content" fxLayout="column" fxLayoutGap="8px">
<div class="tb-card-header">
<div class="tb-card-content" fxLayout="column">
<div class="tb-card-header tb-card-title">
<div class="tb-title">Version</div>
<a mat-button color="primary" href="https://thingsboard.io/docs/contact-us/" target="_blank">Contact us</a>
<a mat-button color="primary" class="tb-contact-us" href="https://thingsboard.io/docs/contact-us/" target="_blank">Contact us</a>
</div>
<div fxLayout="column" fxFlex fxLayoutGap="12px">
<div fxLayout="column" fxFlex>
<div class="tb-version-info-container" fxFlex>
<div class="tb-card-header">
<a class="tb-version-link" [href]="updateMessage?.currentVersionReleaseNotesUrl" target="_blank">Current version</a>
@ -30,7 +30,7 @@
<div class="tb-version-info-container" fxFlex *ngIf="updateMessage?.updateAvailable; else versionUpToDate">
<div class="tb-card-header">
<a class="tb-version-link" [href]="updateMessage?.latestVersionReleaseNotesUrl" target="_blank">Available version</a>
<a mat-flat-button color="primary" [href]="updateMessage?.upgradeInstructionsUrl" target="_blank">Upgrade</a>
<a mat-flat-button color="primary" class="tb-upgrade" [href]="updateMessage?.upgradeInstructionsUrl" target="_blank">Upgrade</a>
</div>
<div class="tb-version">{{ updateMessage?.latestVersion }}</div>
</div>

58
ui-ngx/src/app/modules/home/components/widget/lib/home-page/version-info.component.scss

@ -26,6 +26,13 @@
align-items: center;
}
.tb-card-title {
margin-bottom: 8px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
margin-bottom: 4px;
}
}
.tb-title {
font-style: normal;
font-weight: 500;
@ -33,16 +40,30 @@
line-height: 20px;
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.54);
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 12px;
line-height: 16px;
}
}
.tb-contact-us {
@media screen and (min-width: 960px) and (max-width: 1819px) {
height: 24px;
font-size: 12px;
}
}
.tb-version-info-container {
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.04);
border-radius: 10px;
padding: 16px;
padding: 8px 16px 4px 16px;
display: flex;
flex-direction: column;
justify-content: space-evenly;
@media screen and (min-width: 960px) and (max-width: 1819px) {
padding: 4px;
}
&.up-to-date {
box-shadow: none;
border: none;
@ -51,6 +72,13 @@
}
}
.tb-version-info-container+.tb-version-info-container {
margin-top: 12px;
@media screen and (min-width: 960px) and (max-width: 1819px) {
margin-top: 4px;
}
}
.tb-version-link {
font-weight: 400;
font-size: 14px;
@ -59,21 +87,24 @@
color: rgba(0, 0, 0, 0.76);
position: relative;
border-bottom: none;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 11px;
line-height: 16px;
}
&:hover, &:focus {
border-bottom: none;
}
&::after {
content: 'arrow_forward';
display: inline-block;
position: absolute;
top: -2px;
right: -28px;
transform: rotate(315deg);
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 18px;
color: rgba(0, 0, 0, 0.12);
vertical-align: bottom;
margin-left: 6px;
}
&:hover::after {
color: inherit;
@ -86,11 +117,26 @@
line-height: 24px;
letter-spacing: 0.15px;
color: rgba(0, 0, 0, 0.87);
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 12px;
line-height: 14px;
}
}
.tb-upgrade {
@media screen and (min-width: 960px) and (max-width: 1819px) {
height: 24px;
font-size: 12px;
padding: 0;
}
}
.check-icon {
color: #198038;
font-weight: 600;
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 20px;
}
}
.up-to-date-text {
@ -99,5 +145,9 @@
line-height: 20px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
@media screen and (min-width: 960px) and (max-width: 1819px) {
font-size: 11px;
line-height: 16px;
}
}
}

19
ui-ngx/src/app/modules/home/models/dashboard-component.models.ts

@ -285,7 +285,7 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
return this.dashboardWidgets.find((dashboardWidget) => dashboardWidget.widgetId === widgetId);
}
private updateRowsAndSort() {
updateRowsAndSort() {
let maxRows = this.dashboard.gridsterOpts.maxRows;
this.activeDashboardWidgets.forEach((dashboardWidget) => {
const bottom = dashboardWidget.y + dashboardWidget.rows;
@ -300,6 +300,13 @@ export class DashboardWidgets implements Iterable<DashboardWidget> {
this.dashboardWidgets.sort((widget1, widget2) => {
const row1 = widget1.widgetOrder;
const row2 = widget2.widgetOrder;
if (isDefined(row1) && isUndefined(row2)) {
return -1;
} else if (isUndefined(row1) && isDefined(row2)) {
return 1;
} else if (isUndefined(row1) && isUndefined(row2)) {
return 0;
}
let res = row1 - row2;
if (res === 0) {
res = widget1.x - widget2.x;
@ -627,10 +634,12 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget {
order = this.widgetLayout.mobileOrder;
} else if (isDefined(this.widget.config.mobileOrder) && this.widget.config.mobileOrder >= 0) {
order = this.widget.config.mobileOrder;
} else if (this.widgetLayout) {
order = this.widgetLayout.row;
} else {
order = this.widget.row;
} else if (!this.dashboard.isMobileSize) {
if (this.widgetLayout) {
order = this.widgetLayout.row;
} else {
order = this.widget.row;
}
}
return order;
}

115
ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save