Browse Source

UI: Add to place map item action customize tooltip

pull/13084/head
Vladyslav_Prykhodko 2 years ago
parent
commit
3cefb63436
  1. 2
      ui-ngx/src/app/core/services/utils.service.ts
  2. 41
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts
  3. 82
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/map-item-tooltips.component.html
  4. 123
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/map-item-tooltips.component.ts
  5. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html
  6. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts
  7. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts
  8. 25
      ui-ngx/src/app/shared/models/widget.models.ts
  9. 13
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
ui-ngx/src/app/core/services/utils.service.ts

@ -208,7 +208,7 @@ export class UtilsService {
return parseException(exception, lineOffset);
}
public customTranslation(translationValue: string, defaultValue: string): string {
public customTranslation(translationValue: string, defaultValue: string = translationValue): string {
if (translationValue && isString(translationValue)) {
if (translationValue.includes(`{${i18nPrefix}`)) {
const matches = translationValue.match(i18nRegExp);

41
ui-ngx/src/app/modules/home/components/widget/lib/maps/map.ts

@ -50,7 +50,14 @@ import {
UnplacedMapDataItem,
} from '@home/components/widget/lib/maps/data-layer/latest-map-data-layer';
import { IWidgetSubscription, PlaceMapItemActionData, WidgetSubscriptionOptions } from '@core/api/widget-api.models';
import { FormattedData, MapItemType, WidgetAction, WidgetActionType, widgetType } from '@shared/models/widget.models';
import {
FormattedData,
mapItemTooltipsTranslation,
MapItemType,
WidgetAction,
WidgetActionType,
widgetType
} from '@shared/models/widget.models';
import { EntityDataPageLink } from '@shared/models/query/query.models';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import { TbMarkersDataLayer } from '@home/components/widget/lib/maps/data-layer/markers-data-layer';
@ -661,29 +668,45 @@ export abstract class TbMap<S extends BaseMapSettings> {
private createMarker(actionData: PlaceMapItemActionData) {
this.createItem(actionData, () => this.prepareDrawMode('Marker', {
placeMarker: this.ctx.translate.instant('widgets.maps.data-layer.marker.place-marker-hint')
placeMarker: actionData.action.mapItemTooltips.placeMarker
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.placeMarker)
: this.ctx.translate.instant(mapItemTooltipsTranslation.placeMarker)
}));
}
private createRectangle(actionData: PlaceMapItemActionData): void {
this.createItem(actionData, () => this.prepareDrawMode('Rectangle', {
firstVertex: this.ctx.translate.instant('widgets.maps.data-layer.polygon.rectangle-place-first-point-hint'),
finishRect: this.ctx.translate.instant('widgets.maps.data-layer.polygon.finish-rectangle-hint')
firstVertex: actionData.action.mapItemTooltips.startRect
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.startRect)
: this.ctx.translate.instant(mapItemTooltipsTranslation.startRect),
finishRect: actionData.action.mapItemTooltips.finishRect
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.finishRect)
: this.ctx.translate.instant(mapItemTooltipsTranslation.finishRect),
}));
}
private createPolygon(actionData: PlaceMapItemActionData): void {
this.createItem(actionData, () => this.prepareDrawMode('Polygon', {
firstVertex: this.ctx.translate.instant('widgets.maps.data-layer.polygon.polygon-place-first-point-hint'),
continueLine: this.ctx.translate.instant('widgets.maps.data-layer.polygon.continue-polygon-hint'),
finishPoly: this.ctx.translate.instant('widgets.maps.data-layer.polygon.finish-polygon-hint')
firstVertex: actionData.action.mapItemTooltips.firstVertex
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.firstVertex)
: this.ctx.translate.instant(mapItemTooltipsTranslation.firstVertex),
continueLine: actionData.action.mapItemTooltips.continueLine
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.continueLine)
: this.ctx.translate.instant(mapItemTooltipsTranslation.continueLine),
finishPoly: actionData.action.mapItemTooltips.finishPoly
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.finishPoly)
: this.ctx.translate.instant(mapItemTooltipsTranslation.finishPoly),
}));
}
private createCircle(actionData: PlaceMapItemActionData): void {
this.createItem(actionData, () => this.prepareDrawMode('Circle', {
startCircle: this.ctx.translate.instant('widgets.maps.data-layer.circle.place-circle-center-hint'),
finishCircle: this.ctx.translate.instant('widgets.maps.data-layer.circle.finish-circle-hint')
startCircle: actionData.action.mapItemTooltips.startCircle
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.startCircle)
: this.ctx.translate.instant(mapItemTooltipsTranslation.startCircle),
finishCircle: actionData.action.mapItemTooltips.finishCircle
? this.ctx.utilsService.customTranslation(actionData.action.mapItemTooltips.finishCircle)
: this.ctx.translate.instant(mapItemTooltipsTranslation.finishCircle),
}));
}

82
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/map-item-tooltips.component.html

@ -0,0 +1,82 @@
<!--
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.
-->
<div class="tb-form-panel stroked" [formGroup]="tooltipsForm">
<mat-expansion-panel class="tb-settings">
<mat-expansion-panel-header>{{ 'widget-action.map-item-tooltip.tooltips' | translate }}</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
@switch (mapItemType) {
@case (MapItemType.marker) {
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.place-marker</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.placeMarker | translate }}" formControlName="placeMarker">
</mat-form-field>
</div>
}
@case (MapItemType.rectangle) {
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.start-draw-rectangle</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.startRect | translate }}" formControlName="startRect">
</mat-form-field>
</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.finish-draw-rectangle</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.finishRect | translate }}" formControlName="finishRect">
</mat-form-field>
</div>
}
@case (MapItemType.polygon) {
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.start-draw-polygon</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.firstVertex | translate }}" formControlName="firstVertex">
</mat-form-field>
</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.continue-draw-polygon</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.continueLine | translate }}" formControlName="continueLine">
</mat-form-field>
</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.finish-draw-polygon</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.finishPoly | translate }}" formControlName="finishPoly">
</mat-form-field>
</div>
}
@case (MapItemType.circle) {
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.start-draw-circle</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.startCircle | translate }}" formControlName="startCircle">
</mat-form-field>
</div>
<div class="tb-form-row">
<div class="fixed-title-width" translate>widget-action.map-item-tooltip.finish-draw-circle</div>
<mat-form-field class="flex-1" appearance="outline" subscriptSizing="dynamic">
<input matInput placeholder="{{ mapItemTooltipsDefaultTranslate.finishCircle | translate }}" formControlName="finishCircle">
</mat-form-field>
</div>
}
}
</ng-template>
</mat-expansion-panel>
</div>

123
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/map-item-tooltips.component.ts

@ -0,0 +1,123 @@
///
/// 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, forwardRef, Input, OnChanges, SimpleChanges } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MapItemTooltips, MapItemType, mapItemTooltipsTranslation } from '@shared/models/widget.models';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { deepTrim, isEqual } from '@core/utils';
@Component({
selector: 'tb-map-item-tooltips',
templateUrl: './map-item-tooltips.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MapItemTooltipsComponent),
multi: true
}
]
})
export class MapItemTooltipsComponent implements ControlValueAccessor, OnChanges {
@Input({required: true})
mapItemType: MapItemType;
tooltipsForm: FormGroup;
MapItemType = MapItemType;
readonly mapItemTooltipsDefaultTranslate = mapItemTooltipsTranslation;
private modelValue: MapItemTooltips;
private propagateChange = (_val: any) => {};
constructor(private fd: FormBuilder) {
this.tooltipsForm = this.fd.group({
placeMarker: [''],
firstVertex: [''],
continueLine: [''],
finishPoly: [''],
startRect: [''],
finishRect: [''],
startCircle: [''],
finishCircle: ['']
});
this.tooltipsForm.valueChanges.pipe(
takeUntilDestroyed()
).subscribe(this.updatedModel.bind(this));
}
ngOnChanges(changes: SimpleChanges) {
if (changes.mapItemType) {
const mapItemTypeChanges = changes.mapItemType;
if (!mapItemTypeChanges.firstChange && mapItemTypeChanges.currentValue !== mapItemTypeChanges.previousValue) {
this.updatedValidators(true);
}
}
}
registerOnChange(fn: any) {
this.propagateChange = fn;
}
registerOnTouched(_fn: any) {
}
setDisabledState(isDisabled: boolean) {
if (isDisabled) {
this.tooltipsForm.disable({emitEvent: false});
} else {
this.tooltipsForm.enable({emitEvent: false});
}
}
writeValue(obj: MapItemTooltips) {
this.modelValue = obj;
this.tooltipsForm.patchValue(obj, {emitEvent: false});
this.updatedValidators();
}
private updatedValidators(emitNewValue = false) {
this.tooltipsForm.disable({emitEvent: false});
switch (this.mapItemType) {
case MapItemType.marker:
this.tooltipsForm.get('placeMarker').enable({emitEvent: false});
break;
case MapItemType.rectangle:
this.tooltipsForm.get('startRect').enable({emitEvent: false});
this.tooltipsForm.get('finishRect').enable({emitEvent: false});
break;
case MapItemType.polygon:
this.tooltipsForm.get('firstVertex').enable({emitEvent: false});
this.tooltipsForm.get('continueLine').enable({emitEvent: false});
this.tooltipsForm.get('finishPoly').enable({emitEvent: false});
break;
case MapItemType.circle:
this.tooltipsForm.get('startCircle').enable({emitEvent: false});
this.tooltipsForm.get('finishCircle').enable({emitEvent: false});
break;
}
this.tooltipsForm.updateValueAndValidity({emitEvent: emitNewValue})
}
private updatedModel(value: MapItemTooltips) {
const currentValue = Object.fromEntries(Object.entries(deepTrim(value)).filter(([_, v]) => v != ''));
if (!isEqual(currentValue, this.modelValue)) {
this.modelValue = currentValue;
this.propagateChange(currentValue);
}
}
}

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.html

@ -270,6 +270,10 @@
</mat-select>
</mat-form-field>
</div>
<tb-map-item-tooltips
[mapItemType]="actionTypeFormGroup.get('mapItemType').value"
formControlName="mapItemTooltips">
</tb-map-item-tooltips>
</ng-template>
<ng-template [ngSwitchCase]="widgetActionFormGroup.get('type').value === widgetActionType.customPretty
|| widgetActionFormGroup.get('type').value === widgetActionType.placeMapItem

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts

@ -329,6 +329,7 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali
'mapItemType',
this.fb.control(action?.mapItemType ?? MapItemType.marker, [Validators.required])
);
this.actionTypeFormGroup.addControl('mapItemTooltips', this.fb.control(action?.mapItemTooltips ?? {}));
this.actionTypeFormGroup.addControl(
'customAction',
this.fb.control(toPlaceMapItemAction(action), [Validators.required])
@ -528,7 +529,8 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali
result = {
...this.widgetActionFormGroup.value,
...this.actionTypeFormGroup.get('customAction').value,
mapItemType: this.actionTypeFormGroup.get('mapItemType').value
mapItemType: this.actionTypeFormGroup.get('mapItemType').value,
mapItemTooltips: this.actionTypeFormGroup.get('mapItemTooltips').value,
};
} else {
result = {...this.widgetActionFormGroup.value, ...this.actionTypeFormGroup.value};

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts

@ -69,6 +69,9 @@ import {
} from '@home/components/widget/lib/settings/common/action/set-value-action-settings-panel.component';
import { CssSizeInputComponent } from '@home/components/widget/lib/settings/common/css-size-input.component';
import { WidgetActionComponent } from '@home/components/widget/lib/settings/common/action/widget-action.component';
import {
MapItemTooltipsComponent
} from '@home/components/widget/lib/settings/common/action/map-item-tooltips.component';
import {
CustomActionPrettyResourcesTabsComponent
} from '@home/components/widget/lib/settings/common/action/custom-action-pretty-resources-tabs.component';
@ -283,6 +286,7 @@ import {
SetValueActionSettingsComponent,
SetValueActionSettingsPanelComponent,
WidgetActionComponent,
MapItemTooltipsComponent,
CustomActionPrettyResourcesTabsComponent,
CustomActionPrettyEditorComponent,
MobileActionEditorComponent,

25
ui-ngx/src/app/shared/models/widget.models.ts

@ -770,7 +770,30 @@ export interface WidgetAction extends CustomActionDescriptor {
mobileAction?: WidgetMobileActionDescriptor;
url?: string;
mapItemType?: MapItemType;
}
mapItemTooltips?: MapItemTooltips;
}
export interface MapItemTooltips {
placeMarker?: string;
firstVertex?: string;
continueLine?: string;
finishPoly?: string;
startRect?: string;
finishRect?: string;
startCircle?: string;
finishCircle?: string;
}
export const mapItemTooltipsTranslation: Required<MapItemTooltips> = Object.freeze({
placeMarker: 'widgets.maps.data-layer.marker.place-marker-hint',
firstVertex: 'widgets.maps.data-layer.polygon.polygon-place-first-point-hint',
continueLine: 'widgets.maps.data-layer.polygon.continue-polygon-hint',
finishPoly: 'widgets.maps.data-layer.polygon.finish-polygon-hint',
startRect: 'widgets.maps.data-layer.polygon.rectangle-place-first-point-hint',
finishRect: 'widgets.maps.data-layer.polygon.finish-rectangle-hint',
startCircle: 'widgets.maps.data-layer.circle.place-circle-center-hint',
finishCircle: 'widgets.maps.data-layer.circle.finish-circle-hint'
})
export interface WidgetActionDescriptor extends WidgetAction {
id: string;

13
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -6592,7 +6592,18 @@
"rectangle": "Rectangle",
"circle": "Circle"
},
"place-map-item": "Place map item"
"place-map-item": "Place map item",
"map-item-tooltip": {
"tooltips": "Map item tooltips",
"place-marker": "Place marker",
"start-draw-rectangle": "Start draw rectangle",
"finish-draw-rectangle": "Finish draw rectangle",
"start-draw-polygon": "Start draw polygon",
"continue-draw-polygon": "Continue draw polygon",
"finish-draw-polygon": "Finish draw polygon",
"start-draw-circle": "Start draw circle",
"finish-draw-circle": "Finish draw circle"
}
},
"widgets-bundle": {
"current": "Current bundle",

Loading…
Cancel
Save