diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts
index d9365a50cc..00d33cdde1 100644
--- a/ui-ngx/src/app/core/api/widget-api.models.ts
+++ b/ui-ngx/src/app/core/api/widget-api.models.ts
@@ -259,5 +259,7 @@ export interface IWidgetSubscription {
destroy(): void;
+ update(): void;
+
[key: string]: any;
}
diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts
index 5fce77ab5e..cdbd9d7763 100644
--- a/ui-ngx/src/app/modules/home/components/home-components.module.ts
+++ b/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 { AlarmTableHeaderComponent } from '@home/components/alarm/alarm-table-header.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 { AddAttributeDialogComponent } from './attribute/add-attribute-dialog.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 { TableColumnsAssignmentComponent } from './import-export/table-columns-assignment.component';
import { EventContentDialogComponent } from '@home/components/event/event-content-dialog.component';
+import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
@NgModule({
entryComponents: [
@@ -73,7 +73,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
EventTableHeaderComponent,
RelationDialogComponent,
AlarmTableHeaderComponent,
- AlarmDetailsDialogComponent,
AddAttributeDialogComponent,
EditAttributeValuePanelComponent,
AliasesEntitySelectPanelComponent,
@@ -104,7 +103,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
RelationFiltersComponent,
AlarmTableHeaderComponent,
AlarmTableComponent,
- AlarmDetailsDialogComponent,
AttributeTableComponent,
AddAttributeDialogComponent,
EditAttributeValuePanelComponent,
@@ -136,7 +134,8 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
],
imports: [
CommonModule,
- SharedModule
+ SharedModule,
+ SharedHomeComponentsModule
],
exports: [
EntitiesTableComponent,
@@ -149,7 +148,6 @@ import { EventContentDialogComponent } from '@home/components/event/event-conten
RelationTableComponent,
RelationFiltersComponent,
AlarmTableComponent,
- AlarmDetailsDialogComponent,
AttributeTableComponent,
AliasesEntitySelectComponent,
EntityAliasesDialogComponent,
diff --git a/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts b/ui-ngx/src/app/modules/home/components/shared-home-components.module.ts
new file mode 100644
index 0000000000..30616276c5
--- /dev/null
+++ b/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 { }
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.html
new file mode 100644
index 0000000000..7c3b4e95d7
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }}
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.scss
new file mode 100644
index 0000000000..0ead8c7992
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarm-status-filter-panel.component.ts
new file mode 100644
index 0000000000..a260c22b89
--- /dev/null
+++ b/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('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;
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
index 5ac66cbee0..7a143c80ac 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
+++ b/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 { DataSource } from '@angular/cdk/typings/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 { entityTypeTranslations } from '@shared/models/entity-type.models';
import { catchError, debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators';
@@ -77,6 +77,19 @@ import {
alarmStatusTranslations
} from '@shared/models/alarm.models';
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 {
alarmsTitle: string;
@@ -172,7 +185,10 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private utils: UtilsService,
public translate: TranslateService,
private domSanitizer: DomSanitizer,
- private datePipe: DatePipe) {
+ private datePipe: DatePipe,
+ private dialog: MatDialog,
+ private dialogService: DialogService,
+ private alarmService: AlarmService) {
super(store);
const sortOrder: SortOrder = sortOrderFromString(this.defaultSortOrder);
@@ -390,7 +406,36 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
}
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([
+ [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() {
@@ -538,35 +583,138 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if ($event) {
$event.stopPropagation();
}
- // TODO:
+ if (alarm && alarm.id && alarm.id.id !== NULL_UUID) {
+ this.dialog.open
+ (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) {
if ($event) {
$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) {
if ($event) {
$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[] = [];
+ 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) {
if ($event) {
$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) {
if ($event) {
$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[] = [];
+ 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 {
@@ -722,6 +870,13 @@ class AlarmsDatasource implements DataSource {
return this.selection.isSelected(alarm);
}
+ clearSelection() {
+ if (this.selection.hasValue()) {
+ this.selection.clear();
+ this.onSelectionModeChanged(false);
+ }
+ }
+
masterToggle() {
this.alarmsSubject.pipe(
tap((alarms) => {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts
index 1926bb72ba..db864fddff 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts
+++ b/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'+
'color: ' + mdDarkSecondary + ';\n'+
'}\n'+
+ '.mat-table .mat-cell button.mat-icon-button[disabled][disabled] mat-icon {\n'+
+ 'color: ' + mdDarkDisabled + ';\n'+
+ '}\n'+
'.mat-divider {\n'+
'border-top-color: ' + mdDarkDivider + ';\n'+
'}\n'+
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
index 75317f1108..363595badf 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
@@ -14,7 +14,7 @@
/// 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 { WidgetService } from '@core/http/widget.service';
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 { TranslateService } from '@ngx-translate/core';
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 { 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 { WidgetTypeId } from '@app/shared/models/id/widget-type-id';
import { TenantId } from '@app/shared/models/id/tenant-id';
+import { SharedModule } from '@shared/shared.module';
const tinycolor = tinycolor_;
@@ -117,16 +117,23 @@ export class WidgetComponentService {
const initSubject = new ReplaySubject();
this.init$ = initSubject.asObservable();
const loadDefaultWidgetInfoTasks = [
- this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type'),
- this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type'),
+ this.loadWidgetResources(this.missingWidgetType, 'global-widget-missing-type', [SharedModule]),
+ this.loadWidgetResources(this.errorWidgetType, 'global-widget-error-type', [SharedModule]),
];
forkJoin(loadDefaultWidgetInfoTasks).subscribe(
() => {
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!');
- initSubject.error('Failed to load default widget types!');
+ initSubject.error({
+ widgetInfo: this.errorWidgetType,
+ errorMessages
+ });
}
);
return this.init$;
@@ -194,7 +201,7 @@ export class WidgetComponentService {
}
if (widgetControllerDescriptor) {
const widgetNamespace = `widget-type-${(isSystem ? 'sys-' : '')}${bundleAlias}-${widgetInfo.alias}`;
- this.loadWidgetResources(widgetInfo, widgetNamespace).subscribe(
+ this.loadWidgetResources(widgetInfo, widgetNamespace, [WidgetComponentsModule]).subscribe(
() => {
if (widgetControllerDescriptor.settingsSchema) {
widgetInfo.typeSettingsSchema = widgetControllerDescriptor.settingsSchema;
@@ -219,7 +226,7 @@ export class WidgetComponentService {
}
}
- private loadWidgetResources(widgetInfo: WidgetInfo, widgetNamespace: string): Observable {
+ private loadWidgetResources(widgetInfo: WidgetInfo, widgetNamespace: string, modules?: Type[]): Observable {
this.cssParser.cssPreviewNamespace = widgetNamespace;
this.cssParser.createStyleElement(widgetNamespace, widgetInfo.templateCss);
const resourceTasks: Observable[] = [];
@@ -236,7 +243,7 @@ export class WidgetComponentService {
this.dynamicComponentFactoryService.createDynamicComponentFactory(
class DynamicWidgetComponentInstance extends DynamicWidgetComponent {},
widgetInfo.templateHtml,
- [SharedModule, WidgetComponentsModule]
+ modules
).pipe(
map((factory) => {
widgetInfo.componentFactory = factory;
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
index b965add9f2..b006b317a6 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-components.module.ts
@@ -17,25 +17,28 @@
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';
-import { LegendComponent } from '@home/components/widget/legend.component';
import { EntitiesTableWidgetComponent } from '@home/components/widget/lib/entities-table-widget.component';
import { DisplayColumnsPanelComponent } from '@home/components/widget/lib/display-columns-panel.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({
entryComponents: [
- DisplayColumnsPanelComponent
+ DisplayColumnsPanelComponent,
+ AlarmStatusFilterPanelComponent
],
declarations:
[
DisplayColumnsPanelComponent,
+ AlarmStatusFilterPanelComponent,
EntitiesTableWidgetComponent,
AlarmsTableWidgetComponent
],
imports: [
CommonModule,
- SharedModule
+ SharedModule,
+ SharedHomeComponentsModule
],
exports: [
EntitiesTableWidgetComponent,
diff --git a/ui-ngx/src/app/shared/models/page/page-link.ts b/ui-ngx/src/app/shared/models/page/page-link.ts
index 8317cc325b..8cd5c7fe56 100644
--- a/ui-ngx/src/app/shared/models/page/page-link.ts
+++ b/ui-ngx/src/app/shared/models/page/page-link.ts
@@ -16,7 +16,7 @@
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
-import { getDescendantProp } from '@core/utils';
+import { getDescendantProp, isObject } from '@core/utils';
export type PageLinkSearchFunction = (entity: T, textSearch: string) => boolean;
@@ -28,10 +28,16 @@ const defaultPageLinkSearchFunction: PageLinkSearchFunction =
const expected = ('' + textSearch).toLowerCase();
for (const key of Object.keys(entity)) {
const val = entity[key];
- if (val !== null && val !== Object(val)) {
- const actual = ('' + val).toLowerCase();
- if (actual.indexOf(expected) !== -1) {
- return true;
+ if (val !== null) {
+ if (val !== Object(val)) {
+ const actual = ('' + val).toLowerCase();
+ if (actual.indexOf(expected) !== -1) {
+ return true;
+ }
+ } else if (isObject(val)) {
+ if (defaultPageLinkSearchFunction(val, textSearch)) {
+ return true;
+ }
}
}
}
diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss
index a9f69e6e62..0e490633e6 100644
--- a/ui-ngx/src/styles.scss
+++ b/ui-ngx/src/styles.scss
@@ -498,6 +498,11 @@ mat-label {
mat-icon {
color: rgba(0, 0, 0, .54);
}
+ &[disabled][disabled] {
+ mat-icon {
+ color: rgba(0, 0, 0, .26);
+ }
+ }
}
}