diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index b3a14b0f61..5cc9a49d42 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -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 AssetProfileDialogComponent from '@home/components/profile/asset-profile-dialog.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'; @@ -418,6 +419,7 @@ class ModulesMap implements IModulesMap { '@shared/components/time/quick-time-interval.component': QuickTimeIntervalComponent, '@shared/components/dashboard-select.component': DashboardSelectComponent, '@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.component': DatetimeComponent, '@shared/components/time/timezone-select.component': TimezoneSelectComponent, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html index e7ce8a1a02..2dbedf96bd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html @@ -66,4 +66,29 @@ + + widgets.table.default-column-visibility + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + + + widgets.table.column-selection-to-display + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.ts index 722df5bc5f..66a2c8b483 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.ts @@ -43,7 +43,9 @@ export class TimeseriesTableKeySettingsComponent extends WidgetSettingsComponent useCellStyleFunction: false, cellStyleFunction: '', useCellContentFunction: false, - cellContentFunction: '' + cellContentFunction: '', + defaultColumnVisibility: 'visible', + columnSelectionToDisplay: 'enabled' }; } @@ -53,6 +55,8 @@ export class TimeseriesTableKeySettingsComponent extends WidgetSettingsComponent cellStyleFunction: [settings.cellStyleFunction, [Validators.required]], useCellContentFunction: [settings.useCellContentFunction, []], cellContentFunction: [settings.cellContentFunction, [Validators.required]], + defaultColumnVisibility: [settings.defaultColumnVisibility, []], + columnSelectionToDisplay: [settings.columnSelectionToDisplay, []], }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html index a5b4f6bef2..8fb1629b13 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html @@ -73,4 +73,29 @@ + + widgets.table.default-column-visibility + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + + + widgets.table.column-selection-to-display + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.ts index 70fac42f98..3fe1f1027e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.ts @@ -44,7 +44,9 @@ export class TimeseriesTableLatestKeySettingsComponent extends WidgetSettingsCom useCellStyleFunction: false, cellStyleFunction: '', useCellContentFunction: false, - cellContentFunction: '' + cellContentFunction: '', + defaultColumnVisibility: 'visible', + columnSelectionToDisplay: 'enabled' }; } @@ -56,6 +58,8 @@ export class TimeseriesTableLatestKeySettingsComponent extends WidgetSettingsCom cellStyleFunction: [settings.cellStyleFunction, [Validators.required]], useCellContentFunction: [settings.useCellContentFunction, []], cellContentFunction: [settings.cellContentFunction, [Validators.required]], + defaultColumnVisibility: [settings.defaultColumnVisibility, []], + columnSelectionToDisplay: [settings.columnSelectionToDisplay, []], }); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index 075cb5583c..ed4428fe45 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -23,6 +23,9 @@ {{ 'widgets.table.enable-search' | translate }} + + {{ 'widgets.table.enable-select-column-display' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index 273dfbd703..0a57402870 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -41,6 +41,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon protected defaultSettings(): WidgetSettings { return { enableSearch: true, + enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, reserveSpaceForHiddenAction: 'true', @@ -59,6 +60,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon protected onSettingsSet(settings: WidgetSettings) { this.timeseriesTableWidgetSettingsForm = this.fb.group({ enableSearch: [settings.enableSearch, []], + enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index 3cd343ea57..2a29776e7e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -31,6 +31,7 @@ type ColumnSelectionOptions = 'enabled' | 'disabled'; export interface TableWidgetSettings { enableSearch: boolean; + enableSelectColumnDisplay: boolean; enableStickyAction: boolean; enableStickyHeader: boolean; displayPagination: boolean; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 9aae6523ed..9342a2dc4c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -19,9 +19,12 @@ import { ChangeDetectorRef, Component, ElementRef, + Injector, Input, + OnDestroy, OnInit, QueryList, + StaticProvider, ViewChild, ViewChildren, ViewContainerRef @@ -64,8 +67,9 @@ import { CellStyleInfo, checkHasActions, constructTableCssString, + DisplayColumn, getCellContentInfo, - getCellStyleInfo, + getCellStyleInfo, getColumnDefaultVisibility, getColumnSelectionAvailability, getRowStyleInfo, getTableCellButtonActions, noDataMessage, @@ -75,12 +79,17 @@ import { TableWidgetDataKeySettings, TableWidgetSettings } 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 { DatePipe } from '@angular/common'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ResizeObserver } from '@juggle/resize-observer'; 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 { showTimestamp: boolean; @@ -105,6 +114,8 @@ interface TimeseriesHeader { dataKey: DataKey; sortable: boolean; show: boolean; + columnDefaultVisibility?: boolean; + columnSelectionAvailability?: boolean; styleInfo: CellStyleInfo; contentInfo: CellContentInfo; order?: number; @@ -131,7 +142,7 @@ interface TimeseriesTableSource { templateUrl: './timeseries-table-widget.component.html', 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() ctx: WidgetContext; @@ -169,6 +180,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI private useEntityLabel = false; private dateFormatFilter: string; + private displayedColumns: Array = []; + private rowStylesInfo: RowStyleInfo; 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, private elementRef: ElementRef, private overlay: Overlay, @@ -275,11 +297,12 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI } private initialize() { - this.ctx.widgetActions = [this.searchAction ]; + this.ctx.widgetActions = [this.searchAction, this.columnDisplayAction]; this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length; 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.enableStickyHeader = isDefined(this.settings.enableStickyHeader) ? this.settings.enableStickyHeader : 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.prepareDisplayedColumn(); + this.sources[this.sourceIndex].displayedColumns = + this.displayedColumns[this.sourceIndex].filter(value => value.display).map(value => value.def); 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[] { const dataKeys = datasource.dataKeys; const latestDataKeys = datasource.latestDataKeys; @@ -377,6 +473,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI const keySettings: TableWidgetDataKeySettings = dataKey.settings; const styleInfo = getCellStyleInfo(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.decimals = dataKey.decimals; header.push({ @@ -386,6 +484,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI styleInfo, contentInfo, show: true, + columnDefaultVisibility, + columnSelectionAvailability, order: index + 2 }); }); @@ -396,6 +496,8 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI const keySettings: TimeseriesWidgetLatestDataKeySettings = dataKey.settings; const styleInfo = getCellStyleInfo(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.decimals = dataKey.decimals; header.push({ @@ -405,13 +507,13 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI styleInfo, contentInfo, show: isDefinedAndNotNull(keySettings.show) ? keySettings.show : true, + columnDefaultVisibility, + columnSelectionAvailability, order: isDefinedAndNotNull(keySettings.order) ? keySettings.order : (index + 2) }); }); } - header = header.sort((a, b) => { - return a.order - b.order; - }); + header = header.sort((a, b) => a.order - b.order); return header; } diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html index fc48392e8c..4e7a133009 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html @@ -59,8 +59,7 @@ diff --git a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html index 27b8968344..4ff13778e5 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html @@ -49,8 +49,7 @@
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html index efb4851bd8..4cdaed942d 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html @@ -15,55 +15,48 @@ limitations under the License. --> -
+
-
- -
+ + + +
- + + - -
@@ -164,6 +157,14 @@ + +