Browse Source

Implement Alarm widget

pull/2411/head
Igor Kulikov 7 years ago
parent
commit
bd8af1111e
  1. 2
      ui-ngx/src/app/core/api/widget-api.models.ts
  2. 8
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  3. 38
      ui-ngx/src/app/modules/home/components/shared-home-components.module.ts
  4. 25
      ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.html
  5. 36
      ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.scss
  6. 42
      ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.ts
  7. 171
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
  8. 3
      ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts
  9. 25
      ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
  10. 11
      ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
  11. 16
      ui-ngx/src/app/shared/models/page/page-link.ts
  12. 5
      ui-ngx/src/styles.scss

2
ui-ngx/src/app/core/api/widget-api.models.ts

@ -259,5 +259,7 @@ export interface IWidgetSubscription {
destroy(): void; destroy(): void;
update(): void;
[key: string]: any; [key: string]: any;
} }

8
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -30,7 +30,6 @@ import { RelationTableComponent } from '@home/components/relation/relation-table
import { RelationDialogComponent } from './relation/relation-dialog.component'; import { RelationDialogComponent } from './relation/relation-dialog.component';
import { AlarmTableHeaderComponent } from '@home/components/alarm/alarm-table-header.component'; import { AlarmTableHeaderComponent } from '@home/components/alarm/alarm-table-header.component';
import { AlarmTableComponent } from '@home/components/alarm/alarm-table.component'; import { AlarmTableComponent } from '@home/components/alarm/alarm-table.component';
import { AlarmDetailsDialogComponent } from '@home/components/alarm/alarm-details-dialog.component';
import { AttributeTableComponent } from '@home/components/attribute/attribute-table.component'; import { AttributeTableComponent } from '@home/components/attribute/attribute-table.component';
import { AddAttributeDialogComponent } from './attribute/add-attribute-dialog.component'; import { AddAttributeDialogComponent } from './attribute/add-attribute-dialog.component';
import { EditAttributeValuePanelComponent } from './attribute/edit-attribute-value-panel.component'; import { EditAttributeValuePanelComponent } from './attribute/edit-attribute-value-panel.component';
@ -64,6 +63,7 @@ import { AddWidgetToDashboardDialogComponent } from './attribute/add-widget-to-d
import { ImportDialogCsvComponent } from './import-export/import-dialog-csv.component'; import { ImportDialogCsvComponent } from './import-export/import-dialog-csv.component';
import { TableColumnsAssignmentComponent } from './import-export/table-columns-assignment.component'; import { TableColumnsAssignmentComponent } from './import-export/table-columns-assignment.component';
import { EventContentDialogComponent } from '@home/components/event/event-content-dialog.component'; import { EventContentDialogComponent } from '@home/components/event/event-content-dialog.component';
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
@NgModule({ @NgModule({
entryComponents: [ entryComponents: [
@ -73,7 +73,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
EventTableHeaderComponent, EventTableHeaderComponent,
RelationDialogComponent, RelationDialogComponent,
AlarmTableHeaderComponent, AlarmTableHeaderComponent,
AlarmDetailsDialogComponent,
AddAttributeDialogComponent, AddAttributeDialogComponent,
EditAttributeValuePanelComponent, EditAttributeValuePanelComponent,
AliasesEntitySelectPanelComponent, AliasesEntitySelectPanelComponent,
@ -104,7 +103,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
RelationFiltersComponent, RelationFiltersComponent,
AlarmTableHeaderComponent, AlarmTableHeaderComponent,
AlarmTableComponent, AlarmTableComponent,
AlarmDetailsDialogComponent,
AttributeTableComponent, AttributeTableComponent,
AddAttributeDialogComponent, AddAttributeDialogComponent,
EditAttributeValuePanelComponent, EditAttributeValuePanelComponent,
@ -136,7 +134,8 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
], ],
imports: [ imports: [
CommonModule, CommonModule,
SharedModule SharedModule,
SharedHomeComponentsModule
], ],
exports: [ exports: [
EntitiesTableComponent, EntitiesTableComponent,
@ -149,7 +148,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
RelationTableComponent, RelationTableComponent,
RelationFiltersComponent, RelationFiltersComponent,
AlarmTableComponent, AlarmTableComponent,
AlarmDetailsDialogComponent,
AttributeTableComponent, AttributeTableComponent,
AliasesEntitySelectComponent, AliasesEntitySelectComponent,
EntityAliasesDialogComponent, EntityAliasesDialogComponent,

38
ui-ngx/src/app/modules/home/components/shared-home-components.module.ts

@ -0,0 +1,38 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module';
import { AlarmDetailsDialogComponent } from '@home/components/alarm/alarm-details-dialog.component';
@NgModule({
entryComponents: [
AlarmDetailsDialogComponent
],
declarations:
[
AlarmDetailsDialogComponent
],
imports: [
CommonModule,
SharedModule
],
exports: [
AlarmDetailsDialogComponent
]
})
export class SharedHomeComponentsModule { }

25
ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.html

@ -0,0 +1,25 @@
<!--
Copyright © 2016-2019 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div fxLayout="column" class="mat-content mat-padding">
<label class="tb-title" translate>alarm.alarm-status-filter</label>
<mat-radio-group [(ngModel)]="subscription.alarmSearchStatus" fxLayout="column" fxLayoutGap="16px">
<mat-radio-button *ngFor="let searchStatus of alarmSearchStatuses" [value]="searchStatus" color="primary">
{{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }}
</mat-radio-button>
</mat-radio-group>
</div>

36
ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.scss

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2019 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
width: 100%;
height: 100%;
min-width: 300px;
overflow: hidden;
background: #fff;
border-radius: 4px;
box-shadow:
0 7px 8px -4px rgba(0, 0, 0, .2),
0 13px 19px 2px rgba(0, 0, 0, .14),
0 5px 24px 4px rgba(0, 0, 0, .12);
.mat-content {
overflow: hidden;
background-color: #fff;
}
.mat-padding {
padding: 16px;
}
}

42
ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.ts

@ -0,0 +1,42 @@
///
/// Copyright © 2016-2019 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, Inject, InjectionToken } from '@angular/core';
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { AlarmSearchStatus, alarmSearchStatusTranslations } from '@shared/models/alarm.models';
export const ALARM_STATUS_FILTER_PANEL_DATA = new InjectionToken<any>('AlarmStatusFilterPanelData');
export interface AlarmStatusFilterPanelData {
subscription: IWidgetSubscription;
}
@Component({
selector: 'tb-alarm-status-filter-panel',
templateUrl: './alarm-status-filter-panel.component.html',
styleUrls: ['./alarm-status-filter-panel.component.scss']
})
export class AlarmStatusFilterPanelComponent {
subscription: IWidgetSubscription;
alarmSearchStatuses = Object.keys(AlarmSearchStatus);
alarmSearchStatusTranslationMap = alarmSearchStatusTranslations;
constructor(@Inject(ALARM_STATUS_FILTER_PANEL_DATA) public data: AlarmStatusFilterPanelData) {
this.subscription = this.data.subscription;
}
}

171
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts

@ -39,7 +39,7 @@ import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order'; import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order';
import { DataSource } from '@angular/cdk/typings/collections'; import { DataSource } from '@angular/cdk/typings/collections';
import { CollectionViewer, SelectionModel } from '@angular/cdk/collections'; import { CollectionViewer, SelectionModel } from '@angular/cdk/collections';
import { BehaviorSubject, fromEvent, merge, Observable, of } from 'rxjs'; import { BehaviorSubject, forkJoin, fromEvent, merge, Observable, of } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data'; import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { entityTypeTranslations } from '@shared/models/entity-type.models'; import { entityTypeTranslations } from '@shared/models/entity-type.models';
import { catchError, debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators'; import { catchError, debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators';
@ -77,6 +77,19 @@ import {
alarmStatusTranslations alarmStatusTranslations
} from '@shared/models/alarm.models'; } from '@shared/models/alarm.models';
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import {
ALARM_STATUS_FILTER_PANEL_DATA,
AlarmStatusFilterPanelComponent,
AlarmStatusFilterPanelData
} from '@home/components/widget/lib/alarm-status-filter-panel.component';
import {
AlarmDetailsDialogComponent,
AlarmDetailsDialogData
} from '@home/components/alarm/alarm-details-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { DialogService } from '@core/services/dialog.service';
import { AlarmService } from '@core/http/alarm.service';
interface AlarmsTableWidgetSettings extends TableWidgetSettings { interface AlarmsTableWidgetSettings extends TableWidgetSettings {
alarmsTitle: string; alarmsTitle: string;
@ -172,7 +185,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private utils: UtilsService, private utils: UtilsService,
public translate: TranslateService, public translate: TranslateService,
private domSanitizer: DomSanitizer, private domSanitizer: DomSanitizer,
private datePipe: DatePipe) { private datePipe: DatePipe,
private dialog: MatDialog,
private dialogService: DialogService,
private alarmService: AlarmService) {
super(store); super(store);
const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder); const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder);
@ -390,7 +406,36 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
} }
private editAlarmStatusFilter($event: Event) { private editAlarmStatusFilter($event: Event) {
// TODO: if ($event) {
$event.stopPropagation();
}
const target = $event.target || $event.srcElement || $event.currentTarget;
const config = new OverlayConfig();
config.backdropClass = 'cdk-overlay-transparent-backdrop';
config.hasBackdrop = true;
const connectedPosition: ConnectedPosition = {
originX: 'end',
originY: 'bottom',
overlayX: 'end',
overlayY: 'top'
};
config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement)
.withPositions([connectedPosition]);
const overlayRef = this.overlay.create(config);
overlayRef.backdropClick().subscribe(() => {
overlayRef.dispose();
});
const injectionTokens = new WeakMap<any, any>([
[ALARM_STATUS_FILTER_PANEL_DATA, {
subscription: this.subscription,
} as AlarmStatusFilterPanelData],
[OverlayRef, overlayRef]
]);
const injector = new PortalInjector(this.viewContainerRef.injector, injectionTokens);
overlayRef.attach(new ComponentPortal(AlarmStatusFilterPanelComponent,
this.viewContainerRef, injector));
this.ctx.detectChanges();
} }
private enterFilterMode() { private enterFilterMode() {
@ -538,35 +583,138 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
// TODO: if (alarm && alarm.id && alarm.id.id !== NULL_UUID) {
this.dialog.open<AlarmDetailsDialogComponent, AlarmDetailsDialogData, boolean>
(AlarmDetailsDialogComponent,
{
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
alarmId: alarm.id.id,
allowAcknowledgment: this.allowAcknowledgment,
allowClear: this.allowClear,
displayDetails: true
}
}).afterClosed().subscribe(
(res) => {
if (res) {
this.subscription.update();
}
}
);
}
} }
private ackAlarm($event: Event, alarm: AlarmInfo) { private ackAlarm($event: Event, alarm: AlarmInfo) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
// TODO: if (alarm && alarm.id && alarm.id.id !== NULL_UUID) {
this.dialogService.confirm(
this.translate.instant('alarm.aknowledge-alarm-title'),
this.translate.instant('alarm.aknowledge-alarm-text'),
this.translate.instant('action.no'),
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
this.alarmService.ackAlarm(alarm.id.id).subscribe(() => {
this.subscription.update();
});
}
}
});
}
} }
public ackAlarms($event: Event) { public ackAlarms($event: Event) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
// TODO: if (this.alarmsDatasource.selection.hasValue()) {
const alarms = this.alarmsDatasource.selection.selected.filter(
(alarm) => { return alarm.id.id !== NULL_UUID }
);
if (alarms.length) {
const title = this.translate.instant('alarm.aknowledge-alarms-title', {count: alarms.length});
const content = this.translate.instant('alarm.aknowledge-alarms-text', {count: alarms.length});
this.dialogService.confirm(
title,
content,
this.translate.instant('action.no'),
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
const tasks: Observable<void>[] = [];
for (const alarm of alarms) {
tasks.push(this.alarmService.ackAlarm(alarm.id.id));
}
forkJoin(tasks).subscribe(() => {
this.alarmsDatasource.clearSelection();
this.subscription.update();
});
}
}
});
}
}
} }
private clearAlarm($event: Event, alarm: AlarmInfo) { private clearAlarm($event: Event, alarm: AlarmInfo) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
// TODO: if (alarm && alarm.id && alarm.id.id !== NULL_UUID) {
this.dialogService.confirm(
this.translate.instant('alarm.clear-alarm-title'),
this.translate.instant('alarm.clear-alarm-text'),
this.translate.instant('action.no'),
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
this.alarmService.clearAlarm(alarm.id.id).subscribe(() => {
this.subscription.update();
});
}
}
});
}
} }
public clearAlarms($event: Event) { public clearAlarms($event: Event) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
// TODO: if (this.alarmsDatasource.selection.hasValue()) {
const alarms = this.alarmsDatasource.selection.selected.filter(
(alarm) => { return alarm.id.id !== NULL_UUID }
);
if (alarms.length) {
const title = this.translate.instant('alarm.clear-alarms-title', {count: alarms.length});
const content = this.translate.instant('alarm.clear-alarms-text', {count: alarms.length});
this.dialogService.confirm(
title,
content,
this.translate.instant('action.no'),
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
const tasks: Observable<void>[] = [];
for (const alarm of alarms) {
tasks.push(this.alarmService.clearAlarm(alarm.id.id));
}
forkJoin(tasks).subscribe(() => {
this.alarmsDatasource.clearSelection();
this.subscription.update();
});
}
}
});
}
}
} }
private defaultContent(key: EntityColumn, value: any): any { private defaultContent(key: EntityColumn, value: any): any {
@ -722,6 +870,13 @@ class AlarmsDatasource implements DataSource<AlarmInfo> {
return this.selection.isSelected(alarm); return this.selection.isSelected(alarm);
} }
clearSelection() {
if (this.selection.hasValue()) {
this.selection.clear();
this.onSelectionModeChanged(false);
}
}
masterToggle() { masterToggle() {
this.alarmsSubject.pipe( this.alarmsSubject.pipe(
tap((alarms) => { tap((alarms) => {

3
ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts

@ -234,6 +234,9 @@ export function constructTableCssString(widgetConfig: WidgetConfig): string {
'.mat-table .mat-cell button.mat-icon-button mat-icon {\n'+ '.mat-table .mat-cell button.mat-icon-button mat-icon {\n'+
'color: ' + mdDarkSecondary + ';\n'+ 'color: ' + mdDarkSecondary + ';\n'+
'}\n'+ '}\n'+
'.mat-table .mat-cell button.mat-icon-button[disabled][disabled] mat-icon {\n'+
'color: ' + mdDarkDisabled + ';\n'+
'}\n'+
'.mat-divider {\n'+ '.mat-divider {\n'+
'border-top-color: ' + mdDarkDivider + ';\n'+ 'border-top-color: ' + mdDarkDivider + ';\n'+
'}\n'+ '}\n'+

25
ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts

@ -14,7 +14,7 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable, Type } from '@angular/core';
import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service'; import { DynamicComponentFactoryService } from '@core/services/dynamic-component-factory.service';
import { WidgetService } from '@core/http/widget.service'; import { WidgetService } from '@core/http/widget.service';
import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'; import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs';
@ -34,7 +34,6 @@ import { catchError, map, mergeMap, switchMap } from 'rxjs/operators';
import { isFunction, isUndefined } from '@core/utils'; import { isFunction, isUndefined } from '@core/utils';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DynamicWidgetComponent } from '@home/components/widget/dynamic-widget.component'; import { DynamicWidgetComponent } from '@home/components/widget/dynamic-widget.component';
import { SharedModule } from '@shared/shared.module';
import { WidgetComponentsModule } from '@home/components/widget/widget-components.module'; import { WidgetComponentsModule } from '@home/components/widget/widget-components.module';
import { WINDOW } from '@core/services/window.service'; import { WINDOW } from '@core/services/window.service';
@ -43,6 +42,7 @@ import { TbFlot } from './lib/flot-widget';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { WidgetTypeId } from '@app/shared/models/id/widget-type-id'; import { WidgetTypeId } from '@app/shared/models/id/widget-type-id';
import { TenantId } from '@app/shared/models/id/tenant-id'; import { TenantId } from '@app/shared/models/id/tenant-id';
import { SharedModule } from '@shared/shared.module';
const tinycolor = tinycolor_; const tinycolor = tinycolor_;
@ -117,16 +117,23 @@ export class WidgetComponentService {
const initSubject = new ReplaySubject(); const initSubject = new ReplaySubject();
this.init$ = initSubject.asObservable(); this.init$ = initSubject.asObservable();
const loadDefaultWidgetInfoTasks = [ const loadDefaultWidgetInfoTasks = [
this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type'), this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type', [SharedModule]),
this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type'), this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type', [SharedModule]),
]; ];
forkJoin(loadDefaultWidgetInfoTasks).subscribe( forkJoin(loadDefaultWidgetInfoTasks).subscribe(
() => { () => {
initSubject.next(); initSubject.next();
}, },
() => { (e) => {
let errorMessages = ['Failed to load default widget types!'];
if (e && e.length) {
errorMessages = errorMessages.concat(e);
}
console.error('Failed to load default widget types!'); console.error('Failed to load default widget types!');
initSubject.error('Failed to load default widget types!'); initSubject.error({
widgetInfo: this.errorWidgetType,
errorMessages
});
} }
); );
return this.init$; return this.init$;
@ -194,7 +201,7 @@ export class WidgetComponentService {
} }
if (widgetControllerDescriptor) { if (widgetControllerDescriptor) {
const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`; const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`;
this.loadWidgetResources(widgetInfo, widgetNamespace).subscribe( this.loadWidgetResources(widgetInfo, widgetNamespace, [WidgetComponentsModule]).subscribe(
() => { () => {
if (widgetControllerDescriptor.settingsSchema) { if (widgetControllerDescriptor.settingsSchema) {
widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema; widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema;
@ -219,7 +226,7 @@ export class WidgetComponentService {
} }
} }
private loadWidgetResources(widgetInfo: WidgetInfo, widgetNamespace: string): Observable<any> { private loadWidgetResources(widgetInfo: WidgetInfo, widgetNamespace: string, modules?: Type<any>[]): Observable<any> {
this.cssParser.cssPreviewNamespace = widgetNamespace; this.cssParser.cssPreviewNamespace = widgetNamespace;
this.cssParser.createStyleElement(widgetNamespace, widgetInfo.templateCss); this.cssParser.createStyleElement(widgetNamespace, widgetInfo.templateCss);
const resourceTasks: Observable<string>[] = []; const resourceTasks: Observable<string>[] = [];
@ -236,7 +243,7 @@ export class WidgetComponentService {
this.dynamicComponentFactoryService.createDynamicComponentFactory( this.dynamicComponentFactoryService.createDynamicComponentFactory(
class DynamicWidgetComponentInstance extends DynamicWidgetComponent {}, class DynamicWidgetComponentInstance extends DynamicWidgetComponent {},
widgetInfo.templateHtml, widgetInfo.templateHtml,
[SharedModule, WidgetComponentsModule] modules
).pipe( ).pipe(
map((factory) => { map((factory) => {
widgetInfo.componentFactory = factory; widgetInfo.componentFactory = factory;

11
ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts

@ -17,25 +17,28 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module'; import { SharedModule } from '@app/shared/shared.module';
import { AlarmDetailsDialogComponent } from '@home/components/alarm/alarm-details-dialog.component';
import { LegendComponent } from '@home/components/widget/legend.component';
import { EntitiesTableWidgetComponent } from '@home/components/widget/lib/entities-table-widget.component'; import { EntitiesTableWidgetComponent } from '@home/components/widget/lib/entities-table-widget.component';
import { DisplayColumnsPanelComponent } from '@home/components/widget/lib/display-columns-panel.component'; import { DisplayColumnsPanelComponent } from '@home/components/widget/lib/display-columns-panel.component';
import { AlarmsTableWidgetComponent } from '@home/components/widget/lib/alarms-table-widget.component'; import { AlarmsTableWidgetComponent } from '@home/components/widget/lib/alarms-table-widget.component';
import { AlarmStatusFilterPanelComponent } from '@home/components/widget/lib/alarm-status-filter-panel.component';
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
@NgModule({ @NgModule({
entryComponents: [ entryComponents: [
DisplayColumnsPanelComponent DisplayColumnsPanelComponent,
AlarmStatusFilterPanelComponent
], ],
declarations: declarations:
[ [
DisplayColumnsPanelComponent, DisplayColumnsPanelComponent,
AlarmStatusFilterPanelComponent,
EntitiesTableWidgetComponent, EntitiesTableWidgetComponent,
AlarmsTableWidgetComponent AlarmsTableWidgetComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
SharedModule SharedModule,
SharedHomeComponentsModule
], ],
exports: [ exports: [
EntitiesTableWidgetComponent, EntitiesTableWidgetComponent,

16
ui-ngx/src/app/shared/models/page/page-link.ts

@ -16,7 +16,7 @@
import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { emptyPageData, PageData } from '@shared/models/page/page-data'; import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { getDescendantProp } from '@core/utils'; import { getDescendantProp, isObject } from '@core/utils';
export type PageLinkSearchFunction<T> = (entity: T, textSearch: string) => boolean; export type PageLinkSearchFunction<T> = (entity: T, textSearch: string) => boolean;
@ -28,10 +28,16 @@ const defaultPageLinkSearchFunction: PageLinkSearchFunction<any> =
const expected = ('' + textSearch).toLowerCase(); const expected = ('' + textSearch).toLowerCase();
for (const key of Object.keys(entity)) { for (const key of Object.keys(entity)) {
const val = entity[key]; const val = entity[key];
if (val !== null && val !== Object(val)) { if (val !== null) {
const actual = ('' + val).toLowerCase(); if (val !== Object(val)) {
if (actual.indexOf(expected) !== -1) { const actual = ('' + val).toLowerCase();
return true; if (actual.indexOf(expected) !== -1) {
return true;
}
} else if (isObject(val)) {
if (defaultPageLinkSearchFunction(val, textSearch)) {
return true;
}
} }
} }
} }

5
ui-ngx/src/styles.scss

@ -498,6 +498,11 @@ mat-label {
mat-icon { mat-icon {
color: rgba(0, 0, 0, .54); color: rgba(0, 0, 0, .54);
} }
&[disabled][disabled] {
mat-icon {
color: rgba(0, 0, 0, .26);
}
}
} }
} }

Loading…
Cancel
Save