widget-config.component.html 19.3 KB
<!--

    Copyright © 2016-2019 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.

-->
<mat-tab-group [ngClass]="{'tb-headless': (widgetType === widgetTypes.static && !displayAdvanced())}"
               fxFlex class="tb-widget-config tb-absolute-fill" [(selectedIndex)]="selectedTab">
  <mat-tab label="{{ 'widget-config.data' | translate }}" [fxShow]="widgetType !== widgetTypes.static">
    <div [formGroup]="dataSettings" class="mat-content mat-padding" fxLayout="column" fxLayoutGap="8px">
      <div *ngIf="widgetType === widgetTypes.timeseries || widgetType === widgetTypes.alarm"
            fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
        <div fxLayout="column" fxLayoutGap="8px" fxFlex>
          <mat-checkbox formControlName="useDashboardTimewindow">
            {{ 'widget-config.use-dashboard-timewindow' | translate }}
          </mat-checkbox>
          <mat-checkbox formControlName="displayTimewindow">
            {{ 'widget-config.display-timewindow' | translate }}
          </mat-checkbox>
        </div>
        <section fxFlex fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;">
          <span [ngClass]="{'tb-disabled-label': dataSettings.get('useDashboardTimewindow').value}" translate style="padding-right: 8px;">widget-config.timewindow</span>
          <tb-timewindow asButton="true"
                         aggregation="{{ widgetType === widgetTypes.timeseries }}"
                         fxFlex formControlName="timewindow"></tb-timewindow>
        </section>
      </div>
      <div *ngIf="widgetType === widgetTypes.alarm" fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center"
           fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
        <mat-form-field fxFlex class="mat-block">
          <mat-label translate>alarm.alarm-status</mat-label>
          <mat-select matInput formControlName="alarmSearchStatus">
            <mat-option *ngFor="let searchStatus of alarmSearchStatuses" [value]="searchStatus">
              {{ ('alarm.search-status.' + searchStatus) | translate }}
            </mat-option>
          </mat-select>
        </mat-form-field>
        <mat-form-field fxFlex class="mat-block">
          <mat-label translate>alarm.polling-interval</mat-label>
          <input matInput required
                 formControlName="alarmsPollingInterval"
                 type="number"
                 step="1"/>
          <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('required')">
            {{ 'alarm.polling-interval-required' | translate }}
          </mat-error>
          <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('min')">
            {{ 'alarm.min-polling-interval-message' | translate }}
          </mat-error>
        </mat-form-field>
      </div>
      <mat-expansion-panel class="tb-datasources" *ngIf="widgetType !== widgetTypes.rpc &&
                                  widgetType !== widgetTypes.alarm &&
                                  widgetType !== widgetTypes.static &&
                                  modelValue?.isDataEnabled" [expanded]="true">
        <mat-expansion-panel-header>
          <mat-panel-title fxLayout="column">
            <div class="tb-panel-title" translate>widget-config.datasources</div>
            <div *ngIf="modelValue?.typeParameters && modelValue?.typeParameters.maxDatasources > -1"
                 class="tb-hint">{{ 'widget-config.maximum-datasources' | translate:{count: modelValue?.typeParameters.maxDatasources} }}</div>
          </mat-panel-title>
        </mat-expansion-panel-header>
        <div *ngIf="datasourcesFormArray().length === 0; else datasourcesTemplate">
              <span translate fxLayoutAlign="center center"
                    class="tb-prompt">datasource.add-datasource-prompt</span>
        </div>
        <ng-template #datasourcesTemplate>
          <div fxFlex fxLayout="row" fxLayoutAlign="start center">
            <span fxFlex="5"></span>
            <div fxFlex fxLayout="row" fxLayoutAlign="start center"
                 style="padding: 0 0 0 10px; margin: 5px;">
              <span translate style="min-width: 110px;">widget-config.datasource-type</span>
              <span fxHide fxShow.gt-sm translate fxFlex
                    style="padding-left: 10px;">widget-config.datasource-parameters</span>
              <span style="min-width: 40px;"></span>
            </div>
          </div>
          <div style="overflow: auto; padding-bottom: 15px;">
            <div fxFlex fxLayout="row" fxLayoutAlign="start center"
                 formArrayName="datasources"
                 *ngFor="let datasourceControl of datasourcesFormArray().controls; let $index = index;">
              <span fxFlex="5">{{$index + 1}}.</span>
              <div [formGroupName]="$index" class="mat-elevation-z4" fxFlex
                   fxLayout="row"
                   fxLayoutAlign="start center"
                   style="padding: 0 0 0 10px; margin: 5px;">
                <section fxFlex
                         fxLayout="column"
                         fxLayoutAlign="center"
                         fxLayout.gt-sm="row"
                         fxLayoutAlign.gt-sm="start center">
                  <mat-form-field class="tb-datasource-type">
                    <mat-select matInput formControlName="type">
                      <mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType">
                        {{ datasourceTypesTranslations.get(datasourceType) | translate }}
                      </mat-option>
                    </mat-select>
                  </mat-form-field>
                  <section class="tb-datasource" [ngSwitch]="datasourceControl.get('type').value">
                    <ng-template [ngSwitchCase]="datasourceType.function">
                      <mat-form-field floatLabel="always"
                                      class="tb-datasource-name" style="min-width: 200px;">
                        <mat-label></mat-label>
                        <input matInput
                               placeholder="{{ 'datasource.name' | translate }}"
                               formControlName="name">
                      </mat-form-field>
                    </ng-template>
                    <ng-template [ngSwitchCase]="datasourceType.entity">
                      <tb-entity-alias-select
                        [tbRequired]="datasourceControl.get('type').value === datasourceType.entity"
                        [aliasController]="aliasController"
                        formControlName="entityAliasId"
                        [callbacks]="widgetConfigCallbacks">
                      </tb-entity-alias-select>
                    </ng-template>
                  </section>
                  <tb-data-keys class="tb-data-keys" fxFlex
                                [widgetType]="widgetType"
                                [datasourceType]="datasourceControl.get('type').value"
                                [maxDataKeys]="modelValue?.typeParameters?.maxDataKeys"
                                [optDataKeys]="modelValue?.typeParameters?.dataKeysOptional"
                                [aliasController]="aliasController"
                                [datakeySettingsSchema]="modelValue?.dataKeySettingsSchema"
                                [callbacks]="widgetConfigCallbacks"
                                [entityAliasId]="datasourceControl.get('entityAliasId').value"
                                formControlName="dataKeys">
                  </tb-data-keys>
                </section>
                <button [disabled]="isLoading$ | async"
                        type="button"
                        mat-button mat-icon-button color="primary"
                        style="min-width: 40px;"
                        (click)="removeDatasource($index)"
                        matTooltip="{{ 'widget-config.remove-datasource' | translate }}"
                        matTooltipPosition="above">
                  <mat-icon>close</mat-icon>
                </button>
              </div>
            </div>
          </div>
        </ng-template>
        <div fxFlex fxLayout="row" fxLayoutAlign="start center">
          <button [disabled]="isLoading$ | async"
                  type="button"
                  mat-button mat-raised-button color="primary"
                  [fxShow]="modelValue?.typeParameters &&
                            (modelValue?.typeParameters.maxDatasources == -1 || datasourcesFormArray().controls.length < modelValue?.typeParameters.maxDatasources)"
                  (click)="addDatasource()"
                  matTooltip="{{ 'widget-config.add-datasource' | translate }}"
                  matTooltipPosition="above">
            <mat-icon>add</mat-icon>
            <span translate>action.add</span>
          </button>
        </div>
      </mat-expansion-panel>
      <mat-expansion-panel class="tb-datasources" *ngIf="widgetType === widgetTypes.rpc &&
                                  modelValue?.isDataEnabled" [expanded]="true">
        <mat-expansion-panel-header>
          <mat-panel-title>
            {{ 'widget-config.target-device' | translate }}
          </mat-panel-title>
        </mat-expansion-panel-header>
        <div [formGroup]="targetDeviceSettings" style="padding: 0 5px;">
          <tb-entity-alias-select fxFlex
            [tbRequired]="!widgetEditMode"
            [aliasController]="aliasController"
            [allowedEntityTypes]="[entityTypes.DEVICE]"
            [callbacks]="widgetConfigCallbacks"
            formControlName="targetDeviceAliasId">
          </tb-entity-alias-select>
        </div>
      </mat-expansion-panel>
      <mat-expansion-panel class="tb-datasources" *ngIf="widgetType === widgetTypes.alarm &&
                                  modelValue?.isDataEnabled" [expanded]="true">
        <mat-expansion-panel-header>
          <mat-panel-title>
            {{ 'widget-config.alarm-source' | translate }}
          </mat-panel-title>
        </mat-expansion-panel-header>
        <div [formGroup]="alarmSourceSettings" style="padding: 0 5px;">
          <section fxFlex
                   fxLayout="column"
                   fxLayoutAlign="center"
                   fxLayout.gt-sm="row"
                   fxLayoutAlign.gt-sm="start center">
            <mat-form-field class="tb-datasource-type">
              <mat-select matInput formControlName="type">
                <mat-option *ngFor="let datasourceType of datasourceTypes" [value]="datasourceType">
                  {{ datasourceTypesTranslations.get(datasourceType) | translate }}
                </mat-option>
              </mat-select>
            </mat-form-field>
            <section class="tb-datasource" [ngSwitch]="alarmSourceSettings.get('type').value">
              <ng-template [ngSwitchCase]="datasourceType.function">
                <mat-form-field floatLabel="always" [fxShow]="widgetType !== widgetTypes.alarm"
                                class="tb-datasource-name" style="min-width: 200px;">
                  <mat-label></mat-label>
                  <input matInput
                         placeholder="{{ 'datasource.name' | translate }}"
                         formControlName="name">
                </mat-form-field>
              </ng-template>
              <ng-template [ngSwitchCase]="datasourceType.entity">
                <tb-entity-alias-select
                  [tbRequired]="alarmSourceSettings.get('type').value === datasourceType.entity"
                  [aliasController]="aliasController"
                  formControlName="entityAliasId"
                  [callbacks]="widgetConfigCallbacks">
                </tb-entity-alias-select>
              </ng-template>
            </section>
            <tb-data-keys class="tb-data-keys" fxFlex
                          [widgetType]="widgetType"
                          [datasourceType]="alarmSourceSettings.get('type').value"
                          [aliasController]="aliasController"
                          [datakeySettingsSchema]="modelValue?.dataKeySettingsSchema"
                          [callbacks]="widgetConfigCallbacks"
                          [entityAliasId]="alarmSourceSettings.get('entityAliasId').value"
                          formControlName="dataKeys">
            </tb-data-keys>
          </section>
        </div>
      </mat-expansion-panel>
    </div>
  </mat-tab>
  <mat-tab label="{{ 'widget-config.settings' | translate }}">
    <div class="mat-content mat-padding"
         fxLayout="column" fxLayoutGap="8px">
      <div [formGroup]="widgetSettings" fxLayout="column" fxLayoutGap="8px">
        <span translate>widget-config.general-settings</span>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">
          <mat-form-field fxFlex class="mat-block">
            <mat-label translate>widget-config.title</mat-label>
            <input matInput formControlName="title">
          </mat-form-field>
          <div fxFlex [fxShow]="widgetSettings.get('showTitle').value">
            <tb-json-object-edit
              [editorStyle]="{minHeight: '100px'}"
              required
              label="{{ 'widget-config.title-style' | translate }}"
              formControlName="titleStyle"
            ></tb-json-object-edit>
          </div>
        </div>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <div fxLayout="row" fxFlex>
            <mat-checkbox formControlName="showTitleIcon">
              {{ 'widget-config.display-icon' | translate }}
            </mat-checkbox>
          </div>
          <div fxFlex>
            <tb-material-icon-select
              formControlName="titleIcon">
            </tb-material-icon-select>
          </div>
          <tb-color-input fxFlex
                          label="{{'widget-config.icon-color' | translate}}"
                          icon="format_color_fill"
                          openOnInput
                          formControlName="iconColor">
          </tb-color-input>
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.icon-size</mat-label>
            <input matInput formControlName="iconSize">
          </mat-form-field>
        </div>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <div fxLayout="row">
            <mat-checkbox formControlName="showTitle">
              {{ 'widget-config.display-title' | translate }}
            </mat-checkbox>
          </div>
          <div fxLayout="row">
            <mat-checkbox formControlName="dropShadow">
              {{ 'widget-config.drop-shadow' | translate }}
            </mat-checkbox>
          </div>
          <div fxLayout="row">
            <mat-checkbox formControlName="enableFullscreen">
              {{ 'widget-config.enable-fullscreen' | translate }}
            </mat-checkbox>
          </div>
          <div fxFlex>
            <tb-json-object-edit
              [editorStyle]="{minHeight: '100px'}"
              required
              label="{{ 'widget-config.widget-style' | translate }}"
              formControlName="widgetStyle"
            ></tb-json-object-edit>
          </div>
        </div>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <tb-color-input fxFlex
                          label="{{'widget-config.background-color' | translate}}"
                          icon="format_color_fill"
                          openOnInput
                          formControlName="backgroundColor">
          </tb-color-input>
          <tb-color-input fxFlex
                          label="{{'widget-config.text-color' | translate}}"
                          icon="format_color_fill"
                          openOnInput
                          formControlName="color">
          </tb-color-input>
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.padding</mat-label>
            <input matInput formControlName="padding">
          </mat-form-field>
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.margin</mat-label>
            <input matInput formControlName="margin">
          </mat-form-field>
        </div>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.units</mat-label>
            <input matInput formControlName="units">
          </mat-form-field>
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.decimals</mat-label>
            <input matInput formControlName="decimals" type="number" min="0" max="15" step="1">
          </mat-form-field>
        </div>
        <div [fxShow]="widgetType === widgetTypes.timeseries ||
                       widgetType === widgetTypes.latest"
             fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <mat-checkbox fxFlex formControlName="showLegend">
            {{ 'widget-config.display-legend' | translate }}
          </mat-checkbox>
          <section fxFlex fxLayout="row" fxLayoutAlign="start center" style="margin-bottom: 16px;">
            <tb-legend-config formControlName="legendConfig">
            </tb-legend-config>
          </section>
        </div>
      </div>
      <div [formGroup]="layoutSettings" fxLayout="column" fxLayoutGap="8px">
        <span translate>widget-config.mobile-mode-settings</span>
        <div fxLayout="column" fxLayoutAlign="center" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center"
             fxLayoutGap="8px">
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.order</mat-label>
            <input matInput formControlName="mobileOrder" type="number" step="1">
          </mat-form-field>
          <mat-form-field fxFlex>
            <mat-label translate>widget-config.height</mat-label>
            <input matInput formControlName="mobileHeight" type="number" min="1" max="10" step="1">
          </mat-form-field>
        </div>
      </div>
    </div>
  </mat-tab>
  <mat-tab *ngIf="displayAdvanced()" label="{{ 'widget-config.advanced' | translate }}">
    <div [formGroup]="advancedSettings" class="mat-content mat-padding tb-advanced-widget-config"
         fxLayout="column">
        <tb-json-form
          formControlName="settings">
        </tb-json-form>
    </div>
  </mat-tab>
  <mat-tab label="{{ 'widget-config.actions' | translate }}" [formGroup]="actionsSettings">
    <tb-manage-widget-actions
      [callbacks]="widgetConfigCallbacks"
      formControlName="actionsData">
    </tb-manage-widget-actions>
  </mat-tab>
</mat-tab-group>