Merge branch 'develop/3.5.2' into feature/basic-widget-config
This commit is contained in:
commit
c6dd11f576
@ -300,6 +300,7 @@ import * as QueueFormComponent from '@home/components/queue/queue-form.component
|
|||||||
import * as AssetProfileComponent from '@home/components/profile/asset-profile.component';
|
import * as AssetProfileComponent from '@home/components/profile/asset-profile.component';
|
||||||
import * as AssetProfileDialogComponent from '@home/components/profile/asset-profile-dialog.component';
|
import * as AssetProfileDialogComponent from '@home/components/profile/asset-profile-dialog.component';
|
||||||
import * as AssetProfileAutocompleteComponent from '@home/components/profile/asset-profile-autocomplete.component';
|
import * as AssetProfileAutocompleteComponent from '@home/components/profile/asset-profile-autocomplete.component';
|
||||||
|
import * as RuleChainSelectComponent from '@shared/components/rule-chain/rule-chain-select.component';
|
||||||
|
|
||||||
import { IModulesMap } from '@modules/common/modules-map.models';
|
import { IModulesMap } from '@modules/common/modules-map.models';
|
||||||
|
|
||||||
@ -418,6 +419,7 @@ class ModulesMap implements IModulesMap {
|
|||||||
'@shared/components/time/quick-time-interval.component': QuickTimeIntervalComponent,
|
'@shared/components/time/quick-time-interval.component': QuickTimeIntervalComponent,
|
||||||
'@shared/components/dashboard-select.component': DashboardSelectComponent,
|
'@shared/components/dashboard-select.component': DashboardSelectComponent,
|
||||||
'@shared/components/dashboard-select-panel.component': DashboardSelectPanelComponent,
|
'@shared/components/dashboard-select-panel.component': DashboardSelectPanelComponent,
|
||||||
|
'@shared/components/rule-chain/rule-chain-select.component': RuleChainSelectComponent,
|
||||||
'@shared/components/time/datetime-period.component': DatetimePeriodComponent,
|
'@shared/components/time/datetime-period.component': DatetimePeriodComponent,
|
||||||
'@shared/components/time/datetime.component': DatetimeComponent,
|
'@shared/components/time/datetime.component': DatetimeComponent,
|
||||||
'@shared/components/time/timezone-select.component': TimezoneSelectComponent,
|
'@shared/components/time/timezone-select.component': TimezoneSelectComponent,
|
||||||
|
|||||||
@ -66,4 +66,29 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<mat-form-field fxFlex class="mat-block">
|
||||||
|
<mat-label translate>widgets.table.default-column-visibility</mat-label>
|
||||||
|
<mat-select formControlName="defaultColumnVisibility">
|
||||||
|
<mat-option [value]="'visible'">
|
||||||
|
{{ 'widgets.table.column-visibility-visible' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'hidden'">
|
||||||
|
{{ 'widgets.table.column-visibility-hidden' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'hidden-mobile'">
|
||||||
|
{{ 'widgets.table.column-visibility-hidden-mobile' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field fxFlex class="mat-block">
|
||||||
|
<mat-label translate>widgets.table.column-selection-to-display</mat-label>
|
||||||
|
<mat-select formControlName="columnSelectionToDisplay">
|
||||||
|
<mat-option [value]="'enabled'">
|
||||||
|
{{ 'widgets.table.column-selection-to-display-enabled' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'disabled'">
|
||||||
|
{{ 'widgets.table.column-selection-to-display-disabled' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -43,7 +43,9 @@ export class TimeseriesTableKeySettingsComponent extends WidgetSettingsComponent
|
|||||||
useCellStyleFunction: false,
|
useCellStyleFunction: false,
|
||||||
cellStyleFunction: '',
|
cellStyleFunction: '',
|
||||||
useCellContentFunction: false,
|
useCellContentFunction: false,
|
||||||
cellContentFunction: ''
|
cellContentFunction: '',
|
||||||
|
defaultColumnVisibility: 'visible',
|
||||||
|
columnSelectionToDisplay: 'enabled'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +55,8 @@ export class TimeseriesTableKeySettingsComponent extends WidgetSettingsComponent
|
|||||||
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
|
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
|
||||||
useCellContentFunction: [settings.useCellContentFunction, []],
|
useCellContentFunction: [settings.useCellContentFunction, []],
|
||||||
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
|
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
|
||||||
|
defaultColumnVisibility: [settings.defaultColumnVisibility, []],
|
||||||
|
columnSelectionToDisplay: [settings.columnSelectionToDisplay, []],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -73,4 +73,29 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</mat-expansion-panel>
|
</mat-expansion-panel>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<mat-form-field fxFlex class="mat-block">
|
||||||
|
<mat-label translate>widgets.table.default-column-visibility</mat-label>
|
||||||
|
<mat-select formControlName="defaultColumnVisibility">
|
||||||
|
<mat-option [value]="'visible'">
|
||||||
|
{{ 'widgets.table.column-visibility-visible' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'hidden'">
|
||||||
|
{{ 'widgets.table.column-visibility-hidden' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'hidden-mobile'">
|
||||||
|
{{ 'widgets.table.column-visibility-hidden-mobile' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field fxFlex class="mat-block">
|
||||||
|
<mat-label translate>widgets.table.column-selection-to-display</mat-label>
|
||||||
|
<mat-select formControlName="columnSelectionToDisplay">
|
||||||
|
<mat-option [value]="'enabled'">
|
||||||
|
{{ 'widgets.table.column-selection-to-display-enabled' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option [value]="'disabled'">
|
||||||
|
{{ 'widgets.table.column-selection-to-display-disabled' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -44,7 +44,9 @@ export class TimeseriesTableLatestKeySettingsComponent extends WidgetSettingsCom
|
|||||||
useCellStyleFunction: false,
|
useCellStyleFunction: false,
|
||||||
cellStyleFunction: '',
|
cellStyleFunction: '',
|
||||||
useCellContentFunction: false,
|
useCellContentFunction: false,
|
||||||
cellContentFunction: ''
|
cellContentFunction: '',
|
||||||
|
defaultColumnVisibility: 'visible',
|
||||||
|
columnSelectionToDisplay: 'enabled'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +58,8 @@ export class TimeseriesTableLatestKeySettingsComponent extends WidgetSettingsCom
|
|||||||
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
|
cellStyleFunction: [settings.cellStyleFunction, [Validators.required]],
|
||||||
useCellContentFunction: [settings.useCellContentFunction, []],
|
useCellContentFunction: [settings.useCellContentFunction, []],
|
||||||
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
|
cellContentFunction: [settings.cellContentFunction, [Validators.required]],
|
||||||
|
defaultColumnVisibility: [settings.defaultColumnVisibility, []],
|
||||||
|
columnSelectionToDisplay: [settings.columnSelectionToDisplay, []],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,9 @@
|
|||||||
<mat-checkbox formControlName="enableSearch">
|
<mat-checkbox formControlName="enableSearch">
|
||||||
{{ 'widgets.table.enable-search' | translate }}
|
{{ 'widgets.table.enable-search' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
|
<mat-checkbox formControlName="enableSelectColumnDisplay">
|
||||||
|
{{ 'widgets.table.enable-select-column-display' | translate }}
|
||||||
|
</mat-checkbox>
|
||||||
</section>
|
</section>
|
||||||
<section fxLayout="column" fxFlex>
|
<section fxLayout="column" fxFlex>
|
||||||
<mat-checkbox formControlName="enableStickyHeader">
|
<mat-checkbox formControlName="enableStickyHeader">
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
|
|||||||
protected defaultSettings(): WidgetSettings {
|
protected defaultSettings(): WidgetSettings {
|
||||||
return {
|
return {
|
||||||
enableSearch: true,
|
enableSearch: true,
|
||||||
|
enableSelectColumnDisplay: true,
|
||||||
enableStickyHeader: true,
|
enableStickyHeader: true,
|
||||||
enableStickyAction: true,
|
enableStickyAction: true,
|
||||||
reserveSpaceForHiddenAction: 'true',
|
reserveSpaceForHiddenAction: 'true',
|
||||||
@ -59,6 +60,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon
|
|||||||
protected onSettingsSet(settings: WidgetSettings) {
|
protected onSettingsSet(settings: WidgetSettings) {
|
||||||
this.timeseriesTableWidgetSettingsForm = this.fb.group({
|
this.timeseriesTableWidgetSettingsForm = this.fb.group({
|
||||||
enableSearch: [settings.enableSearch, []],
|
enableSearch: [settings.enableSearch, []],
|
||||||
|
enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []],
|
||||||
enableStickyHeader: [settings.enableStickyHeader, []],
|
enableStickyHeader: [settings.enableStickyHeader, []],
|
||||||
enableStickyAction: [settings.enableStickyAction, []],
|
enableStickyAction: [settings.enableStickyAction, []],
|
||||||
reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []],
|
reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []],
|
||||||
|
|||||||
@ -31,6 +31,7 @@ type ColumnSelectionOptions = 'enabled' | 'disabled';
|
|||||||
|
|
||||||
export interface TableWidgetSettings {
|
export interface TableWidgetSettings {
|
||||||
enableSearch: boolean;
|
enableSearch: boolean;
|
||||||
|
enableSelectColumnDisplay: boolean;
|
||||||
enableStickyAction: boolean;
|
enableStickyAction: boolean;
|
||||||
enableStickyHeader: boolean;
|
enableStickyHeader: boolean;
|
||||||
displayPagination: boolean;
|
displayPagination: boolean;
|
||||||
|
|||||||
@ -19,9 +19,12 @@ import {
|
|||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
|
Injector,
|
||||||
Input,
|
Input,
|
||||||
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
QueryList,
|
QueryList,
|
||||||
|
StaticProvider,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewChildren,
|
ViewChildren,
|
||||||
ViewContainerRef
|
ViewContainerRef
|
||||||
@ -64,8 +67,9 @@ import {
|
|||||||
CellStyleInfo,
|
CellStyleInfo,
|
||||||
checkHasActions,
|
checkHasActions,
|
||||||
constructTableCssString,
|
constructTableCssString,
|
||||||
|
DisplayColumn,
|
||||||
getCellContentInfo,
|
getCellContentInfo,
|
||||||
getCellStyleInfo,
|
getCellStyleInfo, getColumnDefaultVisibility, getColumnSelectionAvailability,
|
||||||
getRowStyleInfo,
|
getRowStyleInfo,
|
||||||
getTableCellButtonActions,
|
getTableCellButtonActions,
|
||||||
noDataMessage,
|
noDataMessage,
|
||||||
@ -75,12 +79,17 @@ import {
|
|||||||
TableWidgetDataKeySettings,
|
TableWidgetDataKeySettings,
|
||||||
TableWidgetSettings
|
TableWidgetSettings
|
||||||
} from '@home/components/widget/lib/table-widget.models';
|
} from '@home/components/widget/lib/table-widget.models';
|
||||||
import { Overlay } from '@angular/cdk/overlay';
|
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
|
||||||
import { SubscriptionEntityInfo } from '@core/api/widget-api.models';
|
import { SubscriptionEntityInfo } from '@core/api/widget-api.models';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
import { ResizeObserver } from '@juggle/resize-observer';
|
import { ResizeObserver } from '@juggle/resize-observer';
|
||||||
import { hidePageSizePixelValue } from '@shared/models/constants';
|
import { hidePageSizePixelValue } from '@shared/models/constants';
|
||||||
|
import {
|
||||||
|
DISPLAY_COLUMNS_PANEL_DATA,
|
||||||
|
DisplayColumnsPanelComponent
|
||||||
|
} from '@home/components/widget/lib/display-columns-panel.component';
|
||||||
|
import { ComponentPortal } from '@angular/cdk/portal';
|
||||||
|
|
||||||
export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
|
export interface TimeseriesTableWidgetSettings extends TableWidgetSettings {
|
||||||
showTimestamp: boolean;
|
showTimestamp: boolean;
|
||||||
@ -105,6 +114,8 @@ interface TimeseriesHeader {
|
|||||||
dataKey: DataKey;
|
dataKey: DataKey;
|
||||||
sortable: boolean;
|
sortable: boolean;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
columnDefaultVisibility?: boolean;
|
||||||
|
columnSelectionAvailability?: boolean;
|
||||||
styleInfo: CellStyleInfo;
|
styleInfo: CellStyleInfo;
|
||||||
contentInfo: CellContentInfo;
|
contentInfo: CellContentInfo;
|
||||||
order?: number;
|
order?: number;
|
||||||
@ -131,7 +142,7 @@ interface TimeseriesTableSource {
|
|||||||
templateUrl: './timeseries-table-widget.component.html',
|
templateUrl: './timeseries-table-widget.component.html',
|
||||||
styleUrls: ['./timeseries-table-widget.component.scss', './table-widget.scss']
|
styleUrls: ['./timeseries-table-widget.component.scss', './table-widget.scss']
|
||||||
})
|
})
|
||||||
export class TimeseriesTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit {
|
export class TimeseriesTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
ctx: WidgetContext;
|
ctx: WidgetContext;
|
||||||
@ -169,6 +180,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
private useEntityLabel = false;
|
private useEntityLabel = false;
|
||||||
private dateFormatFilter: string;
|
private dateFormatFilter: string;
|
||||||
|
|
||||||
|
private displayedColumns: Array<DisplayColumn[]> = [];
|
||||||
|
|
||||||
private rowStylesInfo: RowStyleInfo;
|
private rowStylesInfo: RowStyleInfo;
|
||||||
|
|
||||||
private subscriptions: Subscription[] = [];
|
private subscriptions: Subscription[] = [];
|
||||||
@ -184,6 +197,15 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private columnDisplayAction: WidgetAction = {
|
||||||
|
name: 'entity.columns-to-display',
|
||||||
|
show: true,
|
||||||
|
icon: 'view_column',
|
||||||
|
onAction: ($event) => {
|
||||||
|
this.editColumnsToDisplay($event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private overlay: Overlay,
|
private overlay: Overlay,
|
||||||
@ -275,11 +297,12 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initialize() {
|
private initialize() {
|
||||||
this.ctx.widgetActions = [this.searchAction ];
|
this.ctx.widgetActions = [this.searchAction, this.columnDisplayAction];
|
||||||
|
|
||||||
this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length;
|
this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length;
|
||||||
|
|
||||||
this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true;
|
this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true;
|
||||||
|
this.columnDisplayAction.show = isDefined(this.settings.enableSelectColumnDisplay) ? this.settings.enableSelectColumnDisplay : true;
|
||||||
this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true;
|
this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true;
|
||||||
this.enableStickyHeader = isDefined(this.settings.enableStickyHeader) ? this.settings.enableStickyHeader : true;
|
this.enableStickyHeader = isDefined(this.settings.enableStickyHeader) ? this.settings.enableStickyHeader : true;
|
||||||
this.enableStickyAction = isDefined(this.settings.enableStickyAction) ? this.settings.enableStickyAction : true;
|
this.enableStickyAction = isDefined(this.settings.enableStickyAction) ? this.settings.enableStickyAction : true;
|
||||||
@ -365,9 +388,82 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
this.sources.push(source);
|
this.sources.push(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.prepareDisplayedColumn();
|
||||||
|
this.sources[this.sourceIndex].displayedColumns =
|
||||||
|
this.displayedColumns[this.sourceIndex].filter(value => value.display).map(value => value.def);
|
||||||
this.updateActiveEntityInfo();
|
this.updateActiveEntityInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private editColumnsToDisplay($event: Event) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
const target = $event.target || $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 source = this.sources[this.sourceIndex];
|
||||||
|
|
||||||
|
this.prepareDisplayedColumn();
|
||||||
|
|
||||||
|
const providers: StaticProvider[] = [
|
||||||
|
{
|
||||||
|
provide: DISPLAY_COLUMNS_PANEL_DATA,
|
||||||
|
useValue: {
|
||||||
|
columns: this.displayedColumns[this.sourceIndex],
|
||||||
|
columnsUpdated: (newColumns) => {
|
||||||
|
source.displayedColumns = newColumns.filter(value => value.display).map(value => value.def);
|
||||||
|
this.clearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: OverlayRef,
|
||||||
|
useValue: overlayRef
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
|
||||||
|
overlayRef.attach(new ComponentPortal(DisplayColumnsPanelComponent,
|
||||||
|
this.viewContainerRef, injector));
|
||||||
|
this.ctx.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepareDisplayedColumn() {
|
||||||
|
if (!this.displayedColumns[this.sourceIndex]) {
|
||||||
|
this.displayedColumns[this.sourceIndex] = this.sources[this.sourceIndex].displayedColumns.map(value => {
|
||||||
|
let title = '';
|
||||||
|
const header = this.sources[this.sourceIndex].header.find(column => column.index.toString() === value);
|
||||||
|
if (value === '0') {
|
||||||
|
title = 'Timestamp';
|
||||||
|
} else if (value === 'actions') {
|
||||||
|
title = 'Actions';
|
||||||
|
} else {
|
||||||
|
title = header.dataKey.name;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
def: value,
|
||||||
|
display: header?.columnDefaultVisibility ?? true,
|
||||||
|
selectable: header?.columnSelectionAvailability ?? true
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private prepareHeader(datasource: Datasource): TimeseriesHeader[] {
|
private prepareHeader(datasource: Datasource): TimeseriesHeader[] {
|
||||||
const dataKeys = datasource.dataKeys;
|
const dataKeys = datasource.dataKeys;
|
||||||
const latestDataKeys = datasource.latestDataKeys;
|
const latestDataKeys = datasource.latestDataKeys;
|
||||||
@ -377,6 +473,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
const keySettings: TableWidgetDataKeySettings = dataKey.settings;
|
const keySettings: TableWidgetDataKeySettings = dataKey.settings;
|
||||||
const styleInfo = getCellStyleInfo(keySettings, 'value, rowData, ctx');
|
const styleInfo = getCellStyleInfo(keySettings, 'value, rowData, ctx');
|
||||||
const contentInfo = getCellContentInfo(keySettings, 'value, rowData, ctx');
|
const contentInfo = getCellContentInfo(keySettings, 'value, rowData, ctx');
|
||||||
|
const columnDefaultVisibility = getColumnDefaultVisibility(keySettings, this.ctx);
|
||||||
|
const columnSelectionAvailability = getColumnSelectionAvailability(keySettings);
|
||||||
contentInfo.units = dataKey.units;
|
contentInfo.units = dataKey.units;
|
||||||
contentInfo.decimals = dataKey.decimals;
|
contentInfo.decimals = dataKey.decimals;
|
||||||
header.push({
|
header.push({
|
||||||
@ -386,6 +484,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
styleInfo,
|
styleInfo,
|
||||||
contentInfo,
|
contentInfo,
|
||||||
show: true,
|
show: true,
|
||||||
|
columnDefaultVisibility,
|
||||||
|
columnSelectionAvailability,
|
||||||
order: index + 2
|
order: index + 2
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -396,6 +496,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
const keySettings: TimeseriesWidgetLatestDataKeySettings = dataKey.settings;
|
const keySettings: TimeseriesWidgetLatestDataKeySettings = dataKey.settings;
|
||||||
const styleInfo = getCellStyleInfo(keySettings, 'value, rowData, ctx');
|
const styleInfo = getCellStyleInfo(keySettings, 'value, rowData, ctx');
|
||||||
const contentInfo = getCellContentInfo(keySettings, 'value, rowData, ctx');
|
const contentInfo = getCellContentInfo(keySettings, 'value, rowData, ctx');
|
||||||
|
const columnDefaultVisibility = getColumnDefaultVisibility(keySettings, this.ctx);
|
||||||
|
const columnSelectionAvailability = getColumnSelectionAvailability(keySettings);
|
||||||
contentInfo.units = dataKey.units;
|
contentInfo.units = dataKey.units;
|
||||||
contentInfo.decimals = dataKey.decimals;
|
contentInfo.decimals = dataKey.decimals;
|
||||||
header.push({
|
header.push({
|
||||||
@ -405,13 +507,13 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI
|
|||||||
styleInfo,
|
styleInfo,
|
||||||
contentInfo,
|
contentInfo,
|
||||||
show: isDefinedAndNotNull(keySettings.show) ? keySettings.show : true,
|
show: isDefinedAndNotNull(keySettings.show) ? keySettings.show : true,
|
||||||
|
columnDefaultVisibility,
|
||||||
|
columnSelectionAvailability,
|
||||||
order: isDefinedAndNotNull(keySettings.order) ? keySettings.order : (index + 2)
|
order: isDefinedAndNotNull(keySettings.order) ? keySettings.order : (index + 2)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
header = header.sort((a, b) => {
|
header = header.sort((a, b) => a.order - b.order);
|
||||||
return a.order - b.order;
|
|
||||||
});
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -59,8 +59,7 @@
|
|||||||
</mat-error>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<tb-template-autocomplete
|
<tb-template-autocomplete
|
||||||
required
|
required allowCreate allowEdit
|
||||||
allowCreate
|
|
||||||
formControlName="templateId"
|
formControlName="templateId"
|
||||||
[notificationTypes]="ruleNotificationForm.get('triggerType').value">
|
[notificationTypes]="ruleNotificationForm.get('triggerType').value">
|
||||||
</tb-template-autocomplete>
|
</tb-template-autocomplete>
|
||||||
|
|||||||
@ -49,8 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div *ngIf="notificationRequestForm.get('useTemplate').value; else scratchTemplate">
|
<div *ngIf="notificationRequestForm.get('useTemplate').value; else scratchTemplate">
|
||||||
<tb-template-autocomplete
|
<tb-template-autocomplete
|
||||||
required
|
required allowCreate allowEdit
|
||||||
allowCreate
|
|
||||||
formControlName="templateId"
|
formControlName="templateId"
|
||||||
[notificationTypes]="notificationType.GENERAL">
|
[notificationTypes]="notificationType.GENERAL">
|
||||||
</tb-template-autocomplete>
|
</tb-template-autocomplete>
|
||||||
|
|||||||
@ -15,55 +15,48 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<div class="mat-content" fxFlex tb-fullscreen [fullscreen]="isFullscreen" tb-hotkeys [hotkeys]="hotKeys"
|
<div class="mat-content tb-rulechain" fxFlex tb-fullscreen [fullscreen]="isFullscreen" tb-hotkeys [hotkeys]="hotKeys"
|
||||||
[cheatSheet]="cheatSheetComponent"
|
[cheatSheet]="cheatSheetComponent" fxLayout="column">
|
||||||
fxLayout="column" class="tb-rulechain">
|
|
||||||
<tb-hotkeys-cheatsheet #cheatSheetComponent></tb-hotkeys-cheatsheet>
|
<tb-hotkeys-cheatsheet #cheatSheetComponent></tb-hotkeys-cheatsheet>
|
||||||
<section class="tb-rulechain-container" fxFlex fxLayout="column">
|
<section class="tb-rulechain-container" fxFlex fxLayout="column">
|
||||||
<div class="tb-rulechain-layout" fxFlex fxLayout="row">
|
<div class="tb-rulechain-layout" fxFlex fxLayout="row">
|
||||||
<section fxLayout="row"
|
|
||||||
class="tb-header-buttons tb-library-open" [fxShow]="!isLibraryOpen">
|
|
||||||
<button color="primary"
|
|
||||||
mat-mini-fab
|
|
||||||
class="tb-btn-header tb-btn-open-library"
|
|
||||||
(click)="isLibraryOpen = true"
|
|
||||||
matTooltip="{{ 'rulenode.open-node-library' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>menu</mat-icon>
|
|
||||||
</button>
|
|
||||||
</section>
|
|
||||||
<mat-drawer-container style="width: 100%; height: 100%;">
|
<mat-drawer-container style="width: 100%; height: 100%;">
|
||||||
<mat-drawer class="tb-rulechain-library mat-elevation-z4"
|
<mat-drawer class="tb-rulechain-library mat-elevation-z4"
|
||||||
disableClose="true"
|
disableClose="true"
|
||||||
mode="side"
|
mode="side"
|
||||||
[opened]="isLibraryOpen"
|
#drawer
|
||||||
|
opened
|
||||||
position="start"
|
position="start"
|
||||||
fxLayout="column">
|
fxLayout="column">
|
||||||
<mat-toolbar color="primary" class="tb-dark">
|
<mat-toolbar color="primary" class="tb-dark">
|
||||||
|
<tb-rule-chain-select
|
||||||
|
fxFlex
|
||||||
|
*ngIf="!isImport"
|
||||||
|
[ruleChainType]="ruleChainType"
|
||||||
|
[disabled]="isDirtyValue"
|
||||||
|
[(ngModel)]="ruleChain.id.id"
|
||||||
|
(ngModelChange)="currentRuleChainIdChanged(ruleChain.id?.id)">
|
||||||
|
</tb-rule-chain-select>
|
||||||
|
</mat-toolbar>
|
||||||
|
<mat-toolbar>
|
||||||
<div class="mat-toolbar-tools">
|
<div class="mat-toolbar-tools">
|
||||||
<button mat-icon-button class="tb-small"
|
<mat-form-field fxFlex class="tb-appearance-transparent">
|
||||||
|
<button mat-icon-button matPrefix class="tb-small"
|
||||||
matTooltip="{{'rulenode.search' | translate}}"
|
matTooltip="{{'rulenode.search' | translate}}"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon>search</mat-icon>
|
<mat-icon>search</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<mat-form-field fxFlex class="tb-appearance-transparent">
|
|
||||||
<input #ruleNodeSearchInput matInput
|
<input #ruleNodeSearchInput matInput
|
||||||
[(ngModel)]="ruleNodeTypeSearch"
|
[(ngModel)]="ruleNodeTypeSearch"
|
||||||
placeholder="{{'rulenode.search' | translate}}"/>
|
placeholder="{{'rulenode.search' | translate}}"/>
|
||||||
</mat-form-field>
|
<button mat-icon-button matSuffix class="tb-small"
|
||||||
<button mat-icon-button class="tb-small"
|
|
||||||
[fxShow]="ruleNodeTypeSearch !== ''"
|
[fxShow]="ruleNodeTypeSearch !== ''"
|
||||||
(click)="ruleNodeTypeSearch = ''; updateRuleChainLibrary()"
|
(click)="ruleNodeTypeSearch = ''; updateRuleChainLibrary()"
|
||||||
matTooltip="{{'action.clear-search' | translate}}"
|
matTooltip="{{'action.clear-search' | translate}}"
|
||||||
matTooltipPosition="above">
|
matTooltipPosition="above">
|
||||||
<mat-icon>close</mat-icon>
|
<mat-icon>close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button class="tb-small"
|
</mat-form-field>
|
||||||
(click)="isLibraryOpen = false"
|
|
||||||
matTooltip="{{'action.close' | translate}}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>chevron_left</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
<div class="tb-rulechain-library-panel-group">
|
<div class="tb-rulechain-library-panel-group">
|
||||||
@ -164,6 +157,14 @@
|
|||||||
</tb-details-panel>
|
</tb-details-panel>
|
||||||
</mat-drawer>
|
</mat-drawer>
|
||||||
<mat-drawer-content class="tb-rulechain-graph-content">
|
<mat-drawer-content class="tb-rulechain-graph-content">
|
||||||
|
<button color="primary"
|
||||||
|
mat-mini-fab
|
||||||
|
class="tb-library-node-btn"
|
||||||
|
(click)="drawer.toggle();"
|
||||||
|
matTooltip="{{ (drawer.opened ? 'rulenode.close-node-library' : 'rulenode.open-node-library') | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon class="tb-library-node-btn-icon" [ngClass]="{'tb-library-node-btn-icon-toggled' : drawer.opened}">chevron_right</mat-icon>
|
||||||
|
</button>
|
||||||
<button #versionControlButton
|
<button #versionControlButton
|
||||||
*ngIf="!isImport"
|
*ngIf="!isImport"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@ -54,20 +54,43 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.tb-header-buttons.tb-library-open {
|
.tb-library-node-btn {
|
||||||
|
width: 20px;
|
||||||
|
height: 90px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 50%;
|
||||||
|
z-index: 1000;
|
||||||
|
opacity: 0.5;
|
||||||
|
border-radius: 0 15px 15px 0 !important;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
&-icon {
|
||||||
|
transition: transform 0.4s !important;
|
||||||
|
&-toggled {
|
||||||
|
transform: rotateZ(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:before {
|
||||||
|
width: 20px;
|
||||||
|
height: 30px;
|
||||||
|
top: -28px;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
content: "";
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
.mdc-fab.tb-btn-open-library {
|
border-radius: 0 0 0 15px;
|
||||||
top: 0;
|
box-shadow: -10px 0px 0 0px #305680;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
width: 20px;
|
||||||
|
height: 30px;
|
||||||
|
bottom: -28px;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 36px;
|
content: "";
|
||||||
height: 36px;
|
pointer-events: none;
|
||||||
margin: 4px 0 0 4px;
|
border-top-left-radius: 15px;
|
||||||
line-height: 36px;
|
box-shadow: -10px 0px 0px 0px #305680;
|
||||||
opacity: .5;
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +100,7 @@
|
|||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
|
|
||||||
.mat-toolbar {
|
.mat-toolbar {
|
||||||
height: 48px;
|
height: min-content;
|
||||||
min-height: 48px;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
.mat-toolbar-tools {
|
.mat-toolbar-tools {
|
||||||
|
|||||||
@ -15,7 +15,9 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AfterViewChecked,
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@ -90,6 +92,7 @@ import { MatMiniFabButton } from '@angular/material/button';
|
|||||||
import { TbPopoverService } from '@shared/components/popover.service';
|
import { TbPopoverService } from '@shared/components/popover.service';
|
||||||
import { VersionControlComponent } from '@home/components/vc/version-control.component';
|
import { VersionControlComponent } from '@home/components/vc/version-control.component';
|
||||||
import { ComponentClusteringMode } from '@shared/models/component-descriptor.models';
|
import { ComponentClusteringMode } from '@shared/models/component-descriptor.models';
|
||||||
|
import { MatDrawer } from '@angular/material/sidenav';
|
||||||
import Timeout = NodeJS.Timeout;
|
import Timeout = NodeJS.Timeout;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -99,7 +102,7 @@ import Timeout = NodeJS.Timeout;
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class RuleChainPageComponent extends PageComponent
|
export class RuleChainPageComponent extends PageComponent
|
||||||
implements AfterViewInit, OnInit, OnDestroy, HasDirtyFlag, ISearchableComponent {
|
implements AfterViewInit, OnInit, OnDestroy, HasDirtyFlag, ISearchableComponent, AfterViewChecked {
|
||||||
|
|
||||||
get isDirty(): boolean {
|
get isDirty(): boolean {
|
||||||
return this.isDirtyValue || this.isImport;
|
return this.isDirtyValue || this.isImport;
|
||||||
@ -121,6 +124,8 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
|
|
||||||
@ViewChild('ruleChainMenuTrigger', {static: true}) ruleChainMenuTrigger: MatMenuTrigger;
|
@ViewChild('ruleChainMenuTrigger', {static: true}) ruleChainMenuTrigger: MatMenuTrigger;
|
||||||
|
|
||||||
|
@ViewChild('drawer') drawer: MatDrawer;
|
||||||
|
|
||||||
eventTypes = EventType;
|
eventTypes = EventType;
|
||||||
|
|
||||||
debugEventTypes = DebugEventType;
|
debugEventTypes = DebugEventType;
|
||||||
@ -159,7 +164,6 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
hotKeys: Hotkey[] = [];
|
hotKeys: Hotkey[] = [];
|
||||||
|
|
||||||
enableHotKeys = true;
|
enableHotKeys = true;
|
||||||
isLibraryOpen = true;
|
|
||||||
|
|
||||||
ruleNodeSearch = '';
|
ruleNodeSearch = '';
|
||||||
ruleNodeTypeSearch = '';
|
ruleNodeTypeSearch = '';
|
||||||
@ -266,6 +270,7 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
private popoverService: TbPopoverService,
|
private popoverService: TbPopoverService,
|
||||||
private renderer: Renderer2,
|
private renderer: Renderer2,
|
||||||
private viewContainerRef: ViewContainerRef,
|
private viewContainerRef: ViewContainerRef,
|
||||||
|
private changeDetector: ChangeDetectorRef,
|
||||||
public dialog: MatDialog,
|
public dialog: MatDialog,
|
||||||
public dialogService: DialogService,
|
public dialogService: DialogService,
|
||||||
public fb: UntypedFormBuilder) {
|
public fb: UntypedFormBuilder) {
|
||||||
@ -281,6 +286,10 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewChecked(){
|
||||||
|
this.changeDetector.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
fromEvent(this.ruleNodeSearchInputField.nativeElement, 'keyup')
|
fromEvent(this.ruleNodeSearchInputField.nativeElement, 'keyup')
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -299,6 +308,14 @@ export class RuleChainPageComponent extends PageComponent
|
|||||||
this.rxSubscription.unsubscribe();
|
this.rxSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentRuleChainIdChanged(ruleChainId: string) {
|
||||||
|
if (this.ruleChainType === RuleChainType.CORE) {
|
||||||
|
this.router.navigateByUrl(`ruleChains/${ruleChainId}`);
|
||||||
|
} else {
|
||||||
|
this.router.navigateByUrl(`edgeManagement/ruleChains/${ruleChainId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onSearchTextUpdated(searchText: string) {
|
onSearchTextUpdated(searchText: string) {
|
||||||
this.ruleNodeSearch = searchText;
|
this.ruleNodeSearch = searchText;
|
||||||
this.updateRuleNodesHighlight();
|
this.updateRuleNodesHighlight();
|
||||||
|
|||||||
@ -29,6 +29,14 @@
|
|||||||
(click)="clear()">
|
(click)="clear()">
|
||||||
<mat-icon class="material-icons">close</mat-icon>
|
<mat-icon class="material-icons">close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
<button *ngIf="selectTemplateFormGroup.get('templateName').value && !disabled && allowEdit"
|
||||||
|
type="button"
|
||||||
|
matSuffix mat-icon-button aria-label="Edit"
|
||||||
|
matTooltip="{{ 'notification.edit-notification-template' | translate }}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
(click)="editTemplate($event)">
|
||||||
|
<mat-icon class="material-icons">edit</mat-icon>
|
||||||
|
</button>
|
||||||
<button #createTemplateButton
|
<button #createTemplateButton
|
||||||
mat-button color="primary" matSuffix
|
mat-button color="primary" matSuffix
|
||||||
*ngIf="allowCreate && !selectTemplateFormGroup.get('templateName').value && !disabled"
|
*ngIf="allowCreate && !selectTemplateFormGroup.get('templateName').value && !disabled"
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
|
import { catchError, debounceTime, map, share, switchMap, tap } from 'rxjs/operators';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -66,6 +66,10 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
|
|||||||
@coerceBoolean()
|
@coerceBoolean()
|
||||||
allowCreate = false;
|
allowCreate = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
allowEdit = false;
|
||||||
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@ -196,18 +200,34 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editTemplate($event: Event) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
this.notificationService.getNotificationTemplateById(this.modelValue.id).subscribe(
|
||||||
|
(template) => {
|
||||||
|
this.openNotificationTemplateDialog({template});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
createTemplate($event: Event, button: MatButton) {
|
createTemplate($event: Event, button: MatButton) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
button._elementRef.nativeElement.blur();
|
button._elementRef.nativeElement.blur();
|
||||||
|
this.openNotificationTemplateDialog({
|
||||||
|
isAdd: true,
|
||||||
|
predefinedType: this.notificationTypes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private openNotificationTemplateDialog(dialogData?: TemplateNotificationDialogData) {
|
||||||
this.dialog.open<TemplateNotificationDialogComponent, TemplateNotificationDialogData,
|
this.dialog.open<TemplateNotificationDialogComponent, TemplateNotificationDialogData,
|
||||||
NotificationTemplate>(TemplateNotificationDialogComponent, {
|
NotificationTemplate>(TemplateNotificationDialogComponent, {
|
||||||
disableClose: true,
|
disableClose: true,
|
||||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||||
data: {
|
data: dialogData
|
||||||
predefinedType: this.notificationTypes
|
|
||||||
}
|
|
||||||
}).afterClosed()
|
}).afterClosed()
|
||||||
.subscribe((res) => {
|
.subscribe((res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
Copyright © 2016-2023 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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<mat-select fxFlex
|
||||||
|
class="tb-rule-chain-select"
|
||||||
|
[required]="required"
|
||||||
|
[disabled]="disabled"
|
||||||
|
[(ngModel)]="ruleChainId"
|
||||||
|
(ngModelChange)="ruleChainIdChanged()">
|
||||||
|
<mat-option *ngFor="let ruleChain of ruleChains$ | async" [value]="ruleChain.id.id">
|
||||||
|
{{ruleChain.name}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2023 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 {
|
||||||
|
min-width: 52px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 6px;
|
||||||
|
.tb-rule-chain-select {
|
||||||
|
display: flex;
|
||||||
|
height: 48px;
|
||||||
|
min-height: 100%;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
///
|
||||||
|
/// Copyright © 2016-2023 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, forwardRef, Input, OnInit } from '@angular/core';
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { PageLink } from '@shared/models/page/page-link';
|
||||||
|
import { map, share } from 'rxjs/operators';
|
||||||
|
import { PageData } from '@shared/models/page/page-data';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '@app/core/core.state';
|
||||||
|
import { TooltipPosition } from '@angular/material/tooltip';
|
||||||
|
import { RuleChain, RuleChainType } from '@shared/models/rule-chain.models';
|
||||||
|
import { RuleChainService } from '@core/http/rule-chain.service';
|
||||||
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
|
import { coerceBoolean } from '@shared/decorators/coercion';
|
||||||
|
import { Direction } from '@shared/models/page/sort-order';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-rule-chain-select',
|
||||||
|
templateUrl: './rule-chain-select.component.html',
|
||||||
|
styleUrls: ['./rule-chain-select.component.scss'],
|
||||||
|
providers: [{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => RuleChainSelectComponent),
|
||||||
|
multi: true
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
export class RuleChainSelectComponent implements ControlValueAccessor, OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
tooltipPosition: TooltipPosition = 'above';
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
required: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
@coerceBoolean()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
ruleChainType: RuleChainType = RuleChainType.CORE;
|
||||||
|
|
||||||
|
ruleChains$: Observable<Array<RuleChain>>;
|
||||||
|
|
||||||
|
ruleChainId: string | null;
|
||||||
|
|
||||||
|
private propagateChange = (v: any) => { };
|
||||||
|
|
||||||
|
constructor(private ruleChainService: RuleChainService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
const pageLink = new PageLink(100, 0, null, {
|
||||||
|
property: 'name',
|
||||||
|
direction: Direction.ASC
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ruleChains$ = this.getRuleChains(pageLink).pipe(
|
||||||
|
map((pageData) => pageData.data),
|
||||||
|
share()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: string | null): void {
|
||||||
|
if (isDefinedAndNotNull(value)) {
|
||||||
|
this.ruleChainId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleChainIdChanged() {
|
||||||
|
this.updateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateView() {
|
||||||
|
this.propagateChange(this.ruleChainId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRuleChains(pageLink: PageLink): Observable<PageData<RuleChain>> {
|
||||||
|
return this.ruleChainService.getRuleChains(pageLink, this.ruleChainType, {ignoreLoading: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -191,6 +191,7 @@ import {
|
|||||||
import { ColorPickerComponent } from '@shared/components/color-picker/color-picker.component';
|
import { ColorPickerComponent } from '@shared/components/color-picker/color-picker.component';
|
||||||
import { ShortNumberPipe } from '@shared/pipe/short-number.pipe';
|
import { ShortNumberPipe } from '@shared/pipe/short-number.pipe';
|
||||||
import { ToggleHeaderComponent } from '@shared/components/toggle-header.component';
|
import { ToggleHeaderComponent } from '@shared/components/toggle-header.component';
|
||||||
|
import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component';
|
||||||
|
|
||||||
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
|
export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) {
|
||||||
return markedOptionsService;
|
return markedOptionsService;
|
||||||
@ -360,7 +361,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
GtMdLgLayoutGapDirective,
|
GtMdLgLayoutGapDirective,
|
||||||
GtMdLgShowHideDirective,
|
GtMdLgShowHideDirective,
|
||||||
ColorPickerComponent,
|
ColorPickerComponent,
|
||||||
ToggleHeaderComponent
|
ToggleHeaderComponent,
|
||||||
|
RuleChainSelectComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -586,7 +588,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
GtMdLgLayoutGapDirective,
|
GtMdLgLayoutGapDirective,
|
||||||
GtMdLgShowHideDirective,
|
GtMdLgShowHideDirective,
|
||||||
ColorPickerComponent,
|
ColorPickerComponent,
|
||||||
ToggleHeaderComponent
|
ToggleHeaderComponent,
|
||||||
|
RuleChainSelectComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
|||||||
@ -3349,6 +3349,7 @@
|
|||||||
"events": "Events",
|
"events": "Events",
|
||||||
"search": "Search nodes",
|
"search": "Search nodes",
|
||||||
"open-node-library": "Open node library",
|
"open-node-library": "Open node library",
|
||||||
|
"close-node-library": "Close node library",
|
||||||
"add": "Add rule node",
|
"add": "Add rule node",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"name-required": "Name is required.",
|
"name-required": "Name is required.",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user