Merge pull request #13084 from vvlladd28/improvement/action/place-map-item/tooltips
Add to place map item action - customize tooltip
This commit is contained in:
commit
ad7905f393
@ -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);
|
||||
|
||||
@ -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),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@ -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.customize-map-item-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>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -770,8 +770,31 @@ 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;
|
||||
name: string;
|
||||
|
||||
@ -6592,7 +6592,18 @@
|
||||
"rectangle": "Rectangle",
|
||||
"circle": "Circle"
|
||||
},
|
||||
"place-map-item": "Place map item"
|
||||
"place-map-item": "Place map item",
|
||||
"map-item-tooltip": {
|
||||
"customize-map-item-tooltips": "Customize 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…
x
Reference in New Issue
Block a user