diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts index 1b63e97ad6..40f1a6c819 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/custom-action.models.ts @@ -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); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw new file mode 100644 index 0000000000..bb36a39986 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-html.raw @@ -0,0 +1,82 @@ + + + + +
+ +

Add entity

+ + +
+ + +
+
+
+ + Entity Name + + + Entity name is required. + + + + Entity Label + + +
+
+ + + +
+
+
+ + Address + + + + Owner + + +
+
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw new file mode 100644 index 0000000000..cb8c23faee --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/place-map-item-sample-js.raw @@ -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; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts index 932c0e52c3..bd0fe36910 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/widget-action.component.ts @@ -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; } diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html index c85fc4eb21..b21734cfdd 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.html @@ -15,9 +15,9 @@ limitations under the License. --> - + {{ 'entity.type' | translate }} - + {{ displayEntityTypeFn(type) }} diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts index 773222dcec..82b3fcf572 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-type-select.component.ts @@ -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} = {};