added code for note widget

This commit is contained in:
Nico Melone
2023-01-17 23:06:23 -06:00
parent 8ed2c1510c
commit e1e1314f1f
9 changed files with 600 additions and 2 deletions

BIN
Widgets/.DS_Store vendored

Binary file not shown.

View File

@@ -0,0 +1,31 @@
<form [formGroup]="editEntity" (ngSubmit)="save()" class="edit-entity-form">
<mat-toolbar fxLayout="row" color="primary">
<h2>New Note</h2>
<span fxFlex></span>
<button mat-icon-button (click)="cancel()" type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async) && !loading"></div>
<div mat-dialog-content fxLayout="column">
<div formGroupName="attributes" fxLayout="column">
<textarea formControlName="note" rows="5" cols="50"></textarea>
</div>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<button mat-button mat-raised-button color="primary"
type="submit"
[disabled]="(isLoading$ | async) || editEntity.invalid || !editEntity.dirty">
Save
</button>
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
Cancel
</button>
</div>
</form>

90
Widgets/notes/addNote.js Normal file
View File

@@ -0,0 +1,90 @@
let $injector = widgetContext.$scope.$injector;
let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
let assetService = $injector.get(widgetContext.servicesMap.get('assetService'));
let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
let entityService = $injector.get(widgetContext.servicesMap.get('entityService'));
console.log(widgetContext);
openAddEntityDialog();
function openAddEntityDialog() {
customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe(() => {});
}
function AddEntityDialogController(instance) {
let vm = instance;
vm.entityName = entityName;
vm.attributes = {};
vm.timeseries = {};
vm.editEntity = vm.fb.group({
attributes: vm.fb.group({
note: ""
})
});
getEntityInfo();
vm.cancel = function() {
vm.dialogRef.close(null);
};
vm.save = function() {
vm.loading = true;
saveAttributes(entityId).subscribe(
() => {
vm.dialogRef.close(null);
}, () =>{
vm.loading = false;
}
);
};
function getEntityAttributes(attributes) {
for (var i = 0; i < attributes.length; i++) {
vm.attributes[attributes[i].key] = attributes[i].value;
}
}
function getEntityInfo() {
vm.loading = true;
attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE').subscribe(
function (data) {
console.log(data);
getEntityAttributes(data);
vm.editEntity.patchValue({
attributes: vm.attributes
}, {emitEvent: false});
vm.loading = false;
}
);
/*attributeService.getEntityTimeseries(entityId, ["LOGS"],Date.now() - 24*60*60*1000, Date.now() ).subscribe(
function (data) {
console.log(data);
//getEntityTimeseries(data);
vm.editEntity.patchValue({
timeseries: vm.timeseries
}, {emitEvent: false});
vm.loading = false;
}
);*/
}
function saveAttributes(entityId) {
let attributes = vm.editEntity.get('attributes').value;
let attributesArray = [];
for (let key in attributes) {
if (attributes[key] !== vm.attributes[key]) {
attributesArray.push({key: key, value: attributes[key]});
}
}
/*if (attributesArray.length > 0) {
return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
}*/
return attributeService.saveEntityTimeseries(entityId,"ANY", [{"lastUpdateTs": Date.now(), "key": widgetContext.datasources[0].dataKeys[0].name, "value": attributes.note}] );
//return widgetContext.rxjs.of([]);
}
}

187
Widgets/notes/editNote.html Normal file
View File

@@ -0,0 +1,187 @@
<form #editEntityForm="ngForm" [formGroup]="editEntityFormGroup"
(ngSubmit)="save()" class="edit-entity-form">
<mat-toolbar fxLayout="row" color="primary">
<h2>Edit {{entityType.toLowerCase()}} {{entityName}}</h2>
<span fxFlex></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 fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field fxFlex class="mat-block">
<mat-label>Entity Name</mat-label>
<input matInput formControlName="entityName" required readonly="">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label>Entity Label</mat-label>
<input matInput formControlName="entityLabel">
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field fxFlex class="mat-block">
<mat-label>Entity Type</mat-label>
<input matInput formControlName="entityType" readonly>
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label>Type</mat-label>
<input matInput formControlName="type" readonly>
</mat-form-field>
</div>
<div formGroupName="attributes" fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field fxFlex class="mat-block">
<mat-label>Latitude</mat-label>
<input type="number" step="any" matInput formControlName="latitude">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label>Longitude</mat-label>
<input type="number" step="any" matInput formControlName="longitude">
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field fxFlex class="mat-block">
<mat-label>Address</mat-label>
<input matInput formControlName="address">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label>Owner</mat-label>
<input matInput formControlName="owner">
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field fxFlex class="mat-block">
<mat-label>Integer Value</mat-label>
<input type="number" step="1" matInput formControlName="number">
<mat-error *ngIf="editEntityFormGroup.get('attributes.number').hasError('pattern')">
Invalid integer value.
</mat-error>
</mat-form-field>
<div class="boolean-value-input" fxLayout="column" fxLayoutAlign="center start" fxFlex>
<label class="checkbox-label">Boolean Value</label>
<mat-checkbox formControlName="booleanValue" style="margin-bottom: 40px;">
{{ (editEntityFormGroup.get('attributes.booleanValue').value ? "value.true" : "value.false") | translate }}
</mat-checkbox>
</div>
</div>
</div>
<div class="relations-list old-relations">
<div class="mat-body-1" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);">Relations</div>
<div class="body" [fxShow]="oldRelations().length">
<div class="row" fxLayout="row" fxLayoutAlign="start center" formArrayName="oldRelations"
*ngFor="let relation of oldRelations().controls; let i = index;">
<div [formGroupName]="i" class="mat-elevation-z2" fxFlex fxLayout="row" style="padding: 5px 0 5px 5px;">
<div fxFlex fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field class="mat-block" style="min-width: 100px;">
<mat-label>Direction</mat-label>
<mat-select formControlName="direction" name="direction">
<mat-option *ngFor="let direction of entitySearchDirection | keyvalue" [value]="direction.value">
{{ ("relation.search-direction." + direction.value) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="relation.get('direction').hasError('required')">
Relation direction is required.
</mat-error>
</mat-form-field>
<tb-relation-type-autocomplete
fxFlex class="mat-block"
formControlName="relationType"
required="true">
</tb-relation-type-autocomplete>
</div>
<div fxLayout="row" fxLayout.xs="column">
<tb-entity-select
fxFlex class="mat-block"
required="true"
formControlName="relatedEntity">
</tb-entity-select>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center center">
<button mat-icon-button color="primary"
aria-label="Remove"
type="button"
(click)="removeOldRelation(i)"
matTooltip="Remove relation"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="relations-list">
<div class="mat-body-1" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);">New Relations</div>
<div class="body" [fxShow]="relations().length">
<div class="row" fxLayout="row" fxLayoutAlign="start center" formArrayName="relations" *ngFor="let relation of relations().controls; let i = index;">
<div [formGroupName]="i" class="mat-elevation-z2" fxFlex fxLayout="row" style="padding: 5px 0 5px 5px;">
<div fxFlex fxLayout="column">
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column" fxLayoutGap.xs="0">
<mat-form-field class="mat-block" style="min-width: 100px;">
<mat-label>Direction</mat-label>
<mat-select formControlName="direction" name="direction">
<mat-option *ngFor="let direction of entitySearchDirection | keyvalue" [value]="direction.value">
{{ ("relation.search-direction." + direction.value) | translate}}
</mat-option>
</mat-select>
<mat-error *ngIf="relation.get('direction').hasError('required')">
Relation direction is required.
</mat-error>
</mat-form-field>
<tb-relation-type-autocomplete
fxFlex class="mat-block"
formControlName="relationType"
[required]="true">
</tb-relation-type-autocomplete>
</div>
<div fxLayout="row" fxLayout.xs="column">
<tb-entity-select
fxFlex class="mat-block"
[required]="true"
formControlName="relatedEntity">
</tb-entity-select>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center center">
<button mat-icon-button color="primary"
aria-label="Remove"
type="button"
(click)="removeRelation(i)"
matTooltip="Remove relation"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
</div>
</div>
</div>
<div>
<button mat-raised-button color="primary"
type="button"
(click)="addRelation()"
matTooltip="Add Relation"
matTooltipPosition="above">
Add
</button>
</div>
</div>
</div>
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
<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) || editEntityForm.invalid || !editEntityForm.dirty">
Save
</button>
</div>
</form>

216
Widgets/notes/editNote.js Normal file
View File

@@ -0,0 +1,216 @@
let $injector = widgetContext.$scope.$injector;
let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
let entityService = $injector.get(widgetContext.servicesMap.get('entityService'));
let assetService = $injector.get(widgetContext.servicesMap.get('assetService'));
let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
let entityRelationService = $injector.get(widgetContext.servicesMap.get('entityRelationService'));
openEditEntityDialog();
function openEditEntityDialog() {
customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();
}
function EditEntityDialogController(instance) {
let vm = instance;
vm.entityName = entityName;
vm.entityType = entityId.entityType;
vm.entitySearchDirection = {
from: "FROM",
to: "TO"
};
vm.attributes = {};
vm.oldRelationsData = [];
vm.relationsToDelete = [];
vm.entity = {};
vm.editEntityFormGroup = vm.fb.group({
entityName: ['', [vm.validators.required]],
entityType: [null],
entityLabel: [null],
type: ['', [vm.validators.required]],
attributes: vm.fb.group({
latitude: [null],
longitude: [null],
address: [null],
owner: [null],
number: [null, [vm.validators.pattern(/^-?[0-9]+$/)]],
booleanValue: [false]
}),
oldRelations: vm.fb.array([]),
relations: vm.fb.array([])
});
getEntityInfo();
vm.cancel = function() {
vm.dialogRef.close(null);
};
vm.relations = function() {
return vm.editEntityFormGroup.get('relations');
};
vm.oldRelations = function() {
return vm.editEntityFormGroup.get('oldRelations');
};
vm.addRelation = function() {
vm.relations().push(vm.fb.group({
relatedEntity: [null, [vm.validators.required]],
relationType: [null, [vm.validators.required]],
direction: [null, [vm.validators.required]]
}));
};
function addOldRelation() {
vm.oldRelations().push(vm.fb.group({
relatedEntity: [{value: null, disabled: true}, [vm.validators.required]],
relationType: [{value: null, disabled: true}, [vm.validators.required]],
direction: [{value: null, disabled: true}, [vm.validators.required]]
}));
}
vm.removeRelation = function(index) {
vm.relations().removeAt(index);
vm.relations().markAsDirty();
};
vm.removeOldRelation = function(index) {
vm.oldRelations().removeAt(index);
vm.relationsToDelete.push(vm.oldRelationsData[index]);
vm.oldRelations().markAsDirty();
};
vm.save = function() {
vm.editEntityFormGroup.markAsPristine();
widgetContext.rxjs.forkJoin([
saveAttributes(entityId),
saveRelations(entityId),
saveEntity()
]).subscribe(
function () {
widgetContext.updateAliases();
vm.dialogRef.close(null);
}
);
};
function getEntityAttributes(attributes) {
for (var i = 0; i < attributes.length; i++) {
vm.attributes[attributes[i].key] = attributes[i].value;
}
}
function getEntityRelations(relations) {
let relationsFrom = relations[0];
let relationsTo = relations[1];
for (let i=0; i < relationsFrom.length; i++) {
let relation = {
direction: 'FROM',
relationType: relationsFrom[i].type,
relatedEntity: relationsFrom[i].to
};
vm.oldRelationsData.push(relation);
addOldRelation();
}
for (let i=0; i < relationsTo.length; i++) {
let relation = {
direction: 'TO',
relationType: relationsTo[i].type,
relatedEntity: relationsTo[i].from
};
vm.oldRelationsData.push(relation);
addOldRelation();
}
}
function getEntityInfo() {
widgetContext.rxjs.forkJoin([
entityRelationService.findInfoByFrom(entityId),
entityRelationService.findInfoByTo(entityId),
attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE'),
entityService.getEntity(entityId.entityType, entityId.id)
]).subscribe(
function (data) {
getEntityRelations(data.slice(0,2));
getEntityAttributes(data[2]);
vm.entity = data[3];
vm.editEntityFormGroup.patchValue({
entityName: vm.entity.name,
entityType: vm.entityType,
entityLabel: vm.entity.label,
type: vm.entity.type,
attributes: vm.attributes,
oldRelations: vm.oldRelationsData
}, {emitEvent: false});
}
);
}
function saveEntity() {
const formValues = vm.editEntityFormGroup.value;
if (vm.entity.label !== formValues.entityLabel){
vm.entity.label = formValues.entityLabel;
if (formValues.entityType == 'ASSET') {
return assetService.saveAsset(vm.entity);
} else if (formValues.entityType == 'DEVICE') {
return deviceService.saveDevice(vm.entity);
}
}
return widgetContext.rxjs.of([]);
}
function saveAttributes(entityId) {
let attributes = vm.editEntityFormGroup.get('attributes').value;
let attributesArray = [];
for (let key in attributes) {
if (attributes[key] !== vm.attributes[key]) {
attributesArray.push({key: key, value: attributes[key]});
}
}
if (attributesArray.length > 0) {
return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
}
return widgetContext.rxjs.of([]);
}
function saveRelations(entityId) {
let relations = vm.editEntityFormGroup.get('relations').value;
let tasks = [];
for(let i=0; i < relations.length; i++) {
let relation = {
type: relations[i].relationType,
typeGroup: 'COMMON'
};
if (relations[i].direction == 'FROM') {
relation.to = relations[i].relatedEntity;
relation.from = entityId;
} else {
relation.to = entityId;
relation.from = relations[i].relatedEntity;
}
tasks.push(entityRelationService.saveRelation(relation));
}
for (let i=0; i < vm.relationsToDelete.length; i++) {
let relation = {
type: vm.relationsToDelete[i].relationType
};
if (vm.relationsToDelete[i].direction == 'FROM') {
relation.to = vm.relationsToDelete[i].relatedEntity;
relation.from = entityId;
} else {
relation.to = entityId;
relation.from = vm.relationsToDelete[i].relatedEntity;
}
tasks.push(entityRelationService.deleteRelation(relation.from, relation.type, relation.to));
}
if (tasks.length > 0) {
return widgetContext.rxjs.forkJoin(tasks);
}
return widgetContext.rxjs.of([]);
}
}