thingsboard/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts

222 lines
7.4 KiB
TypeScript

///
/// Copyright © 2016-2021 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, Input, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { WidgetContext } from '@home/models/widget-component.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core';
import { Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models';
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { AttributeService } from '@core/http/attribute.service';
import { AttributeData, AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { EntityId } from '@shared/models/id/entity-id';
import { EntityType } from '@shared/models/entity-type.models';
import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils';
import { Observable } from 'rxjs';
enum JsonInputWidgetMode {
ATTRIBUTE = 'ATTRIBUTE',
TIME_SERIES = 'TIME_SERIES',
}
interface JsonInputWidgetSettings {
widgetTitle: string;
widgetMode: JsonInputWidgetMode;
attributeScope?: AttributeScope;
showLabel: boolean;
labelValue?: string;
attributeRequired: boolean;
showResultMessage: boolean;
}
@Component({
selector: 'tb-json-input-widget ',
templateUrl: './json-input-widget.component.html',
styleUrls: ['./json-input-widget.component.scss']
})
export class JsonInputWidgetComponent extends PageComponent implements OnInit {
@Input()
ctx: WidgetContext;
public settings: JsonInputWidgetSettings;
private widgetConfig: WidgetConfig;
private subscription: IWidgetSubscription;
private datasource: Datasource;
labelValue: string;
datasourceDetected = false;
errorMessage: string;
isFocused: boolean;
originalValue: any;
attributeUpdateFormGroup: FormGroup;
toastTargetId = 'json-input-widget' + this.utils.guid();
constructor(protected store: Store<AppState>,
private utils: UtilsService,
private fb: FormBuilder,
private attributeService: AttributeService,
private translate: TranslateService) {
super(store);
}
ngOnInit(): void {
this.ctx.$scope.jsonInputWidget = this;
this.settings = this.ctx.settings;
this.widgetConfig = this.ctx.widgetConfig;
this.subscription = this.ctx.defaultSubscription;
this.datasource = this.subscription.datasources[0];
this.initializeConfig();
this.validateDatasources();
this.buildForm();
this.ctx.updateWidgetParams();
}
private initializeConfig() {
if (this.settings.widgetTitle && this.settings.widgetTitle.length) {
const title = createLabelFromDatasource(this.datasource, this.settings.widgetTitle);
this.ctx.widgetTitle = this.utils.customTranslation(title, title);
} else {
this.ctx.widgetTitle = this.ctx.widgetConfig.title;
}
if (this.settings.labelValue && this.settings.labelValue.length) {
const label = createLabelFromDatasource(this.datasource, this.settings.labelValue);
this.labelValue = this.utils.customTranslation(label, label);
} else {
this.labelValue = this.translate.instant('widgets.input-widgets.value');
}
}
private validateDatasources() {
this.datasourceDetected = isDefinedAndNotNull(this.datasource);
if (!this.datasourceDetected) {
return;
}
if (this.datasource.type === DatasourceType.entity) {
if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) {
if (this.datasource.dataKeys[0].type === DataKeyType.attribute) {
if (this.settings.attributeScope !== AttributeScope.SERVER_SCOPE && this.datasource.entityType !== EntityType.DEVICE) {
this.errorMessage = 'widgets.input-widgets.not-allowed-entity';
}
} else {
this.errorMessage = 'widgets.input-widgets.no-attribute-selected';
}
} else {
if (this.datasource.dataKeys[0].type !== DataKeyType.timeseries) {
this.errorMessage = 'widgets.input-widgets.no-timeseries-selected';
}
}
} else {
this.errorMessage = 'widgets.input-widgets.no-entity-selected';
}
}
private buildForm() {
const validators: ValidatorFn[] = [];
if (this.settings.attributeRequired) {
validators.push(Validators.required);
}
this.attributeUpdateFormGroup = this.fb.group({
currentValue: [{}, validators]
});
this.attributeUpdateFormGroup.valueChanges.subscribe(() => {
this.ctx.detectChanges();
});
}
private updateWidgetData(data: Array<DatasourceData>) {
if (!this.errorMessage) {
let value = {};
if (data[0].data[0][1] !== '') {
try {
value = JSON.parse(data[0].data[0][1]);
} catch (e) {
value = data[0].data[0][1];
}
}
this.originalValue = value;
if (!this.isFocused) {
this.attributeUpdateFormGroup.get('currentValue').patchValue(this.originalValue);
this.ctx.detectChanges();
}
}
}
public onDataUpdated() {
this.updateWidgetData(this.subscription.data);
}
public save() {
this.isFocused = false;
const attributeToSave: AttributeData = {
key: this.datasource.dataKeys[0].name,
value: this.attributeUpdateFormGroup.get('currentValue').value
};
const entityId: EntityId = {
entityType: this.datasource.entityType,
id: this.datasource.entityId
};
let saveAttributeObservable: Observable<any>;
if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) {
saveAttributeObservable = this.attributeService.saveEntityAttributes(
entityId,
this.settings.attributeScope,
[attributeToSave],
{}
);
} else {
saveAttributeObservable = this.attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
[attributeToSave],
{}
);
}
saveAttributeObservable.subscribe(
() => {
this.attributeUpdateFormGroup.markAsPristine();
this.ctx.detectChanges();
if (this.settings.showResultMessage) {
this.ctx.showSuccessToast(this.translate.instant('widgets.input-widgets.update-successful'),
1000, 'bottom', 'left', this.toastTargetId);
}
},
() => {
if (this.settings.showResultMessage) {
this.ctx.showErrorToast(this.translate.instant('widgets.input-widgets.update-failed'),
'bottom', 'left', this.toastTargetId);
}
});
}
public discard() {
this.attributeUpdateFormGroup.reset({currentValue: this.originalValue}, {emitEvent: false});
this.attributeUpdateFormGroup.markAsPristine();
this.isFocused = false;
}
}