20 changed files with 1217 additions and 323 deletions
@ -0,0 +1,56 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<form #ruleNodeLinkForm="ngForm" [formGroup]="ruleNodeLinkFormGroup" (ngSubmit)="add()" style="width: 900px;"> |
||||
|
<mat-toolbar fxLayout="row" color="primary"> |
||||
|
<h2 translate>rulenode.add-link</h2> |
||||
|
<span fxFlex></span> |
||||
|
<div [tb-help]="'ruleEngine'"></div> |
||||
|
<button mat-button mat-icon-button |
||||
|
(click)="cancel()" |
||||
|
type="button"> |
||||
|
<mat-icon class="material-icons">close</mat-icon> |
||||
|
</button> |
||||
|
</mat-toolbar> |
||||
|
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async"> |
||||
|
</mat-progress-bar> |
||||
|
<div mat-dialog-content> |
||||
|
<fieldset [disabled]="isLoading$ | async"> |
||||
|
<tb-rule-node-link |
||||
|
required |
||||
|
formControlName="link" |
||||
|
[allowedLabels]="labels" |
||||
|
[allowCustom]="allowCustomLabels"> |
||||
|
</tb-rule-node-link> |
||||
|
</fieldset> |
||||
|
</div> |
||||
|
<div mat-dialog-actions fxLayout="row"> |
||||
|
<span fxFlex></span> |
||||
|
<button mat-button mat-raised-button color="primary" |
||||
|
type="submit" |
||||
|
[disabled]="(isLoading$ | async) || ruleNodeLinkFormGroup.invalid || !ruleNodeLinkFormGroup.dirty"> |
||||
|
{{ 'action.add' | translate }} |
||||
|
</button> |
||||
|
<button mat-button color="primary" |
||||
|
style="margin-right: 20px;" |
||||
|
type="button" |
||||
|
[disabled]="(isLoading$ | async)" |
||||
|
(click)="cancel()" cdkFocusInitial> |
||||
|
{{ 'action.cancel' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</form> |
||||
@ -0,0 +1,22 @@ |
|||||
|
/** |
||||
|
* 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. |
||||
|
*/ |
||||
|
:host ::ng-deep { |
||||
|
tb-rule-node-link { |
||||
|
form { |
||||
|
overflow: hidden !important; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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-form-field [formGroup]="linksFormGroup" style="width: 100%;"> |
||||
|
<mat-label translate>rulenode.link-labels</mat-label> |
||||
|
<mat-chip-list #chipList> |
||||
|
<mat-chip |
||||
|
*ngFor="let label of labels" |
||||
|
[selectable]="!disabled" |
||||
|
[removable]="!disabled" |
||||
|
(removed)="remove(label)"> |
||||
|
{{label.name}} |
||||
|
<mat-icon matChipRemove *ngIf="!disabled">close</mat-icon> |
||||
|
</mat-chip> |
||||
|
<input matInput type="text" placeholder="{{ !disabled ? ('rulenode.link-label' | translate) : '' }}" |
||||
|
style="max-width: 200px;" |
||||
|
#labelInput |
||||
|
formControlName="label" |
||||
|
matAutocompleteOrigin |
||||
|
#origin="matAutocompleteOrigin" |
||||
|
[matAutocompleteConnectedTo]="origin" |
||||
|
[matAutocomplete]="labelAutocomplete" |
||||
|
[matChipInputFor]="chipList" |
||||
|
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" |
||||
|
(matChipInputTokenEnd)="add($event)"> |
||||
|
</mat-chip-list> |
||||
|
<mat-autocomplete #labelAutocomplete="matAutocomplete" |
||||
|
class="tb-autocomplete" |
||||
|
(optionSelected)="selected($event)" |
||||
|
[displayWith]="displayLabelFn"> |
||||
|
<mat-option *ngFor="let label of filteredLabels | async" [value]="label"> |
||||
|
<span [innerHTML]="label.name | highlight:searchText"></span> |
||||
|
</mat-option> |
||||
|
<mat-option *ngIf="!(filteredLabels | async)?.length" [value]="null" class="tb-not-found"> |
||||
|
<div class="tb-not-found-content" (click)="$event.stopPropagation()"> |
||||
|
<div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty"> |
||||
|
<span translate>rulenode.no-link-labels-found</span> |
||||
|
</div> |
||||
|
<ng-template #searchNotEmpty> |
||||
|
<span> |
||||
|
{{ translate.get('rulenode.no-link-label-matching', |
||||
|
{label: truncate.transform(searchText, true, 6, '...')}) | async }} |
||||
|
</span> |
||||
|
</ng-template> |
||||
|
<span *ngIf="allowCustom"> |
||||
|
<a translate (click)="createLinkLabel($event, searchText)">rulenode.create-new-link-label</a> |
||||
|
</span> |
||||
|
</div> |
||||
|
</mat-option> |
||||
|
</mat-autocomplete> |
||||
|
</mat-form-field> |
||||
@ -0,0 +1,271 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
import { |
||||
|
AfterViewInit, |
||||
|
Component, ElementRef, |
||||
|
EventEmitter, forwardRef, |
||||
|
Input, |
||||
|
OnChanges, |
||||
|
OnInit, |
||||
|
Output, |
||||
|
SimpleChanges, |
||||
|
ViewChild |
||||
|
} from '@angular/core'; |
||||
|
import { PageComponent } from '@shared/components/page.component'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgForm, Validators } from '@angular/forms'; |
||||
|
import { FcRuleNode, FcRuleEdge } from './rulechain-page.models'; |
||||
|
import { RuleNodeType, LinkLabel } from '@shared/models/rule-node.models'; |
||||
|
import { EntityType } from '@shared/models/entity-type.models'; |
||||
|
import { Observable, of, Subscription } from 'rxjs'; |
||||
|
import { RuleChainService } from '@core/http/rule-chain.service'; |
||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
import { EntityAlias } from '@shared/models/alias.models'; |
||||
|
import { TruncatePipe } from '@shared/pipe/truncate.pipe'; |
||||
|
import { MatChipList, MatAutocomplete, MatChipInputEvent, MatAutocompleteSelectedEvent } from '@angular/material'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
||||
|
import { map, mergeMap, share, startWith } from 'rxjs/operators'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-link-labels', |
||||
|
templateUrl: './link-labels.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => LinkLabelsComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class LinkLabelsComponent implements ControlValueAccessor, OnInit, OnChanges { |
||||
|
|
||||
|
@ViewChild('chipList', {static: false}) chipList: MatChipList; |
||||
|
@ViewChild('labelAutocomplete', {static: false}) matAutocomplete: MatAutocomplete; |
||||
|
@ViewChild('labelInput', {static: false}) labelInput: ElementRef<HTMLInputElement>; |
||||
|
|
||||
|
private requiredValue: boolean; |
||||
|
get required(): boolean { |
||||
|
return this.requiredValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set required(value: boolean) { |
||||
|
this.requiredValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
private allowCustomValue: boolean; |
||||
|
get allowCustom(): boolean { |
||||
|
return this.allowCustomValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set allowCustom(value: boolean) { |
||||
|
this.allowCustomValue = coerceBooleanProperty(value); |
||||
|
this.separatorKeysCodes = this.allowCustomValue ? [ENTER, COMMA, SEMICOLON] : []; |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
allowedLabels: {[label: string]: LinkLabel}; |
||||
|
|
||||
|
linksFormGroup: FormGroup; |
||||
|
|
||||
|
modelValue: Array<string>; |
||||
|
|
||||
|
private labelsList: Array<LinkLabel> = []; |
||||
|
|
||||
|
separatorKeysCodes: number[] = []; |
||||
|
|
||||
|
filteredLabels: Observable<Array<LinkLabel>>; |
||||
|
|
||||
|
private labels: Array<LinkLabel> = []; |
||||
|
|
||||
|
private searchText = ''; |
||||
|
|
||||
|
private propagateChange = (v: any) => { }; |
||||
|
|
||||
|
constructor(private fb: FormBuilder, |
||||
|
public truncate: TruncatePipe, |
||||
|
public translate: TranslateService) { |
||||
|
this.linksFormGroup = this.fb.group({ |
||||
|
label: [null] |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.filteredLabels = this.linksFormGroup.get('label').valueChanges |
||||
|
.pipe( |
||||
|
startWith(''), |
||||
|
map((value) => value ? value : ''), |
||||
|
mergeMap(name => this.fetchLabels(name) ), |
||||
|
share() |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
ngOnChanges(changes: SimpleChanges): void { |
||||
|
let reloadLabels = false; |
||||
|
for (const propName of Object.keys(changes)) { |
||||
|
const change = changes[propName]; |
||||
|
if (change.currentValue !== change.previousValue) { |
||||
|
if (['allowCustom', 'allowedLabels'].includes(propName)) { |
||||
|
reloadLabels = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (reloadLabels) { |
||||
|
this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.linksFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.linksFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: string[]): void { |
||||
|
this.searchText = ''; |
||||
|
this.labelsList.length = 0; |
||||
|
this.labels.length = 0; |
||||
|
this.modelValue = value; |
||||
|
for (const label of Object.keys(this.allowedLabels)) { |
||||
|
this.labelsList.push({name: this.allowedLabels[label].name, value: this.allowedLabels[label].value}); |
||||
|
} |
||||
|
if (value) { |
||||
|
value.forEach((label) => { |
||||
|
if (this.allowedLabels[label]) { |
||||
|
this.labels.push(deepClone(this.allowedLabels[label])); |
||||
|
} else { |
||||
|
this.labels.push({ |
||||
|
name: label, |
||||
|
value: label |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
if (this.chipList && this.required) { |
||||
|
this.chipList.errorState = this.labels.length ? false : true; |
||||
|
} |
||||
|
this.linksFormGroup.get('label').patchValue('', {emitEvent: true}); |
||||
|
} |
||||
|
|
||||
|
displayLabelFn(label?: LinkLabel): string | undefined { |
||||
|
return label ? label.name : undefined; |
||||
|
} |
||||
|
|
||||
|
textIsNotEmpty(text: string): boolean { |
||||
|
return (text && text != null && text.length > 0) ? true : false; |
||||
|
} |
||||
|
|
||||
|
createLinkLabel($event: Event, value: string) { |
||||
|
$event.preventDefault(); |
||||
|
this.transformLinkLabel(value); |
||||
|
} |
||||
|
|
||||
|
add(event: MatChipInputEvent): void { |
||||
|
if (!this.matAutocomplete.isOpen) { |
||||
|
this.transformLinkLabel(event.value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private fetchLabels(searchText?: string): Observable<Array<LinkLabel>> { |
||||
|
this.searchText = searchText; |
||||
|
if (this.searchText && this.searchText.length) { |
||||
|
const search = this.searchText.toUpperCase(); |
||||
|
return of(this.labelsList.filter(label => label.name.toUpperCase().includes(search))); |
||||
|
} else { |
||||
|
return of(this.labelsList); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private transformLinkLabel(value: string) { |
||||
|
if ((value || '').trim()) { |
||||
|
let newLabel: LinkLabel = null; |
||||
|
const labelName = value.trim(); |
||||
|
const existingLabel = this.labelsList.find(label => label.name === labelName); |
||||
|
if (existingLabel) { |
||||
|
newLabel = deepClone(existingLabel); |
||||
|
} else if (this.allowCustom) { |
||||
|
newLabel = { |
||||
|
name: labelName, |
||||
|
value: labelName |
||||
|
}; |
||||
|
} |
||||
|
if (newLabel) { |
||||
|
this.addLabel(newLabel); |
||||
|
} |
||||
|
} |
||||
|
this.clear(''); |
||||
|
} |
||||
|
|
||||
|
remove(label: LinkLabel) { |
||||
|
const index = this.labels.indexOf(label); |
||||
|
if (index >= 0) { |
||||
|
this.labels.splice(index, 1); |
||||
|
if (!this.labels.length) { |
||||
|
if (this.required) { |
||||
|
this.chipList.errorState = true; |
||||
|
} |
||||
|
} |
||||
|
this.updateModel(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
selected(event: MatAutocompleteSelectedEvent): void { |
||||
|
this.addLabel(event.option.value); |
||||
|
this.clear(''); |
||||
|
} |
||||
|
|
||||
|
addLabel(label: LinkLabel): void { |
||||
|
const index = this.labels.findIndex(existinglabel => existinglabel.value === label.value); |
||||
|
if (index === -1) { |
||||
|
this.labels.push(label); |
||||
|
if (this.required) { |
||||
|
this.chipList.errorState = false; |
||||
|
} |
||||
|
} |
||||
|
this.updateModel(); |
||||
|
} |
||||
|
|
||||
|
clear(value: string = '') { |
||||
|
this.labelInput.nativeElement.value = value; |
||||
|
this.linksFormGroup.get('label').patchValue(null, {emitEvent: true}); |
||||
|
setTimeout(() => { |
||||
|
this.labelInput.nativeElement.blur(); |
||||
|
this.labelInput.nativeElement.focus(); |
||||
|
}, 0); |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
const labels = this.labels.map((label => label.value)); |
||||
|
this.propagateChange(labels); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,28 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<div class="mat-padding" fxLayout="column"> |
||||
|
<form #ruleNodeLinkForm="ngForm" [formGroup]="ruleNodeLinkFormGroup"> |
||||
|
<tb-link-labels |
||||
|
fxFlex |
||||
|
required |
||||
|
formControlName="labels" |
||||
|
[allowedLabels]="allowedLabels" |
||||
|
[allowCustom]="allowCustom" |
||||
|
></tb-link-labels> |
||||
|
</form> |
||||
|
</div> |
||||
@ -0,0 +1,135 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
import { |
||||
|
AfterViewInit, |
||||
|
Component, ElementRef, |
||||
|
EventEmitter, forwardRef, |
||||
|
Input, |
||||
|
OnChanges, |
||||
|
OnInit, |
||||
|
Output, |
||||
|
SimpleChanges, |
||||
|
ViewChild |
||||
|
} from '@angular/core'; |
||||
|
import { PageComponent } from '@shared/components/page.component'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, NgForm, Validators } from '@angular/forms'; |
||||
|
import { FcRuleNode, FcRuleEdge } from './rulechain-page.models'; |
||||
|
import { RuleNodeType, LinkLabel } from '@shared/models/rule-node.models'; |
||||
|
import { EntityType } from '@shared/models/entity-type.models'; |
||||
|
import { Observable, of, Subscription } from 'rxjs'; |
||||
|
import { RuleChainService } from '@core/http/rule-chain.service'; |
||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
import { EntityAlias } from '@shared/models/alias.models'; |
||||
|
import { TruncatePipe } from '@shared/pipe/truncate.pipe'; |
||||
|
import { MatChipList, MatAutocomplete, MatChipInputEvent, MatAutocompleteSelectedEvent } from '@angular/material'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; |
||||
|
import { map, mergeMap, share } from 'rxjs/operators'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-rule-node-link', |
||||
|
templateUrl: './rule-node-link.component.html', |
||||
|
styleUrls: [], |
||||
|
providers: [{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => RuleNodeLinkComponent), |
||||
|
multi: true |
||||
|
}] |
||||
|
}) |
||||
|
export class RuleNodeLinkComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
@ViewChild('ruleNodeLinkForm', {static: true}) ruleNodeLinkForm: NgForm; |
||||
|
|
||||
|
private requiredValue: boolean; |
||||
|
get required(): boolean { |
||||
|
return this.requiredValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set required(value: boolean) { |
||||
|
this.requiredValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
private allowCustomValue: boolean; |
||||
|
get allowCustom(): boolean { |
||||
|
return this.allowCustomValue; |
||||
|
} |
||||
|
@Input() |
||||
|
set allowCustom(value: boolean) { |
||||
|
this.allowCustomValue = coerceBooleanProperty(value); |
||||
|
} |
||||
|
|
||||
|
@Input() |
||||
|
allowedLabels: {[label: string]: LinkLabel}; |
||||
|
|
||||
|
ruleNodeLinkFormGroup: FormGroup; |
||||
|
|
||||
|
modelValue: FcRuleEdge; |
||||
|
|
||||
|
private propagateChange = (v: any) => { }; |
||||
|
|
||||
|
constructor(private fb: FormBuilder, |
||||
|
public truncate: TruncatePipe, |
||||
|
public translate: TranslateService) { |
||||
|
this.ruleNodeLinkFormGroup = this.fb.group({ |
||||
|
labels: [[], Validators.required] |
||||
|
}); |
||||
|
this.ruleNodeLinkFormGroup.get('labels').valueChanges.subscribe( |
||||
|
(labels: string[]) => this.updateModel(labels) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (this.disabled) { |
||||
|
this.ruleNodeLinkFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.ruleNodeLinkFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: FcRuleEdge): void { |
||||
|
this.modelValue = value; |
||||
|
const labels = this.modelValue && this.modelValue.labels ? this.modelValue.labels : []; |
||||
|
this.ruleNodeLinkFormGroup.get('labels').patchValue(labels, {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
private updateModel(labels: string[]) { |
||||
|
if (labels && labels.length) { |
||||
|
this.modelValue.labels = labels; |
||||
|
this.modelValue.label = labels.join(' / '); |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} else { |
||||
|
this.propagateChange(this.required ? null : this.modelValue); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,70 +0,0 @@ |
|||||
/** |
|
||||
* 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. |
|
||||
*/ |
|
||||
.tooltipster-base { |
|
||||
.tb-rule-node-tooltip, |
|
||||
.tb-rule-node-help { |
|
||||
color: #333; |
|
||||
} |
|
||||
|
|
||||
.tb-rule-node-tooltip { |
|
||||
max-width: 300px; |
|
||||
font-size: 14px; |
|
||||
|
|
||||
&.tb-lib-tooltip { |
|
||||
width: 300px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.tb-rule-node-help { |
|
||||
font-size: 16px; |
|
||||
} |
|
||||
|
|
||||
.tb-rule-node-error-tooltip { |
|
||||
font-size: 16px; |
|
||||
color: #ea0d0d; |
|
||||
} |
|
||||
|
|
||||
.tb-rule-node-tooltip, |
|
||||
.tb-rule-node-error-tooltip, |
|
||||
.tb-rule-node-help { |
|
||||
#tb-node-content { |
|
||||
.tb-node-title { |
|
||||
font-weight: 600; |
|
||||
} |
|
||||
|
|
||||
.tb-node-description { |
|
||||
font-style: italic; |
|
||||
color: #555; |
|
||||
} |
|
||||
|
|
||||
.tb-node-details { |
|
||||
padding-top: 10px; |
|
||||
padding-bottom: 10px; |
|
||||
} |
|
||||
|
|
||||
code { |
|
||||
padding: 0 3px 2px 3px; |
|
||||
margin: 1px; |
|
||||
font-size: 12px; |
|
||||
color: #ad1625; |
|
||||
white-space: nowrap; |
|
||||
background-color: #f7f7f9; |
|
||||
border: 1px solid #e1e1e8; |
|
||||
border-radius: 2px; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue