Merge pull request #10134 from thingsboard/feature/command-button
Command button widget
This commit is contained in:
		
						commit
						17c87f27a8
					
				@ -8,6 +8,7 @@
 | 
			
		||||
    "name": "Buttons"
 | 
			
		||||
  },
 | 
			
		||||
  "widgetTypeFqns": [
 | 
			
		||||
    "action_button"
 | 
			
		||||
    "action_button",
 | 
			
		||||
    "command_button"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -1049,26 +1049,20 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC
 | 
			
		||||
        this.onAddWidgetClosed();
 | 
			
		||||
        this.isAddingWidgetClosed = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (this.widgetEditMode) {
 | 
			
		||||
        if (revert) {
 | 
			
		||||
          this.dashboard = this.prevDashboard;
 | 
			
		||||
          this.dashboardLogoCache = undefined;
 | 
			
		||||
          this.dashboardConfiguration = this.dashboard.configuration;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        this.resetHighlight();
 | 
			
		||||
        if (revert) {
 | 
			
		||||
          this.dashboard = this.prevDashboard;
 | 
			
		||||
          this.dashboardLogoCache = undefined;
 | 
			
		||||
          this.dashboardConfiguration = this.dashboard.configuration;
 | 
			
		||||
      this.resetHighlight();
 | 
			
		||||
      if (revert) {
 | 
			
		||||
        this.dashboard = this.prevDashboard;
 | 
			
		||||
        this.dashboardLogoCache = undefined;
 | 
			
		||||
        this.dashboardConfiguration = this.dashboard.configuration;
 | 
			
		||||
        if (!this.widgetEditMode) {
 | 
			
		||||
          this.dashboardCtx.dashboardTimewindow = this.dashboardConfiguration.timewindow;
 | 
			
		||||
          this.updateDashboardCss();
 | 
			
		||||
          this.entityAliasesUpdated();
 | 
			
		||||
          this.filtersUpdated();
 | 
			
		||||
          this.updateLayouts();
 | 
			
		||||
        } else {
 | 
			
		||||
          this.dashboard.configuration.timewindow = this.dashboardCtx.dashboardTimewindow;
 | 
			
		||||
        }
 | 
			
		||||
      } else if (!this.widgetEditMode) {
 | 
			
		||||
        this.dashboard.configuration.timewindow = this.dashboardCtx.dashboardTimewindow;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -97,6 +97,9 @@ import {
 | 
			
		||||
import {
 | 
			
		||||
  ActionButtonBasicConfigComponent
 | 
			
		||||
} from '@home/components/widget/config/basic/button/action-button-basic-config.component';
 | 
			
		||||
import {
 | 
			
		||||
  CommandButtonBasicConfigComponent
 | 
			
		||||
} from '@home/components/widget/config/basic/button/command-button-basic-config.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -127,7 +130,8 @@ import {
 | 
			
		||||
    RangeChartBasicConfigComponent,
 | 
			
		||||
    BarChartWithLabelsBasicConfigComponent,
 | 
			
		||||
    SingleSwitchBasicConfigComponent,
 | 
			
		||||
    ActionButtonBasicConfigComponent
 | 
			
		||||
    ActionButtonBasicConfigComponent,
 | 
			
		||||
    CommandButtonBasicConfigComponent
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@ -162,7 +166,8 @@ import {
 | 
			
		||||
    RangeChartBasicConfigComponent,
 | 
			
		||||
    BarChartWithLabelsBasicConfigComponent,
 | 
			
		||||
    SingleSwitchBasicConfigComponent,
 | 
			
		||||
    ActionButtonBasicConfigComponent
 | 
			
		||||
    ActionButtonBasicConfigComponent,
 | 
			
		||||
    CommandButtonBasicConfigComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class BasicWidgetConfigModule {
 | 
			
		||||
@ -191,5 +196,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type<IBasicWidgetCo
 | 
			
		||||
  'tb-range-chart-basic-config': RangeChartBasicConfigComponent,
 | 
			
		||||
  'tb-bar-chart-with-labels-basic-config': BarChartWithLabelsBasicConfigComponent,
 | 
			
		||||
  'tb-single-switch-basic-config': SingleSwitchBasicConfigComponent,
 | 
			
		||||
  'tb-action-button-basic-config': ActionButtonBasicConfigComponent
 | 
			
		||||
  'tb-action-button-basic-config': ActionButtonBasicConfigComponent,
 | 
			
		||||
  'tb-command-button-basic-config': CommandButtonBasicConfigComponent
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,59 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2024 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.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<ng-container [formGroup]="commandButtonWidgetConfigForm">
 | 
			
		||||
  <tb-target-device formControlName="targetDevice"></tb-target-device>
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>widgets.command-button.behavior</div>
 | 
			
		||||
    <div class="tb-form-row space-between">
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.command-button.on-click-hint' | translate}}" translate>widgets.command-button.on-click</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.command-button.on-click"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
                                    formControlName="onClickState"></tb-set-value-action-settings>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-form-row">
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.button-state.disabled-state-hint' | translate}}" translate>widgets.button-state.disabled-state</div>
 | 
			
		||||
      <tb-get-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.button-state.disabled-state"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    stateLabel="widgets.button-state.disabled"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
                                    formControlName="disabledState"></tb-get-value-action-settings>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>widget-config.appearance</div>
 | 
			
		||||
    <tb-widget-button-appearance
 | 
			
		||||
      [borderRadius]="commandButtonWidgetConfigForm.get('borderRadius').value"
 | 
			
		||||
      formControlName="appearance">
 | 
			
		||||
    </tb-widget-button-appearance>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
 | 
			
		||||
    <div class="tb-form-row space-between">
 | 
			
		||||
      <div>{{ 'widget-config.card-border-radius' | translate }}</div>
 | 
			
		||||
      <mat-form-field appearance="outline" subscriptSizing="dynamic">
 | 
			
		||||
        <input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-container>
 | 
			
		||||
@ -0,0 +1,85 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2024 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 } from '@angular/core';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
 | 
			
		||||
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
 | 
			
		||||
import { TargetDevice, } from '@shared/models/widget.models';
 | 
			
		||||
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
 | 
			
		||||
import { ValueType } from '@shared/models/constants';
 | 
			
		||||
import {
 | 
			
		||||
  commandButtonDefaultSettings,
 | 
			
		||||
  CommandButtonWidgetSettings
 | 
			
		||||
} from '@home/components/widget/lib/button/command-button-widget.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-command-button-basic-config',
 | 
			
		||||
  templateUrl: './command-button-basic-config.component.html',
 | 
			
		||||
  styleUrls: ['../basic-config.scss']
 | 
			
		||||
})
 | 
			
		||||
export class CommandButtonBasicConfigComponent extends BasicWidgetConfigComponent {
 | 
			
		||||
 | 
			
		||||
  get targetDevice(): TargetDevice {
 | 
			
		||||
    return this.commandButtonWidgetConfigForm.get('targetDevice').value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  valueType = ValueType;
 | 
			
		||||
 | 
			
		||||
  commandButtonWidgetConfigForm: UntypedFormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              protected widgetConfigComponent: WidgetConfigComponent,
 | 
			
		||||
              private fb: UntypedFormBuilder) {
 | 
			
		||||
    super(store, widgetConfigComponent);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected configForm(): UntypedFormGroup {
 | 
			
		||||
    return this.commandButtonWidgetConfigForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onConfigSet(configData: WidgetConfigComponentData) {
 | 
			
		||||
    const settings: CommandButtonWidgetSettings = {...commandButtonDefaultSettings, ...(configData.config.settings || {})};
 | 
			
		||||
    this.commandButtonWidgetConfigForm = this.fb.group({
 | 
			
		||||
      targetDevice: [configData.config.targetDevice, []],
 | 
			
		||||
 | 
			
		||||
      onClickState: [settings.onClickState, []],
 | 
			
		||||
      disabledState: [settings.disabledState, []],
 | 
			
		||||
 | 
			
		||||
      appearance: [settings.appearance, []],
 | 
			
		||||
 | 
			
		||||
      borderRadius: [configData.config.borderRadius, []]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected prepareOutputConfig(config: any): WidgetConfigComponentData {
 | 
			
		||||
 | 
			
		||||
    this.widgetConfig.config.targetDevice = config.targetDevice;
 | 
			
		||||
 | 
			
		||||
    this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
 | 
			
		||||
 | 
			
		||||
    this.widgetConfig.config.settings.onClickState = config.onClickState;
 | 
			
		||||
    this.widgetConfig.config.settings.disabledState = config.disabledState;
 | 
			
		||||
 | 
			
		||||
    this.widgetConfig.config.settings.appearance = config.appearance;
 | 
			
		||||
 | 
			
		||||
    this.widgetConfig.config.borderRadius = config.borderRadius;
 | 
			
		||||
 | 
			
		||||
    return this.widgetConfig;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -36,7 +36,6 @@
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.rpc-state.turn-on-hint' | translate}}" translate>widgets.rpc-state.turn-on</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.rpc-state.turn-on"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
@ -46,7 +45,6 @@
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.rpc-state.turn-off-hint' | translate}}" translate>widgets.rpc-state.turn-off</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.rpc-state.turn-off"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,12 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
.mdc-linear-progress.tb-action-widget-progress {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
}
 | 
			
		||||
.tb-action-widget-error-container {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@
 | 
			
		||||
    [borderRadius]="borderRadius"
 | 
			
		||||
    [disabled]="disabled"
 | 
			
		||||
    [activated]="activated"
 | 
			
		||||
    [ctx]="ctx"
 | 
			
		||||
    (clicked)="onClick($event)">
 | 
			
		||||
  </tb-widget-button>
 | 
			
		||||
  <div *ngIf="error" class="tb-action-widget-error-container">
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2024 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.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div class="tb-command-button-widget" [style.pointer-events]="ctx.isEdit ? 'none' : 'all'">
 | 
			
		||||
  <div class="tb-command-button-widget-title-panel">
 | 
			
		||||
    <ng-container *ngTemplateOutlet="widgetTitlePanel"></ng-container>
 | 
			
		||||
  </div>
 | 
			
		||||
  <tb-widget-button
 | 
			
		||||
    [appearance]="appearance"
 | 
			
		||||
    [borderRadius]="borderRadius"
 | 
			
		||||
    [disabled]="disabled || (loading$ | async)"
 | 
			
		||||
    [ctx]="ctx"
 | 
			
		||||
    (clicked)="onClick($event)">
 | 
			
		||||
  </tb-widget-button>
 | 
			
		||||
  <mat-progress-bar class="tb-action-widget-progress" style="height: 4px;" color="accent" mode="indeterminate" *ngIf="loading$ | async"></mat-progress-bar>
 | 
			
		||||
  <div *ngIf="error" class="tb-action-widget-error-container">
 | 
			
		||||
    <div class="tb-action-widget-error-panel">
 | 
			
		||||
      <div class="tb-action-widget-error-text" [innerHTML]="error | safe: 'html'"></div>
 | 
			
		||||
      <button class="tb-action-widget-error-clear tb-mat-20" mat-icon-button (click)="clearError()"><mat-icon>close</mat-icon></button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2024 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.
 | 
			
		||||
 */
 | 
			
		||||
.tb-command-button-widget {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
 | 
			
		||||
  > div.tb-command-button-widget-title-panel {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 12px;
 | 
			
		||||
    left: 12px;
 | 
			
		||||
    right: 12px;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,94 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2024 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 { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
 | 
			
		||||
import { BasicActionWidgetComponent, ValueSetter } from '@home/components/widget/lib/action/action-widget.models';
 | 
			
		||||
import { ImagePipe } from '@shared/pipe/image.pipe';
 | 
			
		||||
import { DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
import { ValueType } from '@shared/models/constants';
 | 
			
		||||
import { WidgetButtonAppearance } from '@shared/components/button/widget-button.models';
 | 
			
		||||
import {
 | 
			
		||||
  commandButtonDefaultSettings,
 | 
			
		||||
  CommandButtonWidgetSettings
 | 
			
		||||
} from '@home/components/widget/lib/button/command-button-widget.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-command-button-widget',
 | 
			
		||||
  templateUrl: './command-button-widget.component.html',
 | 
			
		||||
  styleUrls: ['../action/action-widget.scss', './command-button-widget.component.scss'],
 | 
			
		||||
  encapsulation: ViewEncapsulation.None
 | 
			
		||||
})
 | 
			
		||||
export class CommandButtonWidgetComponent extends
 | 
			
		||||
  BasicActionWidgetComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  settings: CommandButtonWidgetSettings;
 | 
			
		||||
 | 
			
		||||
  disabled = false;
 | 
			
		||||
 | 
			
		||||
  appearance: WidgetButtonAppearance;
 | 
			
		||||
  borderRadius = '4px';
 | 
			
		||||
 | 
			
		||||
  private clickValueSetter: ValueSetter<any>;
 | 
			
		||||
 | 
			
		||||
  constructor(protected imagePipe: ImagePipe,
 | 
			
		||||
              protected sanitizer: DomSanitizer,
 | 
			
		||||
              protected cd: ChangeDetectorRef) {
 | 
			
		||||
    super(cd);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    super.ngOnInit();
 | 
			
		||||
    this.settings = {...commandButtonDefaultSettings, ...this.ctx.settings};
 | 
			
		||||
 | 
			
		||||
    this.appearance = this.settings.appearance;
 | 
			
		||||
 | 
			
		||||
    const disabledStateSettings =
 | 
			
		||||
      {...this.settings.disabledState, actionLabel: this.ctx.translate.instant('widgets.button-state.disabled-state')};
 | 
			
		||||
    this.createValueGetter(disabledStateSettings, ValueType.BOOLEAN, {
 | 
			
		||||
      next: (value) => this.onDisabled(value)
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const onClickStateSettings = {...this.settings.onClickState,
 | 
			
		||||
      actionLabel: this.ctx.translate.instant('widgets.command-button.on-click')};
 | 
			
		||||
    this.clickValueSetter = this.createValueSetter(onClickStateSettings);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngAfterViewInit(): void {
 | 
			
		||||
    super.ngAfterViewInit();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy() {
 | 
			
		||||
    super.ngOnDestroy();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onInit() {
 | 
			
		||||
    super.onInit();
 | 
			
		||||
    this.borderRadius = this.ctx.$widgetElement.css('borderRadius');
 | 
			
		||||
    this.cd.detectChanges();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onClick(_$event: MouseEvent) {
 | 
			
		||||
    if (!this.ctx.isEdit && !this.ctx.isPreview) {
 | 
			
		||||
      this.updateValue(this.clickValueSetter, null);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private onDisabled(value: boolean): void {
 | 
			
		||||
    this.disabled = !!value;
 | 
			
		||||
    this.cd.markForCheck();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,71 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2024 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 { WidgetButtonAppearance, widgetButtonDefaultAppearance } from '@shared/components/button/widget-button.models';
 | 
			
		||||
import {
 | 
			
		||||
  DataToValueType,
 | 
			
		||||
  GetValueAction,
 | 
			
		||||
  GetValueSettings, SetValueAction,
 | 
			
		||||
  SetValueSettings, ValueToDataType
 | 
			
		||||
} from '@shared/models/action-widget-settings.models';
 | 
			
		||||
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
 | 
			
		||||
 | 
			
		||||
export interface CommandButtonWidgetSettings {
 | 
			
		||||
  appearance: WidgetButtonAppearance;
 | 
			
		||||
  onClickState: SetValueSettings;
 | 
			
		||||
  disabledState: GetValueSettings<boolean>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const commandButtonDefaultSettings: CommandButtonWidgetSettings = {
 | 
			
		||||
  appearance: {...widgetButtonDefaultAppearance, label: 'Send', icon: 'arrow_outward'},
 | 
			
		||||
  onClickState: {
 | 
			
		||||
    action: SetValueAction.EXECUTE_RPC,
 | 
			
		||||
    executeRpc: {
 | 
			
		||||
      method: 'setState',
 | 
			
		||||
      requestTimeout: 5000,
 | 
			
		||||
      requestPersistent: false,
 | 
			
		||||
      persistentPollingInterval: 1000
 | 
			
		||||
    },
 | 
			
		||||
    setAttribute: {
 | 
			
		||||
      key: 'state',
 | 
			
		||||
      scope: AttributeScope.SHARED_SCOPE
 | 
			
		||||
    },
 | 
			
		||||
    putTimeSeries: {
 | 
			
		||||
      key: 'state'
 | 
			
		||||
    },
 | 
			
		||||
    valueToData: {
 | 
			
		||||
      type: ValueToDataType.NONE,
 | 
			
		||||
      constantValue: true,
 | 
			
		||||
      valueToDataFunction: '/* Return RPC parameters or attribute/time-series value */\nreturn true;'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  disabledState: {
 | 
			
		||||
    action: GetValueAction.DO_NOTHING,
 | 
			
		||||
    defaultValue: false,
 | 
			
		||||
    getAttribute: {
 | 
			
		||||
      key: 'state',
 | 
			
		||||
      scope: null
 | 
			
		||||
    },
 | 
			
		||||
    getTimeSeries: {
 | 
			
		||||
      key: 'state'
 | 
			
		||||
    },
 | 
			
		||||
    dataToValue: {
 | 
			
		||||
      type: DataToValueType.NONE,
 | 
			
		||||
      compareToValue: true,
 | 
			
		||||
      dataToValueFunction: '/* Should return boolean value */\nreturn data;'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
@ -22,17 +22,21 @@
 | 
			
		||||
  </div>
 | 
			
		||||
  <div #singleSwitchContent class="tb-single-switch-content" [class]="this.layout" [class.no-label]="!showIcon && !showLabel" [class.auto-scale]="autoScale">
 | 
			
		||||
    <div *ngIf="showIcon || showLabel" #singleSwitchLabelRow class="tb-single-switch-label-row">
 | 
			
		||||
      <tb-icon *ngIf="showIcon" [style]="iconStyle">{{ icon }}</tb-icon>
 | 
			
		||||
      <div *ngIf="showLabel" class="tb-single-switch-label" [style]="labelStyle">{{ label$ | async }}</div>
 | 
			
		||||
      <tb-icon *ngIf="showIcon" [style]="iconStyle"
 | 
			
		||||
               [style.color]="(disabled || (loading$ | async)) ? disabledColor : settings.iconColor">{{ icon }}</tb-icon>
 | 
			
		||||
      <div *ngIf="showLabel" class="tb-single-switch-label" [style]="labelStyle"
 | 
			
		||||
           [style.color]="(disabled || (loading$ | async)) ? disabledColor : settings.labelColor">{{ label$ | async }}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div #singleSwitchToggleRow class="tb-single-switch-slide-toggle-row">
 | 
			
		||||
      <div *ngIf="showOffLabel" [style]="offLabelStyle">{{ offLabel }}</div>
 | 
			
		||||
      <div *ngIf="showOffLabel" [style]="offLabelStyle"
 | 
			
		||||
           [style.color]="(disabled || (loading$ | async)) ? disabledColor : settings.offLabelColor">{{ offLabel }}</div>
 | 
			
		||||
      <mat-slide-toggle class="tb-single-switch-toggle" [disabled]="disabled || (loading$ | async)" [(ngModel)]="value" (click)="!disabled && onToggleChange($event)">
 | 
			
		||||
      </mat-slide-toggle>
 | 
			
		||||
      <div *ngIf="showOnLabel" [style]="onLabelStyle">{{ onLabel }}</div>
 | 
			
		||||
      <div *ngIf="showOnLabel" [style]="onLabelStyle"
 | 
			
		||||
           [style.color]="(disabled || (loading$ | async)) ? disabledColor : settings.onLabelColor">{{ onLabel }}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <mat-progress-bar class="tb-single-switch-progress" style="height: 2px;" color="accent" mode="indeterminate" *ngIf="loading$ | async"></mat-progress-bar>
 | 
			
		||||
  <mat-progress-bar class="tb-action-widget-progress" style="height: 4px;" color="accent" mode="indeterminate" *ngIf="loading$ | async"></mat-progress-bar>
 | 
			
		||||
  <div *ngIf="error" class="tb-action-widget-error-container">
 | 
			
		||||
    <div class="tb-action-widget-error-panel">
 | 
			
		||||
      <div class="tb-action-widget-error-text" [innerHTML]="error | safe: 'html'"></div>
 | 
			
		||||
 | 
			
		||||
@ -39,12 +39,6 @@ $switchColorDisabled: var(--tb-single-switch-color-disabled, #D5D7E5);
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    inset: 12px;
 | 
			
		||||
  }
 | 
			
		||||
  .tb-single-switch-progress {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  > div.tb-single-switch-title-panel {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 12px;
 | 
			
		||||
 | 
			
		||||
@ -97,6 +97,8 @@ export class SingleSwitchWidgetComponent extends
 | 
			
		||||
  offLabel = '';
 | 
			
		||||
  offLabelStyle: ComponentStyle = {};
 | 
			
		||||
 | 
			
		||||
  disabledColor = 'rgba(0, 0, 0, 0.38)';
 | 
			
		||||
 | 
			
		||||
  autoScale = false;
 | 
			
		||||
 | 
			
		||||
  private panelResize$: ResizeObserver;
 | 
			
		||||
@ -129,22 +131,18 @@ export class SingleSwitchWidgetComponent extends
 | 
			
		||||
    this.showLabel = this.settings.showLabel;
 | 
			
		||||
    this.label$ = this.ctx.registerLabelPattern(this.settings.label, this.label$);
 | 
			
		||||
    this.labelStyle = textStyle(this.settings.labelFont);
 | 
			
		||||
    this.labelStyle.color = this.settings.labelColor;
 | 
			
		||||
 | 
			
		||||
    this.showIcon = this.settings.showIcon;
 | 
			
		||||
    this.icon = this.settings.icon;
 | 
			
		||||
    this.iconStyle = iconStyle(this.settings.iconSize, this.settings.iconSizeUnit );
 | 
			
		||||
    this.iconStyle.color = this.settings.iconColor;
 | 
			
		||||
 | 
			
		||||
    this.showOnLabel = this.settings.showOnLabel;
 | 
			
		||||
    this.onLabel = this.settings.onLabel;
 | 
			
		||||
    this.onLabelStyle = textStyle(this.settings.onLabelFont);
 | 
			
		||||
    this.onLabelStyle.color = this.settings.onLabelColor;
 | 
			
		||||
 | 
			
		||||
    this.showOffLabel = this.settings.showOffLabel;
 | 
			
		||||
    this.offLabel = this.settings.offLabel;
 | 
			
		||||
    this.offLabelStyle = textStyle(this.settings.offLabelFont);
 | 
			
		||||
    this.offLabelStyle.color = this.settings.offLabelColor;
 | 
			
		||||
    const switchVariablesCss = `.tb-single-switch-panel {\n`+
 | 
			
		||||
                                           `--tb-single-switch-tumbler-color-on: ${this.settings.tumblerColorOn};\n`+
 | 
			
		||||
                                           `--tb-single-switch-tumbler-color-off: ${this.settings.tumblerColorOff};\n`+
 | 
			
		||||
@ -211,13 +209,15 @@ export class SingleSwitchWidgetComponent extends
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onToggleChange(event: MouseEvent) {
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
    const targetValue = this.value;
 | 
			
		||||
    const targetSetter = targetValue ? this.onValueSetter : this.offValueSetter;
 | 
			
		||||
    this.updateValue(targetSetter, targetValue, {
 | 
			
		||||
      next: () => this.onValue(targetValue),
 | 
			
		||||
      error: () => this.onValue(!targetValue)
 | 
			
		||||
    });
 | 
			
		||||
    if (!this.ctx.isEdit && !this.ctx.isPreview) {
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      const targetValue = this.value;
 | 
			
		||||
      const targetSetter = targetValue ? this.onValueSetter : this.offValueSetter;
 | 
			
		||||
      this.updateValue(targetSetter, targetValue, {
 | 
			
		||||
        next: () => this.onValue(targetValue),
 | 
			
		||||
        error: () => this.onValue(!targetValue)
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private onValue(value: boolean): void {
 | 
			
		||||
@ -227,33 +227,6 @@ export class SingleSwitchWidgetComponent extends
 | 
			
		||||
 | 
			
		||||
  private onDisabled(value: boolean): void {
 | 
			
		||||
    this.disabled = !!value;
 | 
			
		||||
    if (this.disabled) {
 | 
			
		||||
      if (this.showLabel) {
 | 
			
		||||
        this.labelStyle = {...this.labelStyle, color: 'rgba(0, 0, 0, 0.38)'};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showIcon) {
 | 
			
		||||
        this.iconStyle = {...this.iconStyle, color: 'rgba(0, 0, 0, 0.38)'};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showOnLabel) {
 | 
			
		||||
        this.onLabelStyle = {...this.onLabelStyle, color: 'rgba(0, 0, 0, 0.38)'};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showOffLabel) {
 | 
			
		||||
        this.offLabelStyle = {...this.offLabelStyle, color: 'rgba(0, 0, 0, 0.38)'};
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (this.showLabel) {
 | 
			
		||||
        this.labelStyle = {...this.labelStyle, color: this.settings.labelColor};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showIcon) {
 | 
			
		||||
        this.iconStyle = {...this.iconStyle, color: this.settings.iconColor};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showOnLabel) {
 | 
			
		||||
        this.onLabelStyle = {...this.onLabelStyle, color: this.settings.onLabelColor};
 | 
			
		||||
      }
 | 
			
		||||
      if (this.showOffLabel) {
 | 
			
		||||
        this.offLabelStyle = {...this.offLabelStyle, color: this.settings.offLabelColor};
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.cd.markForCheck();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    Copyright © 2016-2024 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.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<ng-container [formGroup]="commandButtonWidgetSettingsForm">
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>widgets.command-button.behavior</div>
 | 
			
		||||
    <div class="tb-form-row space-between">
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.command-button.on-click-hint' | translate}}" translate>widgets.command-button.on-click</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.command-button.on-click"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
                                    formControlName="onClickState"></tb-set-value-action-settings>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-form-row">
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.button-state.disabled-state-hint' | translate}}" translate>widgets.button-state.disabled-state</div>
 | 
			
		||||
      <tb-get-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.button-state.disabled-state"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    stateLabel="widgets.button-state.disabled"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
                                    formControlName="disabledState"></tb-get-value-action-settings>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="tb-form-panel">
 | 
			
		||||
    <div class="tb-form-panel-title" translate>widget-config.appearance</div>
 | 
			
		||||
    <tb-widget-button-appearance
 | 
			
		||||
      [borderRadius]="borderRadius"
 | 
			
		||||
      formControlName="appearance">
 | 
			
		||||
    </tb-widget-button-appearance>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-container>
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
///
 | 
			
		||||
/// Copyright © 2016-2024 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 } from '@angular/core';
 | 
			
		||||
import { TargetDevice, WidgetSettings, WidgetSettingsComponent, widgetType } from '@shared/models/widget.models';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { ValueType } from '@shared/models/constants';
 | 
			
		||||
import { commandButtonDefaultSettings } from '@home/components/widget/lib/button/command-button-widget.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-command-button-widget-settings',
 | 
			
		||||
  templateUrl: './command-button-widget-settings.component.html',
 | 
			
		||||
  styleUrls: ['./../widget-settings.scss']
 | 
			
		||||
})
 | 
			
		||||
export class CommandButtonWidgetSettingsComponent extends WidgetSettingsComponent {
 | 
			
		||||
 | 
			
		||||
  get targetDevice(): TargetDevice {
 | 
			
		||||
    return this.widgetConfig?.config?.targetDevice;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get widgetType(): widgetType {
 | 
			
		||||
    return this.widgetConfig?.widgetType;
 | 
			
		||||
  }
 | 
			
		||||
  get borderRadius(): string {
 | 
			
		||||
    return this.widgetConfig?.config?.borderRadius;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  valueType = ValueType;
 | 
			
		||||
 | 
			
		||||
  commandButtonWidgetSettingsForm: UntypedFormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              private fb: UntypedFormBuilder) {
 | 
			
		||||
    super(store);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected settingsForm(): UntypedFormGroup {
 | 
			
		||||
    return this.commandButtonWidgetSettingsForm;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected defaultSettings(): WidgetSettings {
 | 
			
		||||
    return {...commandButtonDefaultSettings};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected onSettingsSet(settings: WidgetSettings) {
 | 
			
		||||
    this.commandButtonWidgetSettingsForm = this.fb.group({
 | 
			
		||||
      onClickState: [settings.onClickState, []],
 | 
			
		||||
      disabledState: [settings.disabledState, []],
 | 
			
		||||
 | 
			
		||||
      appearance: [settings.appearance, []]
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -22,14 +22,12 @@ import { Store } from '@ngrx/store';
 | 
			
		||||
import { AppState } from '@core/core.state';
 | 
			
		||||
import { merge } from 'rxjs';
 | 
			
		||||
import {
 | 
			
		||||
  getValueActions,
 | 
			
		||||
  SetValueAction,
 | 
			
		||||
  setValueActions, setValueActionsByWidgetType,
 | 
			
		||||
  setValueActionsByWidgetType,
 | 
			
		||||
  setValueActionTranslations,
 | 
			
		||||
  SetValueSettings,
 | 
			
		||||
  ValueToDataType
 | 
			
		||||
} from '@shared/models/action-widget-settings.models';
 | 
			
		||||
import { ValueType } from '@shared/models/constants';
 | 
			
		||||
import { TargetDevice, widgetType } from '@shared/models/widget.models';
 | 
			
		||||
import { AttributeScope, DataKeyType, telemetryTypeTranslationsShort } from '@shared/models/telemetry/telemetry.models';
 | 
			
		||||
import { IAliasController } from '@core/api/widget-api.models';
 | 
			
		||||
@ -50,9 +48,6 @@ export class SetValueActionSettingsPanelComponent extends PageComponent implemen
 | 
			
		||||
  @Input()
 | 
			
		||||
  setValueSettings: SetValueSettings;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  valueType: ValueType;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  aliasController: IAliasController;
 | 
			
		||||
 | 
			
		||||
@ -84,8 +79,6 @@ export class SetValueActionSettingsPanelComponent extends PageComponent implemen
 | 
			
		||||
 | 
			
		||||
  functionScopeVariables = this.widgetService.getWidgetScopeVariables();
 | 
			
		||||
 | 
			
		||||
  ValueType = ValueType;
 | 
			
		||||
 | 
			
		||||
  setValueSettingsFormGroup: UntypedFormGroup;
 | 
			
		||||
 | 
			
		||||
  constructor(private fb: UntypedFormBuilder,
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,6 @@ import { MatButton } from '@angular/material/button';
 | 
			
		||||
import { TbPopoverService } from '@shared/components/popover.service';
 | 
			
		||||
import { SetValueAction, SetValueSettings, ValueToDataType } from '@shared/models/action-widget-settings.models';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { ValueType } from '@shared/models/constants';
 | 
			
		||||
import { IAliasController } from '@core/api/widget-api.models';
 | 
			
		||||
import { TargetDevice, widgetType } from '@shared/models/widget.models';
 | 
			
		||||
import { isDefinedAndNotNull } from '@core/utils';
 | 
			
		||||
@ -59,9 +58,6 @@ export class SetValueActionSettingsComponent implements OnInit, ControlValueAcce
 | 
			
		||||
  @Input()
 | 
			
		||||
  panelTitle: string;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  valueType: ValueType;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  aliasController: IAliasController;
 | 
			
		||||
 | 
			
		||||
@ -118,7 +114,6 @@ export class SetValueActionSettingsComponent implements OnInit, ControlValueAcce
 | 
			
		||||
      const ctx: any = {
 | 
			
		||||
        setValueSettings: this.modelValue,
 | 
			
		||||
        panelTitle: this.panelTitle,
 | 
			
		||||
        valueType: this.valueType,
 | 
			
		||||
        aliasController: this.aliasController,
 | 
			
		||||
        targetDevice: this.targetDevice,
 | 
			
		||||
        widgetType: this.widgetType
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,7 @@
 | 
			
		||||
        widgets.button.preview
 | 
			
		||||
      </div>
 | 
			
		||||
      <tb-widget-button
 | 
			
		||||
        #widgetButtonPreview
 | 
			
		||||
        [appearance]="previewAppearance"
 | 
			
		||||
        [borderRadius]="borderRadius"
 | 
			
		||||
        disableEvents
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,16 @@
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
 | 
			
		||||
import {
 | 
			
		||||
  ChangeDetectorRef,
 | 
			
		||||
  Component,
 | 
			
		||||
  EventEmitter,
 | 
			
		||||
  Input,
 | 
			
		||||
  OnInit,
 | 
			
		||||
  Output,
 | 
			
		||||
  ViewChild,
 | 
			
		||||
  ViewEncapsulation
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { PageComponent } from '@shared/components/page.component';
 | 
			
		||||
import { TbPopoverComponent } from '@shared/components/popover.component';
 | 
			
		||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
 | 
			
		||||
@ -32,6 +41,7 @@ import {
 | 
			
		||||
} from '@shared/components/button/widget-button.models';
 | 
			
		||||
import { merge } from 'rxjs';
 | 
			
		||||
import { deepClone } from '@core/utils';
 | 
			
		||||
import { WidgetButtonComponent } from '@shared/components/button/widget-button.component';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-widget-button-custom-style-panel',
 | 
			
		||||
@ -42,6 +52,9 @@ import { deepClone } from '@core/utils';
 | 
			
		||||
})
 | 
			
		||||
export class WidgetButtonCustomStylePanelComponent extends PageComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  @ViewChild('widgetButtonPreview')
 | 
			
		||||
  widgetButtonPreview: WidgetButtonComponent;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  appearance: WidgetButtonAppearance;
 | 
			
		||||
 | 
			
		||||
@ -54,8 +67,19 @@ export class WidgetButtonCustomStylePanelComponent extends PageComponent impleme
 | 
			
		||||
  @Input()
 | 
			
		||||
  customStyle: WidgetButtonCustomStyle;
 | 
			
		||||
 | 
			
		||||
  private popoverValue: TbPopoverComponent<WidgetButtonCustomStylePanelComponent>;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  popover: TbPopoverComponent<WidgetButtonCustomStylePanelComponent>;
 | 
			
		||||
  set popover(popover: TbPopoverComponent<WidgetButtonCustomStylePanelComponent>) {
 | 
			
		||||
    this.popoverValue = popover;
 | 
			
		||||
    popover.tbAnimationDone.subscribe(() => {
 | 
			
		||||
      this.widgetButtonPreview?.validateSize();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get popover(): TbPopoverComponent<WidgetButtonCustomStylePanelComponent> {
 | 
			
		||||
    return this.popoverValue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  customStyleApplied = new EventEmitter<WidgetButtonCustomStyle>();
 | 
			
		||||
@ -125,7 +149,7 @@ export class WidgetButtonCustomStylePanelComponent extends PageComponent impleme
 | 
			
		||||
    if (customStyle?.overrideBackgroundColor) {
 | 
			
		||||
      backgroundColor = customStyle?.backgroundColor;
 | 
			
		||||
    }
 | 
			
		||||
    let dropShadow = this.appearance.type === WidgetButtonType.basic ? false : true;
 | 
			
		||||
    let dropShadow = this.appearance.type !== WidgetButtonType.basic;
 | 
			
		||||
    if (customStyle?.overrideDropShadow) {
 | 
			
		||||
      dropShadow = customStyle?.dropShadow;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,6 @@
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.rpc-state.turn-on-hint' | translate}}" translate>widgets.rpc-state.turn-on</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.rpc-state.turn-on"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
@ -45,7 +44,6 @@
 | 
			
		||||
      <div class="fixed-title-width" tb-hint-tooltip-icon="{{'widgets.rpc-state.turn-off-hint' | translate}}" translate>widgets.rpc-state.turn-off</div>
 | 
			
		||||
      <tb-set-value-action-settings fxFlex
 | 
			
		||||
                                    panelTitle="widgets.rpc-state.turn-off"
 | 
			
		||||
                                    [valueType]="valueType.BOOLEAN"
 | 
			
		||||
                                    [aliasController]="aliasController"
 | 
			
		||||
                                    [targetDevice]="targetDevice"
 | 
			
		||||
                                    [widgetType]="widgetType"
 | 
			
		||||
 | 
			
		||||
@ -318,6 +318,9 @@ import {
 | 
			
		||||
import {
 | 
			
		||||
  ActionButtonWidgetSettingsComponent
 | 
			
		||||
} from '@home/components/widget/lib/settings/button/action-button-widget-settings.component';
 | 
			
		||||
import {
 | 
			
		||||
  CommandButtonWidgetSettingsComponent
 | 
			
		||||
} from '@home/components/widget/lib/settings/button/command-button-widget-settings.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -432,7 +435,8 @@ import {
 | 
			
		||||
    RangeChartWidgetSettingsComponent,
 | 
			
		||||
    BarChartWithLabelsWidgetSettingsComponent,
 | 
			
		||||
    SingleSwitchWidgetSettingsComponent,
 | 
			
		||||
    ActionButtonWidgetSettingsComponent
 | 
			
		||||
    ActionButtonWidgetSettingsComponent,
 | 
			
		||||
    CommandButtonWidgetSettingsComponent
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@ -552,7 +556,8 @@ import {
 | 
			
		||||
    RangeChartWidgetSettingsComponent,
 | 
			
		||||
    BarChartWithLabelsWidgetSettingsComponent,
 | 
			
		||||
    SingleSwitchWidgetSettingsComponent,
 | 
			
		||||
    ActionButtonWidgetSettingsComponent
 | 
			
		||||
    ActionButtonWidgetSettingsComponent,
 | 
			
		||||
    CommandButtonWidgetSettingsComponent
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class WidgetSettingsModule {
 | 
			
		||||
@ -639,5 +644,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsCo
 | 
			
		||||
  'tb-range-chart-widget-settings': RangeChartWidgetSettingsComponent,
 | 
			
		||||
  'tb-bar-chart-with-labels-widget-settings': BarChartWithLabelsWidgetSettingsComponent,
 | 
			
		||||
  'tb-single-switch-widget-settings': SingleSwitchWidgetSettingsComponent,
 | 
			
		||||
  'tb-action-button-widget-settings': ActionButtonWidgetSettingsComponent
 | 
			
		||||
  'tb-action-button-widget-settings': ActionButtonWidgetSettingsComponent,
 | 
			
		||||
  'tb-command-button-widget-settings': CommandButtonWidgetSettingsComponent
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -72,6 +72,7 @@ import {
 | 
			
		||||
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.component';
 | 
			
		||||
import { SingleSwitchWidgetComponent } from '@home/components/widget/lib/rpc/single-switch-widget.component';
 | 
			
		||||
import { ActionButtonWidgetComponent } from '@home/components/widget/lib/button/action-button-widget.component';
 | 
			
		||||
import { CommandButtonWidgetComponent } from '@home/components/widget/lib/button/command-button-widget.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations:
 | 
			
		||||
@ -116,7 +117,8 @@ import { ActionButtonWidgetComponent } from '@home/components/widget/lib/button/
 | 
			
		||||
      RangeChartWidgetComponent,
 | 
			
		||||
      BarChartWithLabelsWidgetComponent,
 | 
			
		||||
      SingleSwitchWidgetComponent,
 | 
			
		||||
      ActionButtonWidgetComponent
 | 
			
		||||
      ActionButtonWidgetComponent,
 | 
			
		||||
      CommandButtonWidgetComponent
 | 
			
		||||
    ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
@ -165,7 +167,8 @@ import { ActionButtonWidgetComponent } from '@home/components/widget/lib/button/
 | 
			
		||||
        RangeChartWidgetComponent,
 | 
			
		||||
        BarChartWithLabelsWidgetComponent,
 | 
			
		||||
        SingleSwitchWidgetComponent,
 | 
			
		||||
        ActionButtonWidgetComponent
 | 
			
		||||
        ActionButtonWidgetComponent,
 | 
			
		||||
        CommandButtonWidgetComponent
 | 
			
		||||
    ],
 | 
			
		||||
  providers: [
 | 
			
		||||
    {provide: WIDGET_COMPONENTS_MODULE_TOKEN, useValue: WidgetComponentsModule }
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,6 @@
 | 
			
		||||
        [style.pointer-events]="disableEvents ? 'none' : ''">
 | 
			
		||||
  <div #widgetButtonContent class="tb-widget-button-content" *ngIf="appearance.showIcon || appearance.showLabel">
 | 
			
		||||
    <tb-icon matButtonIcon *ngIf="appearance.showIcon" [style]="iconStyle">{{ appearance.icon }}</tb-icon>
 | 
			
		||||
    <span *ngIf="appearance.showLabel" class="tb-widget-button-label">{{ appearance.label }}</span>
 | 
			
		||||
    <span *ngIf="appearance.showLabel" class="tb-widget-button-label">{{ label$ | async }}</span>
 | 
			
		||||
  </div>
 | 
			
		||||
</button>
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,8 @@ import {
 | 
			
		||||
  OnInit,
 | 
			
		||||
  Output,
 | 
			
		||||
  Renderer2,
 | 
			
		||||
  SimpleChanges, ViewChild,
 | 
			
		||||
  SimpleChanges,
 | 
			
		||||
  ViewChild,
 | 
			
		||||
  ViewEncapsulation
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import {
 | 
			
		||||
@ -36,6 +37,8 @@ import { coerceBoolean } from '@shared/decorators/coercion';
 | 
			
		||||
import { ComponentStyle, iconStyle } from '@shared/models/widget-settings.models';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { ResizeObserver } from '@juggle/resize-observer';
 | 
			
		||||
import { Observable, of } from 'rxjs';
 | 
			
		||||
import { WidgetContext } from '@home/models/widget-component.models';
 | 
			
		||||
 | 
			
		||||
const initialButtonHeight = 60;
 | 
			
		||||
const horizontalLayoutPadding = 24;
 | 
			
		||||
@ -81,9 +84,14 @@ export class WidgetButtonComponent implements OnInit, AfterViewInit, OnDestroy,
 | 
			
		||||
  @coerceBoolean()
 | 
			
		||||
  disableEvents = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  ctx: WidgetContext;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  clicked = new EventEmitter<MouseEvent>();
 | 
			
		||||
 | 
			
		||||
  label$: Observable<string>;
 | 
			
		||||
 | 
			
		||||
  iconStyle: ComponentStyle = {};
 | 
			
		||||
 | 
			
		||||
  mousePressed = false;
 | 
			
		||||
@ -122,11 +130,20 @@ export class WidgetButtonComponent implements OnInit, AfterViewInit, OnDestroy,
 | 
			
		||||
    this.clearAppearanceCss();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public validateSize() {
 | 
			
		||||
    if (this.appearance.autoScale && this.widgetButton.nativeElement) {
 | 
			
		||||
      this.onResize();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateAppearance(): void {
 | 
			
		||||
    this.clearAppearanceCss();
 | 
			
		||||
    if (this.appearance.showIcon) {
 | 
			
		||||
      this.iconStyle = iconStyle(this.appearance.iconSize, this.appearance.iconSizeUnit);
 | 
			
		||||
    }
 | 
			
		||||
    if (this.appearance.showLabel) {
 | 
			
		||||
      this.label$ = this.ctx ? this.ctx.registerLabelPattern(this.appearance.label, this.label$) : of(this.appearance.label);
 | 
			
		||||
    }
 | 
			
		||||
    const appearanceCss = generateWidgetButtonAppearanceCss(this.appearance);
 | 
			
		||||
    this.appearanceCssClass = this.utils.applyCssToElement(this.renderer, this.elementRef.nativeElement,
 | 
			
		||||
      'tb-widget-button', appearanceCss);
 | 
			
		||||
 | 
			
		||||
@ -5187,6 +5187,11 @@
 | 
			
		||||
            "on-click": "On click",
 | 
			
		||||
            "on-click-hint": "Action performed when the button is clicked."
 | 
			
		||||
        },
 | 
			
		||||
        "command-button": {
 | 
			
		||||
            "behavior": "Behavior",
 | 
			
		||||
            "on-click": "On click",
 | 
			
		||||
            "on-click-hint": "Action performed when the button is clicked."
 | 
			
		||||
        },
 | 
			
		||||
        "button": {
 | 
			
		||||
            "layout": "Layout",
 | 
			
		||||
            "outlined": "Outlined",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user