Browse Source

UI: rewrite component search inputs form ngModel to FormControl; Add textSearch pageLink parameters trim value

pull/9021/head
Vladyslav_Prykhodko 3 years ago
parent
commit
12b232132f
  1. 2
      ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html
  2. 57
      ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts
  3. 2
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.html
  4. 105
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts
  5. 2
      ui-ngx/src/app/modules/home/components/relation/relation-table.component.html
  6. 56
      ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts
  7. 2
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html
  8. 50
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html
  10. 49
      ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts
  11. 2
      ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html
  12. 70
      ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts
  13. 2
      ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html
  14. 55
      ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts
  15. 2
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html
  16. 66
      ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts
  17. 2
      ui-ngx/src/app/modules/home/home.component.html
  18. 49
      ui-ngx/src/app/modules/home/home.component.ts
  19. 8
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html
  20. 39
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts
  21. 5
      ui-ngx/src/app/shared/models/page/page-link.ts

2
ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html

@ -68,7 +68,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ 'common.enter-search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

57
ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts

@ -23,6 +23,7 @@ import {
Injector,
Input,
NgZone,
OnDestroy,
OnInit,
StaticProvider,
ViewChild,
@ -38,8 +39,8 @@ import { TranslateService } from '@ngx-translate/core';
import { MatDialog } from '@angular/material/dialog';
import { DialogService } from '@core/services/dialog.service';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { fromEvent, merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import { merge, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, skip, startWith, takeUntil } from 'rxjs/operators';
import { EntityId } from '@shared/models/id/entity-id';
import {
AttributeData,
@ -92,6 +93,7 @@ import {
DeleteTimeseriesPanelComponent,
DeleteTimeseriesPanelData
} from '@home/components/attribute/delete-timeseries-panel.component';
import { FormBuilder } from '@angular/forms';
@Component({
@ -100,7 +102,7 @@ import {
styleUrls: ['./attribute-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AttributeTableComponent extends PageComponent implements AfterViewInit, OnInit {
export class AttributeTableComponent extends PageComponent implements AfterViewInit, OnInit, OnDestroy {
telemetryTypeTranslationsMap = telemetryTypeTranslations;
isClientSideTelemetryTypeMap = isClientSideTelemetryType;
@ -185,6 +187,10 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
textSearch = this.fb.control('', {nonNullable: true});
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
private attributeService: AttributeService,
private telemetryWsService: TelemetryWebsocketService,
@ -199,7 +205,8 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
private widgetService: WidgetService,
private zone: NgZone,
private cd: ChangeDetectorRef,
private elementRef: ElementRef) {
private elementRef: ElementRef,
private fb: FormBuilder) {
super(store);
this.dirtyValue = !this.activeValue;
const sortOrder: SortOrder = { property: 'key', direction: Direction.ASC };
@ -222,6 +229,8 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
if (this.widgetResize$) {
this.widgetResize$.disconnect();
}
this.destroy$.next();
this.destroy$.complete();
}
attributeScopeChanged(attributeScope: TelemetryType) {
@ -232,25 +241,23 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
}
ngAfterViewInit() {
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
this.paginator.pageIndex = 0;
this.pageLink.textSearch = value.trim();
this.updateData();
});
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.paginator.pageIndex = 0;
this.updateData();
})
)
.subscribe();
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
tap(() => this.updateData())
)
.subscribe();
this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page).pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateData());
this.viewsInited = true;
if (this.activeValue && this.entityIdValue) {
@ -268,7 +275,6 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
setTimeout(() => {
this.searchInputField.nativeElement.focus();
this.searchInputField.nativeElement.setSelectionRange(0, 0);
@ -277,9 +283,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
this.updateData();
this.textSearch.reset();
}
resetSortAndFilter(update: boolean = true) {
@ -293,6 +297,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI
}
this.mode = 'default';
this.textSearchMode = false;
this.textSearch.reset('', {emitEvent: false});
this.selectedWidgetsBundleAlias = null;
this.attributeScope = this.defaultAttributeScope;
this.pageLink.textSearch = null;

2
ui-ngx/src/app/modules/home/components/entity/entities-table.component.html

@ -111,7 +111,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ translations.search | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

105
ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts

@ -24,6 +24,7 @@ import {
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
ViewChild
@ -36,9 +37,9 @@ import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, SortDirection } from '@angular/material/sort';
import { EntitiesDataSource } from '@home/models/datasource/entity-datasource';
import { catchError, debounceTime, distinctUntilChanged, map, skip, tap } from 'rxjs/operators';
import { catchError, debounceTime, distinctUntilChanged, map, skip, startWith, takeUntil } from 'rxjs/operators';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { forkJoin, fromEvent, merge, Observable, of, Subscription } from 'rxjs';
import { forkJoin, merge, Observable, of, Subject, Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { BaseData, HasId } from '@shared/models/base-data';
import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router';
@ -59,12 +60,13 @@ import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-co
import { calculateIntervalStartEndTime, HistoryWindowType, Timewindow } from '@shared/models/time/time.models';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { TbAnchorComponent } from '@shared/components/tb-anchor.component';
import { isDefined, isEmptyStr, isEqual, isString, isUndefined } from '@core/utils';
import { isDefined, isEmptyStr, isEqual, isNotEmptyStr, isUndefined } from '@core/utils';
import { HasUUID } from '@shared/models/id/has-uuid';
import { ResizeObserver } from '@juggle/resize-observer';
import { hidePageSizePixelValue } from '@shared/models/constants';
import { EntitiesTableAction, IEntitiesTableComponent } from '@home/models/entity/entity-table-component.models';
import { EntityDetailsPanelComponent } from '@home/components/entity/entity-details-panel.component';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'tb-entities-table',
@ -72,7 +74,7 @@ import { EntityDetailsPanelComponent } from '@home/components/entity/entity-deta
styleUrls: ['./entities-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges {
export class EntitiesTableComponent extends PageComponent implements IEntitiesTableComponent, AfterViewInit, OnInit, OnChanges, OnDestroy {
@Input()
entitiesTableConfig: EntityTableConfig<BaseData<HasId>>;
@ -121,12 +123,13 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
@ViewChild('entityDetailsPanel') entityDetailsPanel: EntityDetailsPanelComponent;
textSearch = this.fb.control('', {nonNullable: true});
private updateDataSubscription: Subscription;
private viewInited = false;
private widgetResize$: ResizeObserver;
private rxSubscriptions = new Array<Subscription>();
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
public route: ActivatedRoute,
@ -137,7 +140,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
private cd: ChangeDetectorRef,
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver,
private elementRef: ElementRef) {
private elementRef: ElementRef,
private fb: FormBuilder) {
super(store);
}
@ -145,11 +149,11 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
if (this.entitiesTableConfig) {
this.init(this.entitiesTableConfig);
} else {
this.rxSubscriptions.push(this.route.data.subscribe(
(data) => {
this.route.data.pipe(
takeUntil(this.destroy$)
).subscribe((data) => {
this.init(data.entitiesTableConfig);
}
));
});
}
this.widgetResize$ = new ResizeObserver(() => {
const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue;
@ -165,10 +169,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
if (this.widgetResize$) {
this.widgetResize$.disconnect();
}
this.rxSubscriptions.forEach((subscription) => {
subscription.unsubscribe();
});
this.rxSubscriptions.length = 0;
this.destroy$.next();
this.destroy$.complete();
}
ngOnChanges(changes: SimpleChanges): void {
@ -268,9 +270,12 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
if (routerQueryParams.hasOwnProperty('pageSize')) {
this.pageLink.pageSize = Number(routerQueryParams.pageSize);
}
if (routerQueryParams.hasOwnProperty('textSearch') && !isEmptyStr(routerQueryParams.textSearch)) {
const textSearchParam = routerQueryParams.textSearch;
if (textSearchParam && !isEmptyStr(textSearchParam)) {
const decodedTextSearch = decodeURI(routerQueryParams.textSearch);
this.textSearchMode = true;
this.pageLink.textSearch = decodeURI(routerQueryParams.textSearch);
this.textSearch.setValue(decodedTextSearch, { emitEvent: false });
this.pageLink.textSearch = decodedTextSearch.trim();
}
}
this.dataSource = this.entitiesTableConfig.dataSource(this.dataLoaded.bind(this));
@ -305,37 +310,39 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
ngAfterViewInit() {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
const queryParams: PageQueryParam = {
textSearch: isString(this.pageLink.textSearch) && this.pageLink.textSearch !== '' ? encodeURI(this.pageLink.textSearch) : null
};
if (this.displayPagination) {
this.paginator.pageIndex = 0;
queryParams.page = null;
}
this.updatedRouterParamsAndData(queryParams);
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe(value => {
const queryParams: PageQueryParam = {};
if (isNotEmptyStr(value)) {
queryParams.textSearch = encodeURI(value);
this.pageLink.textSearch = value.trim();
} else {
queryParams.textSearch = null;
this.pageLink.textSearch = null;
}
if (this.displayPagination) {
this.paginator.pageIndex = 0;
queryParams.page = null;
}
this.updatedRouterParamsAndData(queryParams);
});
if (this.pageMode) {
this.route.queryParams.pipe(skip(1)).subscribe((params: PageQueryParam) => {
this.route.queryParams.pipe(
skip(1),
takeUntil(this.destroy$)
).subscribe((params: PageQueryParam) => {
if (this.displayPagination) {
this.paginator.pageIndex = Number(params.page) || 0;
this.paginator.pageSize = Number(params.pageSize) || this.defaultPageSize;
}
this.sort.active = params.property || this.entitiesTableConfig.defaultSortOrder.property;
this.sort.direction = (params.direction || this.entitiesTableConfig.defaultSortOrder.direction).toLowerCase() as SortDirection;
if (params.hasOwnProperty('textSearch') && !isEmptyStr(params.textSearch)) {
this.textSearchMode = true;
this.pageLink.textSearch = decodeURI(params.textSearch);
} else {
this.pageLink.textSearch = null;
}
this.updateData();
});
}
@ -376,10 +383,8 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
}
this.updateDataSubscription = ((this.displayPagination ? merge(sortSubscription$, paginatorSubscription$)
: sortSubscription$) as Observable<PageQueryParam>).pipe(
tap((queryParams) => {
this.updatedRouterParamsAndData(queryParams);
})
).subscribe();
takeUntil(this.destroy$)
).subscribe(queryParams => this.updatedRouterParamsAndData(queryParams));
}
addEnabled() {
@ -572,7 +577,6 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
setTimeout(() => {
this.searchInputField.nativeElement.focus();
this.searchInputField.nativeElement.setSelectionRange(0, 0);
@ -581,19 +585,12 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
const queryParams: PageQueryParam = {
textSearch: null
};
if (this.displayPagination) {
this.paginator.pageIndex = 0;
queryParams.page = null;
}
this.updatedRouterParamsAndData(queryParams);
this.textSearch.reset();
}
resetSortAndFilter(update: boolean = true, preserveTimewindow: boolean = false) {
this.textSearchMode = false;
this.textSearch.reset('', {emitEvent: false});
this.pageLink.textSearch = null;
if (this.entitiesTableConfig.useTimePageLink && !preserveTimewindow) {
this.timewindow = this.entitiesTableConfig.defaultTimewindowInterval;

2
ui-ngx/src/app/modules/home/components/relation/relation-table.component.html

@ -62,7 +62,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ 'common.enter-search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

56
ui-ngx/src/app/modules/home/components/relation/relation-table.component.ts

@ -21,6 +21,7 @@ import {
Component,
ElementRef,
Input,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
@ -35,8 +36,8 @@ import { MatDialog } from '@angular/material/dialog';
import { DialogService } from '@core/services/dialog.service';
import { EntityRelationService } from '@core/http/entity-relation.service';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { forkJoin, fromEvent, merge, Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import { forkJoin, merge, Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, skip, startWith, takeUntil } from 'rxjs/operators';
import {
EntityRelation,
EntityRelationInfo,
@ -49,6 +50,7 @@ import { RelationsDatasource } from '../../models/datasource/relation-datasource
import { RelationDialogComponent, RelationDialogData } from '@home/components/relation/relation-dialog.component';
import { hidePageSizePixelValue } from '@shared/models/constants';
import { ResizeObserver } from '@juggle/resize-observer';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'tb-relation-table',
@ -56,7 +58,7 @@ import { ResizeObserver } from '@juggle/resize-observer';
styleUrls: ['./relation-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RelationTableComponent extends PageComponent implements AfterViewInit, OnInit {
export class RelationTableComponent extends PageComponent implements AfterViewInit, OnInit, OnDestroy {
directions = EntitySearchDirection;
@ -77,8 +79,6 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
viewsInited = false;
private widgetResize$: ResizeObserver;
@Input()
set active(active: boolean) {
if (this.activeValue !== active) {
@ -110,13 +110,19 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
textSearch = this.fb.control('', {nonNullable: true});
private widgetResize$: ResizeObserver;
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
private entityRelationService: EntityRelationService,
public translate: TranslateService,
public dialog: MatDialog,
private dialogService: DialogService,
private cd: ChangeDetectorRef,
private elementRef: ElementRef) {
private elementRef: ElementRef,
private fb: FormBuilder) {
super(store);
this.dirtyValue = !this.activeValue;
const sortOrder: SortOrder = { property: 'type', direction: Direction.ASC };
@ -141,6 +147,8 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
if (this.widgetResize$) {
this.widgetResize$.disconnect();
}
this.destroy$.next();
this.destroy$.complete();
}
updateColumns() {
@ -159,25 +167,23 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
}
ngAfterViewInit() {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.paginator.pageIndex = 0;
this.updateData();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
this.paginator.pageIndex = 0;
this.pageLink.textSearch = value.trim();
this.updateData();
});
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
tap(() => this.updateData())
)
.subscribe();
merge(this.sort.sortChange, this.paginator.page).pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateData());
this.viewsInited = true;
if (this.activeValue && this.entityIdValue) {
@ -195,7 +201,6 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
setTimeout(() => {
this.searchInputField.nativeElement.focus();
this.searchInputField.nativeElement.setSelectionRange(0, 0);
@ -204,14 +209,13 @@ export class RelationTableComponent extends PageComponent implements AfterViewIn
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
this.updateData();
this.textSearch.reset();
}
resetSortAndFilter(update: boolean = true) {
this.direction = EntitySearchDirection.FROM;
this.updateColumns();
this.textSearch.reset('', {emitEvent: false});
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
const sortable = this.sort.sortables.get('type');

2
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html

@ -74,7 +74,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ 'version-control.search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

50
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts

@ -33,10 +33,10 @@ import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { EntityId, entityIdEquals } from '@shared/models/id/entity-id';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { BehaviorSubject, fromEvent, merge, Observable, of, ReplaySubject } from 'rxjs';
import { BehaviorSubject, merge, Observable, of, ReplaySubject, Subject } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { PageLink } from '@shared/models/page/page-link';
import { catchError, debounceTime, distinctUntilChanged, map, tap } from 'rxjs/operators';
import { catchError, debounceTime, distinctUntilChanged, map, skip, startWith, takeUntil } from 'rxjs/operators';
import { EntityVersion, VersionCreationResult, VersionLoadResult } from '@shared/models/vc.models';
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
import { MatPaginator } from '@angular/material/paginator';
@ -54,7 +54,8 @@ import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-d
import { ComplexVersionCreateComponent } from '@home/components/vc/complex-version-create.component';
import { ComplexVersionLoadComponent } from '@home/components/vc/complex-version-load.component';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { AdminService } from "@core/http/admin.service";
import { AdminService } from '@core/http/admin.service';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'tb-entity-versions-table',
@ -90,7 +91,10 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
isReadOnly: Observable<boolean>;
textSearch = this.fb.control('', {nonNullable: true});
private componentResize$: ResizeObserver;
private destroy$ = new Subject<void>();
@Input()
set active(active: boolean) {
@ -137,7 +141,8 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
private renderer: Renderer2,
private cd: ChangeDetectorRef,
private viewContainerRef: ViewContainerRef,
private elementRef: ElementRef) {
private elementRef: ElementRef,
private fb: FormBuilder) {
super(store);
this.dirtyValue = !this.activeValue;
const sortOrder: SortOrder = { property: 'timestamp', direction: Direction.DESC };
@ -161,6 +166,8 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
if (this.componentResize$) {
this.componentResize$.disconnect();
}
this.destroy$.next();
this.destroy$.complete();
}
branchChanged(newBranch: string) {
@ -174,23 +181,22 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
}
ngAfterViewInit() {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(400),
distinctUntilChanged(),
tap(() => {
this.paginator.pageIndex = 0;
this.updateData();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(400),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
this.paginator.pageIndex = 0;
this.pageLink.textSearch = value.trim();
this.updateData();
});
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
merge(this.sort.sortChange, this.paginator.page)
.pipe(
tap(() => this.updateData())
)
.subscribe();
merge(this.sort.sortChange, this.paginator.page).pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateData());
this.viewsInited = true;
if (!this.singleEntityMode || (this.activeValue && this.externalEntityIdValue)) {
this.initFromDefaultBranch();
@ -341,7 +347,6 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
setTimeout(() => {
this.searchInputField.nativeElement.focus();
this.searchInputField.nativeElement.setSelectionRange(0, 0);
@ -350,9 +355,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
this.paginator.pageIndex = 0;
this.updateData();
this.textSearch.reset();
}
private initFromDefaultBranch() {
@ -376,6 +379,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
private resetSortAndFilter(update: boolean) {
this.textSearchMode = false;
this.textSearch.reset('', {emitEvent: false});
this.pageLink.textSearch = null;
if (this.viewsInited) {
this.paginator.pageIndex = 0;

2
ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html

@ -27,7 +27,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ 'alarm.search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

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

@ -42,9 +42,9 @@ import cssjs from '@core/css/css';
import { sortItems } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections';
import { BehaviorSubject, forkJoin, fromEvent, merge, Observable, Subscription } from 'rxjs';
import { BehaviorSubject, forkJoin, merge, Observable, Subject, Subscription } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, skip, startWith, take, takeUntil, tap } from 'rxjs/operators';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, SortDirection } from '@angular/material/sort';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@ -122,6 +122,7 @@ import {
AlarmFilterConfigData
} from '@home/components/alarm/alarm-filter-config.component';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { FormBuilder } from '@angular/forms';
interface AlarmsTableWidgetSettings extends TableWidgetSettings {
alarmsTitle: string;
@ -159,6 +160,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
textSearch = this.fb.control('', {nonNullable: true});
public enableSelection = true;
public displayPagination = true;
public enableStickyHeader = true;
@ -184,6 +187,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
private widgetResize$: ResizeObserver;
private destroy$ = new Subject<void>();
private displayActivity = false;
private displayDetails = true;
@ -244,7 +248,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private dialogService: DialogService,
private entityService: EntityService,
private alarmService: AlarmService,
private cd: ChangeDetectorRef) {
private cd: ChangeDetectorRef,
private fb: FormBuilder) {
super(store);
this.pageLink = {
page: 0,
@ -285,28 +290,29 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if (this.widgetResize$) {
this.widgetResize$.disconnect();
}
this.destroy$.next();
this.destroy$.complete();
}
ngAfterViewInit(): void {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.resetPageIndex();
this.updateData();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
this.resetPageIndex();
this.pageLink.textSearch = value.trim();
this.updateData();
});
if (this.displayPagination) {
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.paginator.pageIndex = 0);
}
((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable<any>)
.pipe(
tap(() => this.updateData())
)
.subscribe();
((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable<any>).pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateData());
this.updateData();
}
@ -627,7 +633,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
this.ctx.hideTitlePanel = true;
this.ctx.detectChanges(true);
setTimeout(() => {
@ -638,9 +643,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
this.resetPageIndex();
this.updateData();
this.textSearch.reset();
this.ctx.hideTitlePanel = false;
this.ctx.detectChanges(true);
}

2
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html

@ -27,7 +27,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="textSearch"
[formControl]="textSearch"
placeholder="{{ 'entity.search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

70
ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts

@ -14,7 +14,16 @@
/// limitations under the License.
///
import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import {
AfterViewInit,
Component,
ElementRef,
Input,
OnDestroy,
OnInit,
ViewChild,
ViewContainerRef
} from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@ -23,8 +32,7 @@ import { DatasourceData, DatasourceType, WidgetConfig, widgetType } from '@share
import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
import { UtilsService } from '@core/services/utils.service';
import cssjs from '@core/css/css';
import { fromEvent } from 'rxjs';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, skip, startWith, takeUntil } from 'rxjs/operators';
import { constructTableCssString } from '@home/components/widget/lib/table-widget.models';
import { Overlay } from '@angular/cdk/overlay';
import {
@ -36,7 +44,7 @@ import {
NodesInsertedCallback
} from '@shared/components/nav-tree.component';
import { EntityType } from '@shared/models/entity-type.models';
import { deepClone, hashCode } from '@core/utils';
import { deepClone, hashCode, isDefinedAndNotNull, isEmptyStr } from '@core/utils';
import {
defaultNodeIconFunction,
defaultNodeOpenedFunction,
@ -60,13 +68,15 @@ import {
import { EntityRelationsQuery } from '@shared/models/relation.models';
import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models';
import { EntityFilter } from '@shared/models/query/query.models';
import { FormBuilder } from '@angular/forms';
import { Subject } from 'rxjs';
@Component({
selector: 'tb-entities-hierarchy-widget',
templateUrl: './entities-hierarchy-widget.component.html',
styleUrls: ['./entities-hierarchy-widget.component.scss']
})
export class EntitiesHierarchyWidgetComponent extends PageComponent implements OnInit, AfterViewInit {
export class EntitiesHierarchyWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {
@Input()
ctx: WidgetContext;
@ -75,8 +85,8 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
public toastTargetId = 'entities-hierarchy-' + this.utils.guid();
public textSearchMode = false;
public textSearch = null;
textSearchMode = false;
textSearch = this.fb.control('', {nonNullable: true});
public nodeEditCallbacks: NavTreeEditCallbacks = {};
@ -106,11 +116,14 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
}
};
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
private elementRef: ElementRef,
private overlay: Overlay,
private viewContainerRef: ViewContainerRef,
private utils: UtilsService) {
private utils: UtilsService,
private fb: FormBuilder) {
super(store);
}
@ -125,15 +138,25 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
}
ngAfterViewInit(): void {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.updateSearchNodes();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
if (isDefinedAndNotNull(value) && !isEmptyStr(value)) {
this.nodeEditCallbacks.search(value.trim());
} else {
this.nodeEditCallbacks.clearSearch();
}
});
}
ngOnDestroy() {
super.ngOnDestroy();
this.destroy$.next();
this.destroy$.complete();
}
public onDataUpdated() {
@ -190,7 +213,6 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
private enterFilterMode() {
this.textSearchMode = true;
this.textSearch = '';
this.ctx.hideTitlePanel = true;
this.ctx.detectChanges(true);
setTimeout(() => {
@ -201,20 +223,12 @@ export class EntitiesHierarchyWidgetComponent extends PageComponent implements O
exitFilterMode() {
this.textSearchMode = false;
this.textSearch = null;
this.updateSearchNodes();
this.textSearch.reset();
this.nodeEditCallbacks.clearSearch();
this.ctx.hideTitlePanel = false;
this.ctx.detectChanges(true);
}
private updateSearchNodes() {
if (this.textSearch != null) {
this.nodeEditCallbacks.search(this.textSearch);
} else {
this.nodeEditCallbacks.clearSearch();
}
}
private updateNodeData(subscriptionData: Array<DatasourceData>) {
const affectedNodes: string[] = [];
if (subscriptionData) {

2
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html

@ -27,7 +27,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="pageLink.textSearch"
[formControl]="textSearch"
placeholder="{{ 'entity.search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

55
ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts

@ -46,11 +46,11 @@ import { deepClone, hashCode, isDefined, isNumber, isObject, isUndefined } from
import cssjs from '@core/css/css';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { BehaviorSubject, fromEvent, merge, Observable } from 'rxjs';
import { BehaviorSubject, merge, Observable, Subject } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { EntityId } from '@shared/models/id/entity-id';
import { entityTypeTranslations } from '@shared/models/entity-type.models';
import { debounceTime, distinctUntilChanged, map, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, map, skip, startWith, takeUntil } from 'rxjs/operators';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, SortDirection } from '@angular/material/sort';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@ -105,6 +105,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ResizeObserver } from '@juggle/resize-observer';
import { hidePageSizePixelValue } from '@shared/models/constants';
import { AggregationType } from '@shared/models/time/time.models';
import { FormBuilder } from '@angular/forms';
interface EntitiesTableWidgetSettings extends TableWidgetSettings {
entitiesTitle: string;
@ -131,6 +132,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
textSearch = this.fb.control('', {nonNullable: true});
public displayPagination = true;
public enableStickyHeader = true;
public enableStickyAction = true;
@ -155,6 +158,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
private widgetResize$: ResizeObserver;
private destroy$ = new Subject<void>();
private defaultPageSize = 10;
private defaultSortOrder = 'entityName';
@ -194,7 +198,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
private datePipe: DatePipe,
private translate: TranslateService,
private domSanitizer: DomSanitizer,
private cd: ChangeDetectorRef) {
private cd: ChangeDetectorRef,
private fb: FormBuilder) {
super(store);
this.pageLink = {
page: 0,
@ -228,30 +233,31 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
if (this.widgetResize$) {
this.widgetResize$.disconnect();
}
this.destroy$.next();
this.destroy$.complete();
}
ngAfterViewInit(): void {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
if (this.displayPagination) {
this.paginator.pageIndex = 0;
}
this.updateData();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => {
if (this.displayPagination) {
this.paginator.pageIndex = 0;
}
this.pageLink.textSearch = value.trim();
this.updateData();
});
if (this.displayPagination) {
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe(() => this.paginator.pageIndex = 0);
}
((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable<any>)
.pipe(
tap(() => this.updateData())
)
.subscribe();
((this.displayPagination ? merge(this.sort.sortChange, this.paginator.page) : this.sort.sortChange) as Observable<any>).pipe(
takeUntil(this.destroy$)
).subscribe(() => this.updateData());
this.updateData();
}
@ -510,7 +516,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
private enterFilterMode() {
this.textSearchMode = true;
this.pageLink.textSearch = '';
this.ctx.hideTitlePanel = true;
this.ctx.detectChanges(true);
setTimeout(() => {
@ -521,11 +526,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni
exitFilterMode() {
this.textSearchMode = false;
this.pageLink.textSearch = null;
if (this.displayPagination) {
this.paginator.pageIndex = 0;
}
this.updateData();
this.textSearch.reset();
this.ctx.hideTitlePanel = false;
this.ctx.detectChanges(true);
}

2
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html

@ -27,7 +27,7 @@
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[(ngModel)]="textSearch"
[formControl]="textSearch"
placeholder="{{ 'widget.search-data' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"

66
ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts

@ -56,9 +56,9 @@ import cssjs from '@core/css/css';
import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order';
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { BehaviorSubject, fromEvent, merge, Observable, of, Subscription } from 'rxjs';
import { BehaviorSubject, merge, Observable, of, Subject, Subscription } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { catchError, debounceTime, distinctUntilChanged, map, tap } from 'rxjs/operators';
import { catchError, debounceTime, distinctUntilChanged, map, skip, startWith, takeUntil } from 'rxjs/operators';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@ -69,7 +69,9 @@ import {
constructTableCssString,
DisplayColumn,
getCellContentInfo,
getCellStyleInfo, getColumnDefaultVisibility, getColumnSelectionAvailability,
getCellStyleInfo,
getColumnDefaultVisibility,
getColumnSelectionAvailability,
getRowStyleInfo,
getTableCellButtonActions,
noDataMessage,
@ -90,6 +92,7 @@ import {
DisplayColumnsPanelComponent
} from '@home/components/widget/lib/display-columns-panel.component';
import { ComponentPortal } from '@angular/cdk/portal';
import { FormBuilder } from '@angular/forms';
export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
showTimestamp: boolean;
@ -151,6 +154,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
@ViewChildren(MatPaginator) paginators: QueryList<MatPaginator>;
@ViewChildren(MatSort) sorts: QueryList<MatSort>;
textSearch = this.fb.control('', {nonNullable: true});
public displayPagination = true;
public enableStickyHeader = true;
public enableStickyAction = true;
@ -158,7 +163,6 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
public pageSizeOptions;
public textSearchMode = false;
public hidePageSize = false;
public textSearch: string = null;
public sources: TimeseriesTableSource[];
public sourceIndex: number;
public noDataDisplayMessageText: string;
@ -189,6 +193,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private subscriptions: Subscription[] = [];
private widgetTimewindowChanged$: Subscription;
private widgetResize$: ResizeObserver;
private destroy$ = new Subject<void>();
private searchAction: WidgetAction = {
name: 'action.search',
@ -216,7 +221,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private translate: TranslateService,
private domSanitizer: DomSanitizer,
private datePipe: DatePipe,
private cd: ChangeDetectorRef) {
private cd: ChangeDetectorRef,
private fb: FormBuilder) {
super(store);
}
@ -262,24 +268,24 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
}
ngAfterViewInit(): void {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.sources.forEach((source) => {
source.pageLink.textSearch = this.textSearch;
if (this.displayPagination) {
source.pageLink.page = 0;
}
});
this.loadCurrentSourceRow();
this.ctx.detectChanges();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((textSearch) => {
this.sources.forEach((source) => {
source.pageLink.textSearch = textSearch.trim();
if (this.displayPagination) {
source.pageLink.page = 0;
}
});
this.loadCurrentSourceRow();
this.ctx.detectChanges();
});
this.sorts.changes.subscribe(() => {
this.sorts.changes.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.initSubscriptionsToSortAndPaginator();
});
@ -559,9 +565,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
observables.push(paginator.page);
}
this.updateData(sort, paginator);
this.subscriptions.push(merge(...observables).pipe(
tap(() => this.updateData(sort, paginator))
).subscribe());
this.subscriptions.push(merge(...observables).subscribe(() => this.updateData(sort, paginator)));
});
}
@ -573,10 +577,6 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
private enterFilterMode() {
this.textSearchMode = true;
this.textSearch = '';
this.sources.forEach((source) => {
source.pageLink.textSearch = this.textSearch;
});
this.ctx.hideTitlePanel = true;
this.ctx.detectChanges(true);
setTimeout(() => {
@ -587,13 +587,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
exitFilterMode() {
this.textSearchMode = false;
this.textSearch = null;
this.sources.forEach((source) => {
source.pageLink.textSearch = this.textSearch;
if (this.displayPagination) {
source.pageLink.page = 0;
}
});
this.textSearch.reset();
this.loadCurrentSourceRow();
this.ctx.hideTitlePanel = false;
this.ctx.detectChanges(true);

2
ui-ngx/src/app/modules/home/home.component.html

@ -57,7 +57,7 @@
<div [fxShow]="displaySearchMode()" fxFlex fxLayout="row" class="tb-dark">
<mat-form-field fxFlex class="tb-appearance-transparent">
<input #searchInput matInput
[(ngModel)]="searchText"
[formControl]="textSearch"
placeholder="{{ 'common.enter-search' | translate }}"/>
</mat-form-field>
</div>

49
ui-ngx/src/app/modules/home/home.component.ts

@ -14,10 +14,10 @@
/// limitations under the License.
///
import { AfterViewInit, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core';
import { fromEvent } from 'rxjs';
import { AfterViewInit, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { startWith, skip, Subject } from 'rxjs';
import { Store } from '@ngrx/store';
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { PageComponent } from '@shared/components/page.component';
@ -31,13 +31,14 @@ import { WINDOW } from '@core/services/window.service';
import { instanceOfSearchableComponent, ISearchableComponent } from '@home/models/searchable-component.models';
import { ActiveComponentService } from '@core/services/active-component.service';
import { RouterTabsComponent } from '@home/components/router-tabs.component';
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'tb-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent extends PageComponent implements AfterViewInit, OnInit {
export class HomeComponent extends PageComponent implements AfterViewInit, OnInit, OnDestroy {
authState: AuthState = getCurrentAuthState(this.store);
@ -60,14 +61,17 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
searchEnabled = false;
showSearch = false;
searchText = '';
textSearch = this.fb.control('', {nonNullable: true});
hideLoadingBar = false;
private destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
@Inject(WINDOW) private window: Window,
private activeComponentService: ActiveComponentService,
public breakpointObserver: BreakpointObserver) {
public breakpointObserver: BreakpointObserver,
private fb: FormBuilder) {
super(store);
}
@ -79,6 +83,7 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
this.breakpointObserver
.observe(MediaBreakpoints['gt-sm'])
.pipe(takeUntil(this.destroy$))
.subscribe((state: BreakpointState) => {
if (state.matches) {
this.sidenavMode = 'side';
@ -91,16 +96,19 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
ngAfterViewInit() {
fromEvent(this.searchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.searchTextUpdated();
})
)
.subscribe();
this.textSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe((value) => this.searchTextUpdated(value));
}
sidenavClicked() {
@ -136,7 +144,7 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
private updateActiveComponent(activeComponent: any) {
this.showSearch = false;
this.searchText = '';
this.textSearch.reset('', {emitEvent: false});
this.activeComponent = activeComponent;
this.hideLoadingBar = activeComponent && activeComponent instanceof RouterTabsComponent;
if (this.activeComponent && instanceOfSearchableComponent(this.activeComponent)) {
@ -165,16 +173,15 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni
closeSearch() {
if (this.searchEnabled) {
this.showSearch = false;
if (this.searchText.length) {
this.searchText = '';
this.searchTextUpdated();
if (this.textSearch.value.length) {
this.textSearch.reset();
}
}
}
private searchTextUpdated() {
private searchTextUpdated(searchText: string) {
if (this.searchableComponent) {
this.searchableComponent.onSearchTextUpdated(this.searchText);
this.searchableComponent.onSearchTextUpdated(searchText.trim());
}
}
}

8
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html

@ -46,12 +46,12 @@
matTooltipPosition="above">
<mat-icon>search</mat-icon>
</button>
<input #ruleNodeSearchInput matInput
[(ngModel)]="ruleNodeTypeSearch"
<input matInput
[formControl]="ruleNodeTypeSearch"
placeholder="{{'rulenode.search' | translate}}"/>
<button mat-icon-button matSuffix class="tb-small"
[fxShow]="ruleNodeTypeSearch !== ''"
(click)="ruleNodeTypeSearch = ''; updateRuleChainLibrary()"
[fxShow]="ruleNodeTypeSearch.value !== ''"
(click)="ruleNodeTypeSearch.reset()"
matTooltip="{{'action.clear-search' | translate}}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>

39
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts

@ -19,7 +19,6 @@ import {
AfterViewInit,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostBinding,
Inject,
@ -37,6 +36,7 @@ import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import {
FormBuilder,
FormGroupDirective,
NgForm,
UntypedFormBuilder,
@ -77,8 +77,8 @@ import {
} from '@shared/models/rule-node.models';
import { FcRuleNodeModel, FcRuleNodeTypeModel, RuleChainMenuContextInfo } from './rulechain-page.models';
import { RuleChainService } from '@core/http/rule-chain.service';
import { fromEvent, NEVER, Observable, of, ReplaySubject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, mergeMap, tap } from 'rxjs/operators';
import { NEVER, Observable, of, ReplaySubject, startWith, skip, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, mergeMap, takeUntil, tap } from 'rxjs/operators';
import { ISearchableComponent } from '../../models/searchable-component.models';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import { RuleNodeDetailsComponent } from '@home/pages/rulechain/rule-node-details.component';
@ -115,8 +115,6 @@ export class RuleChainPageComponent extends PageComponent
@HostBinding('style.width') width = '100%';
@HostBinding('style.height') height = '100%';
@ViewChild('ruleNodeSearchInput') ruleNodeSearchInputField: ElementRef;
@ViewChild('ruleChainCanvas', {static: true}) ruleChainCanvas: NgxFlowchartComponent;
@ViewChildren('ruleNodeTypeExpansionPanels',
@ -167,7 +165,7 @@ export class RuleChainPageComponent extends PageComponent
enableHotKeys = true;
ruleNodeSearch = '';
ruleNodeTypeSearch = '';
ruleNodeTypeSearch = this.fb.control('', {nonNullable: true});
ruleChain: RuleChain;
ruleChainMetaData: RuleChainMetaData;
@ -257,7 +255,7 @@ export class RuleChainPageComponent extends PageComponent
updateBreadcrumbs = new EventEmitter();
private rxSubscription: Subscription;
private destroy$ = new Subject<void>();
private tooltipTimeout: Timeout;
@ -274,9 +272,11 @@ export class RuleChainPageComponent extends PageComponent
private changeDetector: ChangeDetectorRef,
public dialog: MatDialog,
public dialogService: DialogService,
public fb: UntypedFormBuilder) {
public fb: FormBuilder) {
super(store);
this.rxSubscription = this.route.data.subscribe(
this.route.data.pipe(
takeUntil(this.destroy$)
).subscribe(
() => {
this.reset();
this.init();
@ -285,6 +285,13 @@ export class RuleChainPageComponent extends PageComponent
}
ngOnInit() {
this.ruleNodeTypeSearch.valueChanges.pipe(
debounceTime(150),
startWith(''),
distinctUntilChanged((a: string, b: string) => a.trim() === b.trim()),
skip(1),
takeUntil(this.destroy$)
).subscribe(() => this.updateRuleChainLibrary());
}
ngAfterViewChecked(){
@ -292,21 +299,13 @@ export class RuleChainPageComponent extends PageComponent
}
ngAfterViewInit() {
fromEvent(this.ruleNodeSearchInputField.nativeElement, 'keyup')
.pipe(
debounceTime(150),
distinctUntilChanged(),
tap(() => {
this.updateRuleChainLibrary();
})
)
.subscribe();
this.ruleChainCanvas.adjustCanvasSize(true);
}
ngOnDestroy() {
super.ngOnDestroy();
this.rxSubscription.unsubscribe();
this.destroy$.next();
this.destroy$.complete();
}
currentRuleChainIdChanged(ruleChainId: string) {
@ -461,7 +460,7 @@ export class RuleChainPageComponent extends PageComponent
}
updateRuleChainLibrary() {
const search = this.ruleNodeTypeSearch.toUpperCase();
const search = this.ruleNodeTypeSearch.value.trim().toUpperCase();
const res = this.ruleNodeComponents.filter(
(ruleNodeComponent) => ruleNodeComponent.name.toUpperCase().includes(search));
this.loadRuleChainLibrary(res);

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

@ -115,8 +115,9 @@ export class PageLink {
public toQuery(): string {
let query = `?pageSize=${this.pageSize}&page=${this.page}`;
if (this.textSearch && this.textSearch.length) {
const textSearch = encodeURIComponent(this.textSearch);
const textSearchParams = this.textSearch?.trim();
if (textSearchParams?.length) {
const textSearch = encodeURIComponent(textSearchParams);
query += `&textSearch=${textSearch}`;
}
if (this.sortOrder) {

Loading…
Cancel
Save