committed by
GitHub
42 changed files with 894 additions and 135 deletions
@ -0,0 +1,96 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2025 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. |
||||
|
|
||||
|
--> |
||||
|
<ng-container *ngIf="panelMode; else componentMode"> |
||||
|
<ng-container *ngTemplateOutlet="calculatedFieldsFilterPanel"></ng-container> |
||||
|
</ng-container> |
||||
|
<ng-template #componentMode> |
||||
|
<ng-container *ngIf="buttonMode; else calculatedFieldsFilter"> |
||||
|
<button color="primary" |
||||
|
matTooltip="{{ 'calculated-fields.calculated-fields-filter' | translate }}" |
||||
|
matTooltipPosition="above" |
||||
|
mat-stroked-button |
||||
|
(click)="toggleCfFilterPanel($event)"> |
||||
|
<mat-icon>filter_list</mat-icon>{{ 'calculated-fields.calculated-fields-filter' | translate }} |
||||
|
</button> |
||||
|
</ng-container> |
||||
|
</ng-template> |
||||
|
<ng-template #calculatedFieldsFilterPanel> |
||||
|
<form class="mat-content mat-padding flex flex-col" (ngSubmit)="update()"> |
||||
|
<ng-container *ngTemplateOutlet="calculatedFieldsFilter"></ng-container> |
||||
|
<div class="tb-panel-actions flex flex-row items-center justify-end"> |
||||
|
<button type="button" |
||||
|
mat-button |
||||
|
color="primary" |
||||
|
(click)="reset()"> |
||||
|
{{ 'action.reset' | translate }} |
||||
|
</button> |
||||
|
<span class="flex-1"></span> |
||||
|
<button type="button" |
||||
|
mat-button |
||||
|
(click)="cancel()"> |
||||
|
{{ 'action.cancel' | translate }} |
||||
|
</button> |
||||
|
<button type="submit" |
||||
|
mat-raised-button |
||||
|
color="primary" |
||||
|
[disabled]="cfFilterForm.invalid || !cfFilterForm.dirty"> |
||||
|
{{ 'action.update' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</form> |
||||
|
</ng-template> |
||||
|
<ng-template #calculatedFieldsFilter> |
||||
|
<div class="tb-form-panel tb-calculated-fields-config-component no-padding no-border" [formGroup]="cfFilterForm"> |
||||
|
<div class="tb-form-row column-xs"> |
||||
|
<div class="fixed-title-width" translate>calculated-fields.calculated-field-types</div> |
||||
|
<tb-string-items-list subscriptSizing="dynamic" |
||||
|
formControlName="types" |
||||
|
appearance="outline" |
||||
|
fieldClass="flex" |
||||
|
class="flex-1" |
||||
|
placeholder="{{ !cfFilterForm.get('types').value?.length ? ('calculated-fields.any-type' | translate) : '' }}" |
||||
|
[predefinedValues]="types"> |
||||
|
</tb-string-items-list> |
||||
|
</div> |
||||
|
<div class="tb-form-row column-xs"> |
||||
|
<div class="fixed-title-width" translate>alarm-rule.target-entity-type</div> |
||||
|
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<mat-select formControlName="entityType" placeholder="{{ 'alarm-rule.any-type' | translate }}"> |
||||
|
<mat-option>{{ 'alarm-rule.any-type' | translate }}</mat-option> |
||||
|
<mat-option *ngFor="let type of listEntityTypes" [value]="type"> |
||||
|
{{ entityTypeTranslations.get(type)?.type | translate }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
@if (cfFilterForm.get('entityType').value) { |
||||
|
<div class="tb-form-row column-xs"> |
||||
|
<div class="fixed-title-width" translate>alarm-rule.target-entities</div> |
||||
|
<tb-entity-list appearance="outline" |
||||
|
subscriptSizing="dynamic" |
||||
|
class="flex flex-1" |
||||
|
inlineField |
||||
|
syncIdsWithDB |
||||
|
labelText="{{'entity.entity-list' | translate}}" |
||||
|
[entityType]="cfFilterForm.get('entityType').value" |
||||
|
formControlName="entities"> |
||||
|
</tb-entity-list> |
||||
|
</div> |
||||
|
} |
||||
|
</div> |
||||
|
</ng-template> |
||||
@ -0,0 +1,56 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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 '../scss/constants'; |
||||
|
|
||||
|
:host { |
||||
|
display: flex; |
||||
|
max-width: 100%; |
||||
|
.mdc-button { |
||||
|
max-width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:host ::ng-deep { |
||||
|
.mdc-button { |
||||
|
.mat-icon { |
||||
|
min-width: 24px; |
||||
|
} |
||||
|
.mdc-button__label { |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
::ng-deep { |
||||
|
.tb-calculated-fields-config-component { |
||||
|
max-width: 100%; |
||||
|
width: 600px; |
||||
|
min-width: 100%; |
||||
|
flex: 1; |
||||
|
|
||||
|
tb-entity-subtype-list { |
||||
|
flex: 1; |
||||
|
@media #{$mat-gt-xs} { |
||||
|
width: 180px; |
||||
|
} |
||||
|
.mdc-evolution-chip-set__chips { |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,281 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2025 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, |
||||
|
DestroyRef, |
||||
|
ElementRef, |
||||
|
forwardRef, |
||||
|
Inject, |
||||
|
InjectionToken, |
||||
|
Input, |
||||
|
OnInit, |
||||
|
Optional, |
||||
|
TemplateRef, |
||||
|
ViewChild, |
||||
|
ViewContainerRef |
||||
|
} from '@angular/core'; |
||||
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; |
||||
|
import { coerceBoolean } from '@shared/decorators/coercion'; |
||||
|
import { Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; |
||||
|
import { TemplatePortal } from '@angular/cdk/portal'; |
||||
|
import { deepClone, isArraysEqualIgnoreUndefined, isDefinedAndNotNull, isEmpty, isUndefinedOrNull } from '@core/utils'; |
||||
|
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; |
||||
|
import { fromEvent, Subscription } from 'rxjs'; |
||||
|
import { POSITION_MAP } from '@shared/models/overlay.models'; |
||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
||||
|
import { |
||||
|
calculatedFieldsEntityTypeList, |
||||
|
CalculatedFieldsQuery, |
||||
|
calculatedFieldTypes, |
||||
|
CalculatedFieldTypeTranslations |
||||
|
} from '@shared/models/calculated-field.models'; |
||||
|
import { StringItemsOption } from '@shared/components/string-items-list.component'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
|
||||
|
export const CALCULATED_FIELDS_CONFIG_DATA = new InjectionToken<any>('CalculatedFieldsFilterConfigData'); |
||||
|
|
||||
|
export interface CalculatedFieldsFilterConfigData { |
||||
|
panelMode: boolean; |
||||
|
userMode: boolean; |
||||
|
filterConfig: CalculatedFieldsQuery; |
||||
|
initialFilterConfig?: CalculatedFieldsQuery; |
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-calculated-fields-filter-config', |
||||
|
templateUrl: './calculated-fields-filter-config.component.html', |
||||
|
styleUrls: ['./calculated-fields-filter-config.component.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => CalculatedFieldsFilterConfigComponent), |
||||
|
multi: true |
||||
|
} |
||||
|
] |
||||
|
}) |
||||
|
export class CalculatedFieldsFilterConfigComponent implements OnInit, ControlValueAccessor { |
||||
|
|
||||
|
@ViewChild('calculatedFieldsFilterPanel') |
||||
|
calculatedFieldsFilterPanel: TemplateRef<any>; |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
@coerceBoolean() |
||||
|
@Input() |
||||
|
buttonMode = true; |
||||
|
|
||||
|
@coerceBoolean() |
||||
|
@Input() |
||||
|
userMode = false; |
||||
|
|
||||
|
@coerceBoolean() |
||||
|
@Input() |
||||
|
propagatedFilter = true; |
||||
|
|
||||
|
@Input() |
||||
|
initialCfFilterConfig: CalculatedFieldsQuery = { |
||||
|
types: [], |
||||
|
entityType: null, |
||||
|
entities: [] |
||||
|
}; |
||||
|
|
||||
|
panelMode = false; |
||||
|
|
||||
|
cfFilterForm: FormGroup; |
||||
|
|
||||
|
panelResult: CalculatedFieldsQuery = null; |
||||
|
|
||||
|
entityType = EntityType; |
||||
|
|
||||
|
listEntityTypes = calculatedFieldsEntityTypeList; |
||||
|
entityTypeTranslations = entityTypeTranslations; |
||||
|
|
||||
|
readonly types: StringItemsOption[] = calculatedFieldTypes.map(item => ({ |
||||
|
name: this.translate.instant(CalculatedFieldTypeTranslations.get(item).name), |
||||
|
value: item |
||||
|
})); |
||||
|
|
||||
|
private cfFilterOverlayRef: OverlayRef; |
||||
|
private cfFilterConfig: CalculatedFieldsQuery; |
||||
|
private resizeWindows: Subscription; |
||||
|
|
||||
|
private propagateChange = (_: any) => {}; |
||||
|
|
||||
|
constructor(@Optional() @Inject(CALCULATED_FIELDS_CONFIG_DATA) |
||||
|
private data: CalculatedFieldsFilterConfigData | undefined, |
||||
|
@Optional() private overlayRef: OverlayRef, |
||||
|
private fb: FormBuilder, |
||||
|
private overlay: Overlay, |
||||
|
private nativeElement: ElementRef, |
||||
|
private viewContainerRef: ViewContainerRef, |
||||
|
private destroyRef: DestroyRef, |
||||
|
private translate: TranslateService) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
if (this.data) { |
||||
|
this.panelMode = this.data.panelMode; |
||||
|
this.userMode = this.data.userMode; |
||||
|
this.cfFilterConfig = this.data.filterConfig; |
||||
|
this.initialCfFilterConfig = this.data.initialFilterConfig; |
||||
|
if (this.panelMode && !this.initialCfFilterConfig) { |
||||
|
this.initialCfFilterConfig = deepClone(this.cfFilterConfig); |
||||
|
} |
||||
|
} |
||||
|
this.cfFilterForm = this.fb.group({ |
||||
|
types: [null, []], |
||||
|
entityType: [null, []], |
||||
|
entities: [null, []] |
||||
|
}); |
||||
|
this.cfFilterForm.valueChanges.pipe( |
||||
|
takeUntilDestroyed(this.destroyRef) |
||||
|
).subscribe( |
||||
|
() => { |
||||
|
if (!this.buttonMode) { |
||||
|
this.cfConfigUpdated(this.cfFilterForm.value); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
if (this.panelMode) { |
||||
|
this.updateCfConfigForm(this.cfFilterConfig); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(_fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.cfFilterForm.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.cfFilterForm.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(cfFilterConfig?: CalculatedFieldsQuery): void { |
||||
|
this.cfFilterConfig = cfFilterConfig; |
||||
|
if (!this.initialCfFilterConfig && cfFilterConfig) { |
||||
|
this.initialCfFilterConfig = deepClone(cfFilterConfig); |
||||
|
} |
||||
|
this.updateCfConfigForm(cfFilterConfig); |
||||
|
} |
||||
|
|
||||
|
toggleCfFilterPanel($event: Event) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
const config = new OverlayConfig({ |
||||
|
panelClass: 'tb-filter-panel', |
||||
|
backdropClass: 'cdk-overlay-transparent-backdrop', |
||||
|
hasBackdrop: true, |
||||
|
maxHeight: '80vh', |
||||
|
height: 'min-content', |
||||
|
minWidth: '' |
||||
|
}); |
||||
|
config.hasBackdrop = true; |
||||
|
config.positionStrategy = this.overlay.position() |
||||
|
.flexibleConnectedTo(this.nativeElement) |
||||
|
.withPositions([POSITION_MAP.bottomLeft]); |
||||
|
|
||||
|
this.cfFilterOverlayRef = this.overlay.create(config); |
||||
|
this.cfFilterOverlayRef.backdropClick().subscribe(() => { |
||||
|
this.cfFilterOverlayRef.dispose(); |
||||
|
}); |
||||
|
this.cfFilterOverlayRef.attach(new TemplatePortal(this.calculatedFieldsFilterPanel, |
||||
|
this.viewContainerRef)); |
||||
|
this.resizeWindows = fromEvent(window, 'resize').subscribe(() => { |
||||
|
this.cfFilterOverlayRef.updatePosition(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
cancel() { |
||||
|
this.updateCfConfigForm(this.cfFilterConfig); |
||||
|
if (this.overlayRef) { |
||||
|
this.overlayRef.dispose(); |
||||
|
} else { |
||||
|
this.resizeWindows.unsubscribe(); |
||||
|
this.cfFilterOverlayRef.dispose(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
update() { |
||||
|
this.cfConfigUpdated(this.cfFilterForm.value); |
||||
|
this.cfFilterForm.markAsPristine(); |
||||
|
if (this.panelMode) { |
||||
|
this.panelResult = this.cfFilterConfig; |
||||
|
} |
||||
|
if (this.overlayRef) { |
||||
|
this.overlayRef.dispose(); |
||||
|
} else { |
||||
|
this.resizeWindows.unsubscribe(); |
||||
|
this.cfFilterOverlayRef.dispose(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
reset() { |
||||
|
const cfFilterConfig = this.cfFilterFromFormValue(this.cfFilterForm.value); |
||||
|
if (!this.cfFilterConfigEquals(cfFilterConfig, this.initialCfFilterConfig)) { |
||||
|
this.updateCfConfigForm(this.initialCfFilterConfig); |
||||
|
this.cfFilterForm.markAsDirty(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private cfFilterConfigEquals = (filter1?: CalculatedFieldsQuery, filter2?: CalculatedFieldsQuery): boolean => { |
||||
|
if (filter1 === filter2) { |
||||
|
return true; |
||||
|
} |
||||
|
if ((isUndefinedOrNull(filter1) || isEmpty(filter1)) && (isUndefinedOrNull(filter2) || isEmpty(filter2))) { |
||||
|
return true; |
||||
|
} else if (isDefinedAndNotNull(filter1) && isDefinedAndNotNull(filter2)) { |
||||
|
if (!isArraysEqualIgnoreUndefined(filter1.types, filter2.types)) { |
||||
|
return false; |
||||
|
} |
||||
|
if (!isArraysEqualIgnoreUndefined(filter1.entities, filter2.entities)) { |
||||
|
return false; |
||||
|
} |
||||
|
return filter1.entityType !== filter2.entityType; |
||||
|
} |
||||
|
return false; |
||||
|
}; |
||||
|
|
||||
|
private updateCfConfigForm(cfFilterConfig?: CalculatedFieldsQuery) { |
||||
|
this.cfFilterForm.patchValue({ |
||||
|
types: cfFilterConfig?.types ?? [], |
||||
|
entityType: cfFilterConfig?.entityType ?? null, |
||||
|
entities: cfFilterConfig?.entities ?? [], |
||||
|
}, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private cfConfigUpdated(formValue: any) { |
||||
|
this.cfFilterConfig = this.cfFilterFromFormValue(formValue); |
||||
|
this.propagateChange(this.cfFilterConfig); |
||||
|
} |
||||
|
|
||||
|
private cfFilterFromFormValue(formValue: any): CalculatedFieldsQuery { |
||||
|
return { |
||||
|
types: formValue?.types ?? [], |
||||
|
entityType: formValue?.entityType ?? null, |
||||
|
entities: formValue?.entities ?? [], |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2025 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. |
||||
|
|
||||
|
--> |
||||
|
<tb-calculated-fields-filter-config [ngModel]="calculatedFieldsTableConfig.calculatedFieldFilterConfig" |
||||
|
(ngModelChange)="calculatedFieldsFilterChanged($event)"> |
||||
|
</tb-calculated-fields-filter-config> |
||||
@ -0,0 +1,21 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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 { |
||||
|
padding-right: 8px; |
||||
|
overflow: hidden; |
||||
|
max-width: 100%; |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2025 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 } from '@angular/core'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component'; |
||||
|
import { CalculatedField, CalculatedFieldsQuery } from "@shared/models/calculated-field.models"; |
||||
|
import { CalculatedFieldsTableConfig } from '@home/components/calculated-fields/calculated-fields-table-config'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-calculated-fields-table-header', |
||||
|
templateUrl: './calculated-fields-header.component.html', |
||||
|
styleUrls: ['./calculated-fields-header.component.scss'] |
||||
|
}) |
||||
|
export class CalculatedFieldsHeaderComponent extends EntityTableHeaderComponent<CalculatedField> { |
||||
|
|
||||
|
get calculatedFieldsTableConfig(): CalculatedFieldsTableConfig { |
||||
|
return this.entitiesTableConfig as CalculatedFieldsTableConfig; |
||||
|
} |
||||
|
|
||||
|
constructor(protected store: Store<AppState>) { |
||||
|
super(store); |
||||
|
} |
||||
|
|
||||
|
calculatedFieldsFilterChanged(calculatedFieldFilterConfig: CalculatedFieldsQuery) { |
||||
|
this.calculatedFieldsTableConfig.calculatedFieldFilterConfig = calculatedFieldFilterConfig; |
||||
|
this.calculatedFieldsTableConfig.getTable().resetSortAndFilter(true, true); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2025 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 { RouterModule, Routes } from '@angular/router'; |
||||
|
import { Authority } from '@shared/models/authority.enum'; |
||||
|
import { MenuId } from '@core/services/menu.models'; |
||||
|
import { CalculatedFieldsTableComponent } from '@home/components/calculated-fields/calculated-fields-table.component'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ |
||||
|
path: 'calculatedFields', |
||||
|
component: CalculatedFieldsTableComponent, |
||||
|
data: { |
||||
|
auth: [Authority.TENANT_ADMIN], |
||||
|
title: 'entity.type-calculated-fields', |
||||
|
breadcrumb: { |
||||
|
menuId: MenuId.calculated_fields |
||||
|
}, |
||||
|
isPage: true, |
||||
|
} |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
providers: [] |
||||
|
}) |
||||
|
export class CalculatedFieldsRoutingModule { } |
||||
@ -0,0 +1,34 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2025 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 '@shared/shared.module'; |
||||
|
import { HomeDialogsModule } from '../../dialogs/home-dialogs.module'; |
||||
|
import { HomeComponentsModule } from '@modules/home/components/home-components.module'; |
||||
|
import { CalculatedFieldsRoutingModule } from '@home/pages/calculated-fields/calculated-fields-routing.module'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [], |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
SharedModule, |
||||
|
HomeComponentsModule, |
||||
|
HomeDialogsModule, |
||||
|
CalculatedFieldsRoutingModule |
||||
|
] |
||||
|
}) |
||||
|
export class CalculatedFieldsModule { } |
||||
Loading…
Reference in new issue