UI: Add new predefined example when created action place map item

This commit is contained in:
Vladyslav_Prykhodko 2025-03-19 12:04:34 +02:00
parent c9ef125911
commit c25b57eb39
6 changed files with 192 additions and 4 deletions

View File

@ -22,6 +22,8 @@ import { deepClone, isDefined, isUndefined } from '@core/utils';
import customSampleJs from './custom-sample-js.raw';
import customSampleCss from './custom-sample-css.raw';
import customSampleHtml from './custom-sample-html.raw';
import placeMapItemSampleHtml from './place-map-item-sample-html.raw';
import placeMapItemSampleJs from './place-map-item-sample-js.raw';
const customActionCompletions: TbEditorCompletions = {
...{
@ -96,5 +98,15 @@ export const toCustomAction = (action: WidgetAction): CustomActionDescriptor =>
return result;
};
export const toPlaceMapItemAction = (action: WidgetAction): CustomActionDescriptor => {
const result: CustomActionDescriptor = {
customHtml: action?.customHtml ?? placeMapItemSampleHtml,
customCss: action?.customCss ?? '',
customFunction: action?.customFunction ?? placeMapItemSampleJs
};
result.customResources = isDefined(action?.customResources) ? deepClone(action.customResources) : [];
return result;
};
export const CustomActionEditorCompleter = new TbEditorCompleter(customActionCompletions);
export const CustomPrettyActionEditorCompleter = new TbEditorCompleter(customPrettyActionCompletions);

View File

@ -0,0 +1,82 @@
<!--========================================================================-->
<!--========================= Add entity example =========================-->
<!--========================================================================-->
<form #addEntityForm="ngForm" [formGroup]="addEntityFormGroup"
(ngSubmit)="save()" style="width: 552px">
<mat-toolbar class="flex flex-row" color="primary">
<h2>Add entity</h2>
<span class="flex-1"></span>
<button mat-icon-button (click)="cancel()" type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content class="flex flex-col" style="padding-bottom: 0">
<div class="flex flex-row gap-2 xs:flex-col xs:gap-0">
<mat-form-field class="mat-block flex-1" appearance="outline">
<mat-label>Entity Name</mat-label>
<input matInput formControlName="entityName" required>
<mat-error *ngIf="addEntityFormGroup.get('entityName').hasError('required')">
Entity name is required.
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block flex-1" appearance="outline">
<mat-label>Entity Label</mat-label>
<input matInput formControlName="entityLabel" >
</mat-form-field>
</div>
<div class="flex flex-row gap-2 xs:flex-col xs:gap-0">
<tb-entity-type-select
class="mat-block flex-1"
formControlName="entityType"
[showLabel]="true"
[appearance]="'outline'"
[allowedEntityTypes]="allowedEntityTypes"
></tb-entity-type-select>
<tb-entity-subtype-autocomplete
*ngIf="addEntityFormGroup.get('entityType').value == 'ASSET'"
class="mat-block flex-1"
formControlName="type"
[required]="true"
[entityType]="'ASSET'"
[appearance]="'outline'"
></tb-entity-subtype-autocomplete>
<tb-entity-subtype-autocomplete
*ngIf="addEntityFormGroup.get('entityType').value != 'ASSET'"
class="mat-block flex-1"
formControlName="type"
[required]="true"
[entityType]="'DEVICE'"
[appearance]="'outline'"
></tb-entity-subtype-autocomplete>
</div>
<div formGroupName="attributes" class="flex flex-col">
<div class="flex flex-row gap-2 xs:flex-col xs:gap-0">
<mat-form-field class="mat-block flex-1" appearance="outline">
<mat-label>Address</mat-label>
<input matInput formControlName="address">
</mat-form-field>
<mat-form-field class="mat-block flex-1" appearance="outline">
<mat-label>Owner</mat-label>
<input matInput formControlName="owner">
</mat-form-field>
</div>
</div>
</div>
<div mat-dialog-actions class="flex flex-row items-center justify-end">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
Cancel
</button>
<button mat-button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || addEntityForm.invalid || !addEntityForm.dirty">
Create
</button>
</div>
</form>

View File

@ -0,0 +1,89 @@
/*========================================================================*/
/*========================= Add entity example =========================*/
/*========================================================================*/
let $injector = widgetContext.$scope.$injector;
let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
let assetService = $injector.get(widgetContext.servicesMap.get('assetService'));
let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
openAddEntityDialog();
function openAddEntityDialog() {
customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();
}
function AddEntityDialogController(instance) {
let vm = instance;
vm.allowedEntityTypes = ['ASSET', 'DEVICE'];
vm.addEntityFormGroup = vm.fb.group({
entityName: ['', [vm.validators.required]],
entityType: ['DEVICE'],
entityLabel: [null],
type: ['', [vm.validators.required]],
attributes: vm.fb.group({
address: [null],
owner: [null]
})
});
vm.cancel = function() {
vm.dialogRef.close(null);
};
vm.save = function() {
vm.addEntityFormGroup.markAsPristine();
saveEntityObservable().pipe(
widgetContext.rxjs.switchMap((entity) => saveAttributes(entity.id))
).subscribe(() => {
widgetContext.updateAliases();
vm.dialogRef.close(null);
});
};
function saveEntityObservable() {
const formValues = vm.addEntityFormGroup.value;
let entity = {
name: formValues.entityName,
type: formValues.type,
label: formValues.entityLabel
};
if (formValues.entityType == 'ASSET') {
return assetService.saveAsset(entity);
} else if (formValues.entityType == 'DEVICE') {
return deviceService.saveDevice(entity);
}
}
function saveAttributes(entityId) {
let attributes = vm.addEntityFormGroup.get('attributes').value;
let attributesArray = getMapItemLocationAttributes();
for (let key in attributes) {
if(attributes[key] !== null) {
attributesArray.push({key: key, value: attributes[key]});
}
}
if (attributesArray.length > 0) {
return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
}
return widgetContext.rxjs.of([]);
}
function getMapItemLocationAttributes() {
const attributes = [];
const mapItemType = $event.shape;
if (mapItemType === 'Marker') {
const mapType = widgetContext.mapInstance.type();
attributes.push({key: mapType === 'image' ? 'xPos' : 'latitude', value: additionalParams.coordinates.x});
attributes.push({key: mapType === 'image' ? 'yPos' : 'longitude', value: additionalParams.coordinates.y});
} else if (mapItemType === 'Rectangle' || mapItemType === 'Polygon') {
attributes.push({key: 'perimeter', value: additionalParams.coordinates});
} else if (mapItemType === 'Circle') {
attributes.push({key: 'circle', value: additionalParams.coordinates});
}
return attributes;
}
}

View File

@ -48,7 +48,8 @@ import { TranslateService } from '@ngx-translate/core';
import { PopoverPlacement, PopoverPlacements } from '@shared/components/popover.models';
import {
CustomActionEditorCompleter,
toCustomAction
toCustomAction,
toPlaceMapItemAction
} from '@home/components/widget/lib/settings/common/action/custom-action.models';
import { coerceBoolean } from '@shared/decorators/coercion';
@ -336,7 +337,7 @@ export class WidgetActionComponent implements ControlValueAccessor, OnInit, Vali
);
this.actionTypeFormGroup.addControl(
'customAction',
this.fb.control(toCustomAction(action), [Validators.required])
this.fb.control(toPlaceMapItemAction(action), [Validators.required])
);
break;
}

View File

@ -15,9 +15,9 @@
limitations under the License.
-->
<mat-form-field [formGroup]="entityTypeFormGroup">
<mat-form-field [formGroup]="entityTypeFormGroup" [appearance]="appearance">
<mat-label *ngIf="showLabel">{{ 'entity.type' | translate }}</mat-label>
<mat-select [required]="required" matInput formControlName="entityType">
<mat-select [required]="required" formControlName="entityType">
<mat-option *ngFor="let type of entityTypes" [value]="type">
{{ displayEntityTypeFn(type) }}
</mat-option>

View File

@ -32,6 +32,7 @@ import { AliasEntityType, EntityType, entityTypeTranslations } from '@app/shared
import { EntityService } from '@core/http/entity.service';
import { coerceBoolean } from '@shared/decorators/coercion';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatFormFieldAppearance } from '@angular/material/form-field';
@Component({
selector: 'tb-entity-type-select',
@ -69,6 +70,9 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
@Input()
disabled: boolean;
@Input()
appearance: MatFormFieldAppearance = 'fill';
@Input()
additionEntityTypes: {[key in string]: string} = {};