215 lines
12 KiB
HTML
215 lines
12 KiB
HTML
<!--
|
|
|
|
Copyright © 2016-2023 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.
|
|
|
|
-->
|
|
<form #formContainer class="tb-multiple-input"
|
|
[formGroup]="multipleInputFormGroup"
|
|
tb-toast toastTarget="{{ toastTargetId }}"
|
|
(ngSubmit)="saveForm()" novalidate autocomplete="off">
|
|
<div class="tb-multiple-input-container" *ngIf="entityDetected && isAllParametersValid">
|
|
<fieldset *ngFor="let source of sources" [ngClass]="{'fields-group': settings.showGroupTitle}">
|
|
<legend class="group-title" *ngIf="settings.showGroupTitle">{{ getGroupTitle(source.datasource) }}
|
|
</legend>
|
|
<div class="tb-multiple-input-layout"
|
|
[style]="{'grid-template-columns': 'repeat(' + columns + ', 1fr)', 'column-gap': settings.columnGap + 'px', 'row-gap': settings.rowGap + 'px'}">
|
|
<ng-container *ngFor="let key of visibleKeys(source)">
|
|
<mat-form-field *ngIf="key.settings.dataKeyValueType === 'string'"
|
|
[appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<input matInput
|
|
formControlName="{{key.formId}}"
|
|
[required]="key.settings.required"
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
type="text"
|
|
(focus)="key.isFocused = true; focusInputElement($event)"
|
|
(blur)="key.isFocused = false; inputChanged(source, key)">
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon" matIconPrefix>
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')">
|
|
{{ getErrorMessageText(key.settings, 'required') }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-form-field *ngIf="['double', 'integer'].includes(key.settings.dataKeyValueType)"
|
|
[appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<input matInput
|
|
formControlName="{{key.formId}}"
|
|
[required]="key.settings.required"
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
type="number"
|
|
step="{{key.settings.step}}"
|
|
min="{{key.settings.minValue}}"
|
|
max="{{key.settings.maxValue}}"
|
|
(focus)="key.isFocused = true; focusInputElement($event)"
|
|
(blur)="key.isFocused = false; inputChanged(source, key)">
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon" matIconPrefix>
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')">
|
|
{{ getErrorMessageText(key.settings,'required') }}
|
|
</mat-error>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('min')">
|
|
{{ getErrorMessageText(key.settings,'min') }}
|
|
</mat-error>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('max')">
|
|
{{ getErrorMessageText(key.settings,'max') }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-form-field *ngIf="key.settings.dataKeyValueType === 'JSON'"
|
|
[appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<input
|
|
matInput
|
|
type="text"
|
|
formControlName="{{key.formId}}"
|
|
tb-json-to-string
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
[required]="key.settings.required"
|
|
(focus)="key.isFocused = true; focusInputElement($event)"
|
|
(blur)="key.isFocused = false; inputChanged(source, key)"
|
|
/>
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon" matIconPrefix>
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<button [disabled]="key.settings.isEditable === 'disabled' || key.settings.isEditable === 'readonly'"
|
|
type="button"
|
|
matSuffix mat-icon-button
|
|
(click)="openEditJSONDialog($event, key, source)">
|
|
<mat-icon>open_in_new</mat-icon>
|
|
</button>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required') && !multipleInputFormGroup.get(key.formId).hasError('invalidJSON')">
|
|
{{ getErrorMessageText(key.settings,'required') }}
|
|
</mat-error>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('invalidJSON')">
|
|
{{ getErrorMessageText(key.settings,'invalidJSON') | translate }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-form-field *ngIf="['dateTime','date', 'time'].includes(key.settings.dataKeyValueType)"
|
|
[appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<mat-datetimepicker-toggle [for]="datePicker" matPrefix></mat-datetimepicker-toggle>
|
|
<mat-datetimepicker #datePicker type="{{datePickerType(key.settings.dataKeyValueType)}}"
|
|
openOnFocus="true"></mat-datetimepicker>
|
|
<input matInput formControlName="{{key.formId}}"
|
|
[required]="key.settings.required"
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
[matDatetimepicker]="datePicker"
|
|
(focus)="key.isFocused = true;"
|
|
(blur)="key.isFocused = false;"
|
|
(dateChange)="inputChanged(source, key)">
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')">
|
|
{{ getErrorMessageText(key.settings, 'required') }}
|
|
</mat-error>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('matDatepickerParse')">
|
|
{{ getErrorMessageText(key.settings, 'invalidDate') }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-form-field *ngIf="key.settings.dataKeyValueType === 'select'"
|
|
[appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<mat-select formControlName="{{key.formId}}"
|
|
[required]="key.settings.required"
|
|
(focus)="key.isFocused = true;"
|
|
(selectionChange)="key.isFocused = false; inputChanged(source, key)">
|
|
<mat-option *ngFor="let option of key.settings.selectOptions"
|
|
[value]="option.value"
|
|
[disabled]="key.settings.isEditable === 'readonly'">
|
|
{{ getCustomTranslationText(option.label ? option.label : option.value) }}
|
|
</mat-option>
|
|
</mat-select>
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon" matIconPrefix>
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')">
|
|
{{ getErrorMessageText(key.settings, 'required') }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-form-field *ngIf="key.settings.dataKeyValueType === 'color'"
|
|
class="color-input" [appearance]="key.settings.appearance" [subscriptSizing]="key.settings.subscriptSizing"
|
|
(click)="colorInput.openColorPickerPopup($event)">
|
|
<mat-label>{{key.label}}</mat-label>
|
|
<input matInput
|
|
formControlName="{{key.formId}}"
|
|
[required]="key.settings.required"
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
type="text"
|
|
(keydown)="$event.preventDefault();">
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon" matIconPrefix>
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<tb-color-input #colorInput asBoxInput matSuffix
|
|
colorClearButton
|
|
[disabled]="multipleInputFormGroup.get(key.formId).disabled"
|
|
[readonly]="key.settings.isEditable === 'readonly'"
|
|
[ngModel]="multipleInputFormGroup.get(key.formId).value"
|
|
(ngModelChange)="colorChanged(source, key, $event)"
|
|
[ngModelOptions]="{ standalone: true }">
|
|
</tb-color-input>
|
|
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')">
|
|
{{ getErrorMessageText(key.settings, 'required') }}
|
|
</mat-error>
|
|
</mat-form-field>
|
|
<mat-checkbox *ngIf="key.settings.dataKeyValueType === 'booleanCheckbox'"
|
|
formControlName="{{key.formId}}"
|
|
(change)="inputChanged(source, key)">
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon">
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<span class="label-wrapper">{{key.label}}</span>
|
|
</mat-checkbox>
|
|
<mat-slide-toggle *ngIf="key.settings.dataKeyValueType === 'booleanSwitch'"
|
|
formControlName="{{key.formId}}"
|
|
[labelPosition]="key.settings.slideToggleLabelPosition"
|
|
(change)="inputChanged(source, key)">
|
|
<ng-container *ngIf="key.settings.icon || key.settings.safeCustomIcon">
|
|
<ng-container *ngTemplateOutlet="iconPrefix; context: {key: key}"></ng-container>
|
|
</ng-container>
|
|
<span class="label-wrapper">{{key.label}}</span>
|
|
</mat-slide-toggle>
|
|
</ng-container>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<div class="mat-padding tb-multiple-input--buttons-container"
|
|
*ngIf="entityDetected && isAllParametersValid && settings.showActionButtons">
|
|
<button mat-button color="primary" type="button"
|
|
(click)="discardAll()" class="tb-multiple-input--buttons-container__button"
|
|
[disabled]="!multipleInputFormGroup.dirty">
|
|
{{ resetButtonLabel }}
|
|
</button>
|
|
<button mat-button mat-raised-button color="primary" type="submit"
|
|
class="tb-multiple-input--buttons-container__button"
|
|
[disabled]="!multipleInputFormGroup.dirty || invalid()">
|
|
{{ saveButtonLabel }}
|
|
</button>
|
|
</div>
|
|
<div class="tb-multiple-input--errors-container" *ngIf="(!entityDetected || !isAllParametersValid) && datasourceDetected">
|
|
<div class="tb-multiple-input--errors-container__error" [fxHide]="entityDetected">
|
|
{{ 'widgets.input-widgets.no-entity-selected' | translate }}
|
|
</div>
|
|
<div class="tb-multiple-input--errors-container__error" [fxShow]="entityDetected && !isAllParametersValid">
|
|
{{ 'widgets.input-widgets.not-allowed-entity' | translate }}
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<ng-template #iconPrefix let-key="key">
|
|
<tb-icon *ngIf="!key.settings.safeCustomIcon; else customToggleIcon">{{key.settings.icon}}</tb-icon>
|
|
<ng-template #customToggleIcon>
|
|
<img class="mat-icon" [src]="key.settings.safeCustomIcon" alt="icon">
|
|
</ng-template>
|
|
</ng-template>
|