21 changed files with 587 additions and 14 deletions
@ -0,0 +1,36 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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. |
|||
|
|||
--> |
|||
<section [formGroup]="qrCodeWidgetSettingsForm" fxLayout="column"> |
|||
<mat-checkbox formControlName="useQrCodeTextFunction" style="padding-bottom: 16px;"> |
|||
{{ 'widgets.qr-code.use-qr-code-text-function' | translate }} |
|||
</mat-checkbox> |
|||
<mat-form-field [fxShow]="qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value === false"> |
|||
<mat-label translate>widgets.qr-code.qr-code-text-pattern</mat-label> |
|||
<input required matInput formControlName="qrCodeTextPattern"> |
|||
<mat-error *ngIf="qrCodeWidgetSettingsForm.get('qrCodeTextPattern').hasError('required')"> |
|||
{{ 'widgets.qr-code.qr-code-text-pattern-required' | translate }} |
|||
</mat-error> |
|||
</mat-form-field> |
|||
<section fxLayout="column" [fxShow]="qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value === true"> |
|||
<label translate class="tb-title no-padding">widgets.qr-code.qr-code-text-function</label> |
|||
<tb-js-func formControlName="qrCodeTextFunction" |
|||
[functionArgs]="['data']" |
|||
helpId="widget/lib/qrcode/qrcode_text_fn"> |
|||
</tb-js-func> |
|||
</section> |
|||
</section> |
|||
@ -0,0 +1,67 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
|
|||
|
|||
@Component({ |
|||
selector: 'tb-qrcode-widget-settings', |
|||
templateUrl: './qrcode-widget-settings.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class QrCodeWidgetSettingsComponent extends WidgetSettingsComponent { |
|||
|
|||
qrCodeWidgetSettingsForm: FormGroup; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private fb: FormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
protected settingsForm(): FormGroup { |
|||
return this.qrCodeWidgetSettingsForm; |
|||
} |
|||
|
|||
protected onSettingsSet(settings: WidgetSettings) { |
|||
this.qrCodeWidgetSettingsForm = this.fb.group({ |
|||
qrCodeTextPattern: [settings ? settings.qrCodeTextPattern : '${entityName}', []], |
|||
useQrCodeTextFunction: [settings ? settings.useQrCodeTextFunction : false, []], |
|||
qrCodeTextFunction: [settings ? settings.qrCodeTextFunction : 'return data[0][\'entityName\'];', []] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['useQrCodeTextFunction']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
const useQrCodeTextFunction: boolean = this.qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value; |
|||
if (useQrCodeTextFunction) { |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').setValidators([]); |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').setValidators([Validators.required]); |
|||
} else { |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').setValidators([Validators.required]); |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').setValidators([]); |
|||
} |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextPattern').updateValueAndValidity({emitEvent}); |
|||
this.qrCodeWidgetSettingsForm.get('qrCodeTextFunction').updateValueAndValidity({emitEvent}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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 { NgModule, Type } from '@angular/core'; |
|||
import { QrCodeWidgetSettingsComponent } from '@home/components/widget/lib/settings/qrcode-widget-settings.component'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module'; |
|||
import { IWidgetSettingsComponent } from '@shared/models/widget.models'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
QrCodeWidgetSettingsComponent |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
SharedHomeComponentsModule |
|||
], |
|||
exports: [ |
|||
QrCodeWidgetSettingsComponent |
|||
] |
|||
}) |
|||
export class WidgetSettingsModule { |
|||
} |
|||
|
|||
export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsComponent>} = { |
|||
'tb-qrcode-widget-settings': QrCodeWidgetSettingsComponent |
|||
}; |
|||
@ -0,0 +1,24 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2022 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 [formGroup]="widgetSettingsFormGroup"> |
|||
<ng-container #definedSettingsContent></ng-container> |
|||
<div class="tb-settings-directive-error" *ngIf="definedDirectiveError">{{definedDirectiveError}}</div> |
|||
<tb-json-form *ngIf="useJsonForm()" #jsonFormComponent |
|||
formControlName="settings"> |
|||
</tb-json-form> |
|||
</div> |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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. |
|||
*/ |
|||
:host { |
|||
.tb-settings-directive-error { |
|||
font-size: 13px; |
|||
font-weight: 400; |
|||
color: rgb(221, 44, 0); |
|||
} |
|||
} |
|||
@ -0,0 +1,201 @@ |
|||
///
|
|||
/// Copyright © 2016-2022 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, |
|||
Component, ComponentFactoryResolver, |
|||
ComponentRef, |
|||
forwardRef, |
|||
Input, |
|||
OnDestroy, |
|||
OnInit, |
|||
ViewChild, |
|||
ViewContainerRef |
|||
} from '@angular/core'; |
|||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
|||
import { |
|||
IRuleNodeConfigurationComponent, |
|||
RuleNodeConfiguration, |
|||
RuleNodeDefinition |
|||
} from '@shared/models/rule-node.models'; |
|||
import { Subscription } from 'rxjs'; |
|||
import { RuleChainService } from '@core/http/rule-chain.service'; |
|||
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; |
|||
import { deepClone } from '@core/utils'; |
|||
import { RuleChainType } from '@shared/models/rule-chain.models'; |
|||
import { JsonFormComponent } from '@shared/components/json-form/json-form.component'; |
|||
import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models'; |
|||
import { IWidgetSettingsComponent, WidgetSettings } from '@shared/models/widget.models'; |
|||
import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-widget-settings', |
|||
templateUrl: './widget-settings.component.html', |
|||
styleUrls: ['./widget-settings.component.scss'], |
|||
providers: [{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => WidgetSettingsComponent), |
|||
multi: true |
|||
}] |
|||
}) |
|||
export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, OnDestroy, AfterViewInit { |
|||
|
|||
@ViewChild('definedSettingsContent', {read: ViewContainerRef, static: true}) definedSettingsContainer: ViewContainerRef; |
|||
|
|||
@ViewChild('jsonFormComponent') jsonFormComponent: JsonFormComponent; |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
settingsDirectiveValue: string; |
|||
|
|||
@Input() |
|||
set settingsDirective(settingsDirective: string) { |
|||
if (this.settingsDirectiveValue !== settingsDirective) { |
|||
this.settingsDirectiveValue = settingsDirective; |
|||
if (this.settingsDirectiveValue) { |
|||
this.validateDefinedDirective(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
get settingsDirective(): string { |
|||
return this.settingsDirectiveValue; |
|||
} |
|||
|
|||
definedDirectiveError: string; |
|||
|
|||
widgetSettingsFormGroup: FormGroup; |
|||
|
|||
changeSubscription: Subscription; |
|||
|
|||
private definedSettingsComponentRef: ComponentRef<IWidgetSettingsComponent>; |
|||
private definedSettingsComponent: IWidgetSettingsComponent; |
|||
|
|||
private widgetSettingsFormData: JsonFormComponentData; |
|||
|
|||
private propagateChange = (v: any) => { }; |
|||
|
|||
constructor(private translate: TranslateService, |
|||
private cfr: ComponentFactoryResolver, |
|||
private fb: FormBuilder) { |
|||
this.widgetSettingsFormGroup = this.fb.group({ |
|||
settings: [null, Validators.required] |
|||
}); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
} |
|||
|
|||
ngOnDestroy(): void { |
|||
if (this.definedSettingsComponentRef) { |
|||
this.definedSettingsComponentRef.destroy(); |
|||
} |
|||
} |
|||
|
|||
ngAfterViewInit(): void { |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (this.disabled) { |
|||
this.widgetSettingsFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.widgetSettingsFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: JsonFormComponentData): void { |
|||
this.widgetSettingsFormData = value; |
|||
if (this.changeSubscription) { |
|||
this.changeSubscription.unsubscribe(); |
|||
this.changeSubscription = null; |
|||
} |
|||
if (this.definedSettingsComponent) { |
|||
this.definedSettingsComponent.settings = this.widgetSettingsFormData.model; |
|||
this.changeSubscription = this.definedSettingsComponent.settingsChanged.subscribe((settings) => { |
|||
this.updateModel(settings); |
|||
}); |
|||
} else { |
|||
this.widgetSettingsFormGroup.get('settings').patchValue(this.widgetSettingsFormData, {emitEvent: false}); |
|||
this.changeSubscription = this.widgetSettingsFormGroup.get('settings').valueChanges.subscribe( |
|||
(widgetSettingsFormData: JsonFormComponentData) => { |
|||
this.updateModel(widgetSettingsFormData.model); |
|||
} |
|||
); |
|||
} |
|||
} |
|||
|
|||
useDefinedDirective(): boolean { |
|||
return this.settingsDirective && |
|||
this.settingsDirective.length && !this.definedDirectiveError; |
|||
} |
|||
|
|||
useJsonForm(): boolean { |
|||
return !this.settingsDirective || !this.settingsDirective.length; |
|||
} |
|||
|
|||
private updateModel(settings: WidgetSettings) { |
|||
this.widgetSettingsFormData.model = settings; |
|||
if (this.definedSettingsComponent || this.widgetSettingsFormGroup.valid) { |
|||
this.propagateChange(this.widgetSettingsFormData); |
|||
} else { |
|||
this.propagateChange(null); |
|||
} |
|||
} |
|||
|
|||
private validateDefinedDirective() { |
|||
if (this.definedSettingsComponentRef) { |
|||
this.definedSettingsComponentRef.destroy(); |
|||
this.definedSettingsComponentRef = null; |
|||
} |
|||
if (this.settingsDirective && this.settingsDirective.length) { |
|||
const componentType = widgetSettingsComponentsMap[this.settingsDirective]; |
|||
if (!componentType) { |
|||
this.definedDirectiveError = this.translate.instant('widget-config.settings-component-not-found', |
|||
{selector: this.settingsDirective}); |
|||
} else { |
|||
if (this.changeSubscription) { |
|||
this.changeSubscription.unsubscribe(); |
|||
this.changeSubscription = null; |
|||
} |
|||
this.definedSettingsContainer.clear(); |
|||
const factory = this.cfr.resolveComponentFactory(componentType); |
|||
this.definedSettingsComponentRef = this.definedSettingsContainer.createComponent(factory); |
|||
this.definedSettingsComponent = this.definedSettingsComponentRef.instance; |
|||
this.definedSettingsComponent.settings = this.widgetSettingsFormData?.model; |
|||
this.changeSubscription = this.definedSettingsComponent.settingsChanged.subscribe((settings) => { |
|||
this.updateModel(settings); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
validate() { |
|||
if (this.useDefinedDirective()) { |
|||
this.definedSettingsComponent.validate(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue