diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html index fd02ac6b34..46faecb9f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html @@ -15,9 +15,43 @@ limitations under the License. --> - +
+
+ + legend.direction + + + {{ legendDirectionTranslations.get(legendDirection[direction]) | translate }} + + + + + legend.position + + + {{ legendPositionTranslations.get(legendPosition[pos]) | translate }} + + + +
+
+ + {{ 'legend.sort-legend' | translate }} + + + {{ 'legend.show-min' | translate }} + + + {{ 'legend.show-max' | translate }} + + + {{ 'legend.show-avg' | translate }} + + + {{ 'legend.show-total' | translate }} + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index 6072bf7eaf..d4ec111bb9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -17,30 +17,21 @@ import { Component, forwardRef, - Inject, - Injector, Input, OnDestroy, OnInit, - StaticProvider, - ViewChild, ViewContainerRef } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { DOCUMENT } from '@angular/common'; -import { CdkOverlayOrigin, ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ComponentPortal } from '@angular/cdk/portal'; -import { MediaBreakpoints } from '@shared/models/constants'; -import { BreakpointObserver } from '@angular/cdk/layout'; -import { WINDOW } from '@core/services/window.service'; -import { deepClone } from '@core/utils'; -import { LegendConfig } from '@shared/models/widget.models'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { isDefined } from '@core/utils'; import { - LEGEND_CONFIG_PANEL_DATA, - LegendConfigPanelComponent, - LegendConfigPanelData -} from '@home/components/widget/legend-config-panel.component'; - + LegendConfig, + LegendDirection, + legendDirectionTranslationMap, + LegendPosition, + legendPositionTranslationMap +} from '@shared/models/widget.models'; +import { Subscription } from 'rxjs'; // @dynamic @Component({ selector: 'tb-legend-config', @@ -58,105 +49,37 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc @Input() disabled: boolean; - @ViewChild('legendConfigPanelOrigin') legendConfigPanelOrigin: CdkOverlayOrigin; + legendSettings: LegendConfig; + legendConfigForm: FormGroup; + legendDirection = LegendDirection; + legendDirections = Object.keys(LegendDirection); + legendDirectionTranslations = legendDirectionTranslationMap; + legendPosition = LegendPosition; + legendPositions = Object.keys(LegendPosition); + legendPositionTranslations = legendPositionTranslationMap; - innerValue: LegendConfig; + legendSettingsChangesSubscription: Subscription; private propagateChange = (_: any) => {}; - constructor(private overlay: Overlay, - public viewContainerRef: ViewContainerRef, - public breakpointObserver: BreakpointObserver, - @Inject(DOCUMENT) private document: Document, - @Inject(WINDOW) private window: Window) { + constructor(public fb: FormBuilder, + public viewContainerRef: ViewContainerRef) { } ngOnInit(): void { + this.legendConfigForm = this.fb.group({ + direction: [null, []], + position: [null, []], + sortDataKeys: [null, []], + showMin: [null, []], + showMax: [null, []], + showAvg: [null, []], + showTotal: [null, []] + }); } ngOnDestroy(): void { - } - - openEditMode() { - if (this.disabled) { - return; - } - const isGtSm = this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']); - const position = this.overlay.position(); - const config = new OverlayConfig({ - panelClass: 'tb-legend-config-panel', - backdropClass: 'cdk-overlay-transparent-backdrop', - hasBackdrop: isGtSm, - }); - if (isGtSm) { - config.minWidth = '220px'; - config.maxHeight = '300px'; - const panelHeight = 220; - const panelWidth = 220; - const el = this.legendConfigPanelOrigin.elementRef.nativeElement; - const offset = el.getBoundingClientRect(); - const scrollTop = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0; - const scrollLeft = this.window.pageXOffset || this.document.documentElement.scrollLeft || this.document.body.scrollLeft || 0; - const bottomY = offset.bottom - scrollTop; - const leftX = offset.left - scrollLeft; - let originX; - let originY; - let overlayX; - let overlayY; - const wHeight = this.document.documentElement.clientHeight; - const wWidth = this.document.documentElement.clientWidth; - if (bottomY + panelHeight > wHeight) { - originY = 'top'; - overlayY = 'bottom'; - } else { - originY = 'bottom'; - overlayY = 'top'; - } - if (leftX + panelWidth > wWidth) { - originX = 'end'; - overlayX = 'end'; - } else { - originX = 'start'; - overlayX = 'start'; - } - const connectedPosition: ConnectedPosition = { - originX, - originY, - overlayX, - overlayY - }; - config.positionStrategy = position.flexibleConnectedTo(this.legendConfigPanelOrigin.elementRef) - .withPositions([connectedPosition]); - } else { - config.minWidth = '100%'; - config.minHeight = '100%'; - config.positionStrategy = position.global().top('0%').left('0%') - .right('0%').bottom('0%'); - } - - const overlayRef = this.overlay.create(config); - - overlayRef.backdropClick().subscribe(() => { - overlayRef.dispose(); - }); - - const injector = this._createLegendConfigPanelInjector( - overlayRef, - { - legendConfig: deepClone(this.innerValue), - legendConfigUpdated: this.legendConfigUpdated.bind(this) - } - ); - - overlayRef.attach(new ComponentPortal(LegendConfigPanelComponent, this.viewContainerRef, injector)); - } - - private _createLegendConfigPanelInjector(overlayRef: OverlayRef, data: LegendConfigPanelData): Injector { - const providers: StaticProvider[] = [ - {provide: LEGEND_CONFIG_PANEL_DATA, useValue: data}, - {provide: OverlayRef, useValue: overlayRef} - ]; - return Injector.create({parent: this.viewContainerRef.injector, providers}); + this.removeChangeSubscriptions(); } registerOnChange(fn: any): void { @@ -168,14 +91,45 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; + if (this.disabled) { + this.legendConfigForm.disable({emitEvent: false}); + } else { + this.legendConfigForm.enable({emitEvent: false}); + } + } + + private removeChangeSubscriptions() { + if (this.legendSettingsChangesSubscription) { + this.legendSettingsChangesSubscription.unsubscribe(); + this.legendSettingsChangesSubscription = null; + } + } + + private createChangeSubscriptions() { + this.legendSettingsChangesSubscription = this.legendConfigForm.valueChanges.subscribe( + () => this.legendConfigUpdated() + ); } writeValue(obj: LegendConfig): void { - this.innerValue = obj; + this.legendSettings = obj; + this.removeChangeSubscriptions(); + if (this.legendSettings) { + this.legendConfigForm.patchValue({ + direction: this.legendSettings.direction, + position: this.legendSettings.position, + sortDataKeys: isDefined(this.legendSettings.sortDataKeys) ? this.legendSettings.sortDataKeys : false, + showMin: isDefined(this.legendSettings.showMin) ? this.legendSettings.showMin : false, + showMax: isDefined(this.legendSettings.showMax) ? this.legendSettings.showMax : false, + showAvg: isDefined(this.legendSettings.showAvg) ? this.legendSettings.showAvg : false, + showTotal: isDefined(this.legendSettings.showTotal) ? this.legendSettings.showTotal : false + }); + } + this.createChangeSubscriptions(); } - private legendConfigUpdated(legendConfig: LegendConfig) { - this.innerValue = legendConfig; - this.propagateChange(this.innerValue); + private legendConfigUpdated() { + this.legendSettings = this.legendConfigForm.value; + this.propagateChange(this.legendSettings); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html index 3be4f1705b..7e69ca704a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.html @@ -292,12 +292,16 @@ -
-
- widget-config.general-settings -
-
- +
+
+
+ widget-config.title + + {{ 'widget-config.display-title' | translate }} + +
+ widget-config.title @@ -306,91 +310,139 @@
-
- -
-
-
-
- + + + + widget-config.advanced-settings + + +
+ +
+
+
+ widget-config.title-icon + {{ 'widget-config.display-icon' | translate }} - - - + +
+ + + + + + widget-config.icon-size + + +
+
+ +
+ widget-config.widget-style +
+
+ + + + +
+
+ + widget-config.padding + + + + widget-config.margin + + +
-
- - - - widget-config.icon-size - - -
-
-
-
- - {{ 'widget-config.display-title' | translate }} - - - {{ 'widget-config.drop-shadow' | translate }} - - - {{ 'widget-config.enable-fullscreen' | translate }} - -
-
- -
-
-
-
- - - - -
-
- - widget-config.padding - - - - widget-config.margin - - -
-
+ + {{ 'widget-config.drop-shadow' | translate }} + + + {{ 'widget-config.enable-fullscreen' | translate }} + + + + + widget-config.advanced-settings + + +
+ +
+
+ +
+ widget-config.legend + + + + + {{ 'widget-config.display-legend' | translate }} + + + + widget-config.advanced-settings + + + + +
+
+ widget-config.mobile-mode-settings + + + + + {{ 'widget-config.mobile-hide' | translate }} + + + + widget-config.advanced-settings + + +
+ + widget-config.order + + + + widget-config.height + + +
+
+
@@ -402,34 +454,6 @@
-
- - {{ 'widget-config.display-legend' | translate }} - -
- - -
-
-
-
- widget-config.mobile-mode-settings -
- - {{ 'widget-config.mobile-hide' | translate }} - - - widget-config.order - - - - widget-config.height - - -
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 6e1e1cabdf..4c4fa317ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -17,9 +17,6 @@ :host { .tb-widget-config { - .tb-advanced-widget-config { - height: 100%; - } .tb-advanced-widget-config { height: 100%; } @@ -69,6 +66,25 @@ padding-left: 8px; } } + .fields-group { + padding: 0 16px 8px; + margin-bottom: 10px; + border: 1px groove rgba(0, 0, 0, .25); + border-radius: 4px; + legend { + color: rgba(0, 0, 0, .7); + width: fit-content; + } + } + .fields-group-slider { + padding: 0; + legend { + margin-left: 16px; + } + .tb-settings { + padding: 0 16px 8px; + } + } } } @@ -94,6 +110,36 @@ white-space: normal; } .mat-expansion-panel { + &.tb-settings { + box-shadow: none; + .mat-content { + overflow: visible; + } + .mat-expansion-panel-header { + padding: 0; + &:hover { + background: none; + } + .mat-expansion-indicator { + padding: 2px; + } + } + .mat-expansion-panel-header-description { + align-items: center; + } + .mat-expansion-panel-body{ + padding: 0 0 16px; + } + .tb-json-object-panel { + margin: 0; + } + .mat-checkbox-layout { + margin: 5px 0; + } + .mat-checkbox-inner-container { + margin-right: 12px; + } + } &.tb-datasources { &.mat-expanded { overflow: visible; @@ -152,5 +198,8 @@ } } } + .mat-slide-toggle-content { + white-space: normal; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 7351f9985a..48ed4bf700 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -212,11 +212,28 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont showLegend: [null, []], legendConfig: [null, []] }); + this.widgetSettings.get('showTitle').valueChanges.subscribe((value: boolean) => { + if (value) { + this.widgetSettings.get('titleStyle').enable({emitEvent: false}); + this.widgetSettings.get('titleTooltip').enable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').enable({emitEvent: false}); + } else { + this.widgetSettings.get('titleStyle').disable({emitEvent: false}); + this.widgetSettings.get('titleTooltip').disable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').patchValue(false); + this.widgetSettings.get('showTitleIcon').disable({emitEvent: false}); + } + }); + this.widgetSettings.get('showTitleIcon').valueChanges.subscribe((value: boolean) => { if (value) { this.widgetSettings.get('titleIcon').enable({emitEvent: false}); + this.widgetSettings.get('iconColor').enable({emitEvent: false}); + this.widgetSettings.get('iconSize').enable({emitEvent: false}); } else { this.widgetSettings.get('titleIcon').disable({emitEvent: false}); + this.widgetSettings.get('iconColor').disable({emitEvent: false}); + this.widgetSettings.get('iconSize').disable({emitEvent: false}); } }); this.widgetSettings.get('showLegend').valueChanges.subscribe((value: boolean) => { @@ -236,6 +253,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }); } + ngOnDestroy(): void { + this.removeChangeSubscriptions(); + } + private removeChangeSubscriptions() { if (this.dataSettingsChangesSubscription) { this.dataSettingsChangesSubscription.unsubscribe(); @@ -376,7 +397,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont iconColor: isDefined(config.iconColor) ? config.iconColor : 'rgba(0, 0, 0, 0.87)', iconSize: isDefined(config.iconSize) ? config.iconSize : '24px', titleTooltip: isDefined(config.titleTooltip) ? config.titleTooltip : '', - showTitle: config.showTitle, + showTitle: isDefined(config.showTitle) ? config.showTitle : false, dropShadow: isDefined(config.dropShadow) ? config.dropShadow : true, enableFullscreen: isDefined(config.enableFullscreen) ? config.enableFullscreen : true, backgroundColor: config.backgroundColor, @@ -396,11 +417,25 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont }, {emitEvent: false} ); + const showTitle: boolean = this.widgetSettings.get('showTitle').value; + if (showTitle) { + this.widgetSettings.get('titleTooltip').enable({emitEvent: false}); + this.widgetSettings.get('titleStyle').enable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').enable({emitEvent: false}); + } else { + this.widgetSettings.get('titleTooltip').disable({emitEvent: false}); + this.widgetSettings.get('titleStyle').disable({emitEvent: false}); + this.widgetSettings.get('showTitleIcon').disable({emitEvent: false}); + } const showTitleIcon: boolean = this.widgetSettings.get('showTitleIcon').value; if (showTitleIcon) { this.widgetSettings.get('titleIcon').enable({emitEvent: false}); + this.widgetSettings.get('iconColor').enable({emitEvent: false}); + this.widgetSettings.get('iconSize').enable({emitEvent: false}); } else { this.widgetSettings.get('titleIcon').disable({emitEvent: false}); + this.widgetSettings.get('iconColor').disable({emitEvent: false}); + this.widgetSettings.get('iconSize').disable({emitEvent: false}); } const showLegend: boolean = this.widgetSettings.get('showLegend').value; if (showLegend) { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 16788b9adc..dd719d3258 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3026,16 +3026,16 @@ "title": "Title", "title-tooltip": "Title Tooltip", "general-settings": "General settings", - "display-title": "Display title", + "display-title": "Display widget title", "drop-shadow": "Drop shadow", - "enable-fullscreen": "Enable fullscreen", + "enable-fullscreen": "Allow fullscreen", "background-color": "Background color", "text-color": "Text color", "padding": "Padding", "margin": "Margin", "widget-style": "Widget style", "title-style": "Title style", - "mobile-mode-settings": "Mobile mode settings", + "mobile-mode-settings": "Mobile mode", "order": "Order", "height": "Height", "mobile-hide": "Hide widget in mobile mode", @@ -3044,6 +3044,7 @@ "timewindow": "Timewindow", "use-dashboard-timewindow": "Use dashboard timewindow", "display-timewindow": "Display timewindow", + "legend": "Legend", "display-legend": "Display legend", "datasources": "Datasources", "maximum-datasources": "Maximum { count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }", @@ -3071,9 +3072,11 @@ "delete-action": "Delete action", "delete-action-title": "Delete widget action", "delete-action-text": "Are you sure you want delete widget action with name '{{actionName}}'?", + "title-icon": "Title icon", "display-icon": "Display title icon", "icon-color": "Icon color", - "icon-size": "Icon size" + "icon-size": "Icon size", + "advanced-settings": "Advanced settings" }, "widget-type": { "import": "Import widget type", diff --git a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json index 35df70e300..65381458ce 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1631,7 +1631,7 @@ "advanced": "Дополнительно", "title": "Название", "general-settings": "Общие настройки", - "display-title": "Показать название", + "display-title": "Показать название на виджете", "drop-shadow": "Тень", "enable-fullscreen": "Во весь экран", "background-color": "Цвет фона", @@ -1640,7 +1640,7 @@ "margin": "Margin", "widget-style": "Стиль виджета", "title-style": "Стиль названия", - "mobile-mode-settings": "Настройки мобильного режима", + "mobile-mode-settings": "Мобильный режим", "order": "Порядок", "height": "Высота", "units": "Специальный символ после значения", @@ -1648,6 +1648,7 @@ "timewindow": "Временное окно", "use-dashboard-timewindow": "Использовать временное окно дашборда", "display-timewindow": "Показывать временное окно", + "legend": "Легенда", "display-legend": "Показать легенду", "datasources": "Источники данных", "maximum-datasources": "Максимальной количество источников данных равно {{count}}", @@ -1673,9 +1674,11 @@ "delete-action": "Удалить действие", "delete-action-title": "Удалить действие виджета", "delete-action-text": "Вы точно хотите удалить действие виджета '{{actionName}}'?", - "display-icon": "Показывать иконку в названии", + "title-icon": "Иконка в названии виджета", + "display-icon": "Показывать иконку в названии виджета", "icon-color": "Цвет иконки", - "icon-size": "Размер иконки" + "icon-size": "Размер иконки", + "advanced-settings": "Расширенные настройки" }, "widget-type": { "import": "Импортировать тип виджета", diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index 257a3519a9..b4620a937d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2202,7 +2202,7 @@ "advanced": "Додатково", "title": "Назва", "general-settings": "Загальні налаштування", - "display-title": "Відобразити назву", + "display-title": "Відобразити назву у віджеті", "drop-shadow": "Тінь", "enable-fullscreen": "Увімкнути повноекранний режим", "enable-data-export": "Увімкнути експорт даних", @@ -2212,7 +2212,7 @@ "margin": "Границі", "widget-style": "Стиль віджетів", "title-style": "Стиль заголовка", - "mobile-mode-settings": "Налаштування мобільного режиму", + "mobile-mode-settings": "мобільний режим", "order": "Порядок", "height": "Висота", "units": "Спеціальний символ після значення", @@ -2220,6 +2220,7 @@ "timewindow": "Вікно часу", "use-dashboard-timewindow": "Використати вікно часу на панелі візуалізації", "display-timewindow": "Показувати вікно часу", + "legend": "Легенда", "display-legend": "Показати легенду", "datasources": "Джерела даних", "maximum-datasources": "Максимально { count, plural, 1 {1 дозволене джерело даних.} other {# дозволені джерела даних } }", @@ -2245,9 +2246,11 @@ "delete-action": "Видалити дію", "delete-action-title": "Видалити дію віджета", "delete-action-text": "Ви впевнені, що хочете видалити дію віджета '{{actionName}}'?", - "display-icon": "Показувати іконку у назві", + "title-icon": "Іконка у назві віджету", + "display-icon": "Показувати іконку у назві віджету", "icon-color": "Колір іконки", - "icon-size": "Розмір іконки" + "icon-size": "Розмір іконки", + "advanced-settings": "Розширені налаштування" }, "widget-type": { "import": "Імпортувати тип віджета",