|
1
|
+///
|
|
2
|
+/// Copyright © 2016-2020 The Thingsboard Authors
|
|
3
|
+///
|
|
4
|
+/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+/// you may not use this file except in compliance with the License.
|
|
6
|
+/// You may obtain a copy of the License at
|
|
7
|
+///
|
|
8
|
+/// http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+///
|
|
10
|
+/// Unless required by applicable law or agreed to in writing, software
|
|
11
|
+/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+/// See the License for the specific language governing permissions and
|
|
14
|
+/// limitations under the License.
|
|
15
|
+///
|
|
16
|
+
|
|
17
|
+import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
|
|
18
|
+import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
19
|
+import { Observable } from 'rxjs';
|
|
20
|
+import { map, mergeMap, share, tap } from 'rxjs/operators';
|
|
21
|
+import { Store } from '@ngrx/store';
|
|
22
|
+import { AppState } from '@core/core.state';
|
|
23
|
+import { TranslateService } from '@ngx-translate/core';
|
|
24
|
+import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
25
|
+import { EntityId } from '@shared/models/id/entity-id';
|
|
26
|
+import { EntityType } from '@shared/models/entity-type.models';
|
|
27
|
+import { BaseData } from '@shared/models/base-data';
|
|
28
|
+import { EntityService } from '@core/http/entity.service';
|
|
29
|
+import { TruncatePipe } from '@shared/pipe/truncate.pipe';
|
|
30
|
+import { RuleChainService } from '@core/http/rule-chain.service';
|
|
31
|
+import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
|
|
32
|
+
|
|
33
|
+@Component({
|
|
34
|
+ selector: 'tb-rule-chain-autocomplete',
|
|
35
|
+ templateUrl: './rule-chain-autocomplete.component.html',
|
|
36
|
+ styleUrls: [],
|
|
37
|
+ providers: [{
|
|
38
|
+ provide: NG_VALUE_ACCESSOR,
|
|
39
|
+ useExisting: forwardRef(() => RuleChainAutocompleteComponent),
|
|
40
|
+ multi: true
|
|
41
|
+ }]
|
|
42
|
+})
|
|
43
|
+export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnInit {
|
|
44
|
+
|
|
45
|
+ selectRuleChainFormGroup: FormGroup;
|
|
46
|
+
|
|
47
|
+ ruleChainLabel = 'rulechain.rulechain';
|
|
48
|
+
|
|
49
|
+ modelValue: string | null;
|
|
50
|
+
|
|
51
|
+ @Input()
|
|
52
|
+ labelText: string;
|
|
53
|
+
|
|
54
|
+ @Input()
|
|
55
|
+ requiredText: string;
|
|
56
|
+
|
|
57
|
+ private requiredValue: boolean;
|
|
58
|
+ get required(): boolean {
|
|
59
|
+ return this.requiredValue;
|
|
60
|
+ }
|
|
61
|
+ @Input()
|
|
62
|
+ set required(value: boolean) {
|
|
63
|
+ this.requiredValue = coerceBooleanProperty(value);
|
|
64
|
+ }
|
|
65
|
+
|
|
66
|
+ @Input()
|
|
67
|
+ disabled: boolean;
|
|
68
|
+
|
|
69
|
+ @ViewChild('entityInput', {static: true}) entityInput: ElementRef;
|
|
70
|
+
|
|
71
|
+ filteredRuleChains: Observable<Array<BaseData<EntityId>>>;
|
|
72
|
+
|
|
73
|
+ searchText = '';
|
|
74
|
+
|
|
75
|
+ private dirty = false;
|
|
76
|
+
|
|
77
|
+ private propagateChange = (v: any) => { };
|
|
78
|
+
|
|
79
|
+ constructor(private store: Store<AppState>,
|
|
80
|
+ public translate: TranslateService,
|
|
81
|
+ public truncate: TruncatePipe,
|
|
82
|
+ private entityService: EntityService,
|
|
83
|
+ private ruleChainService: RuleChainService,
|
|
84
|
+ private fb: FormBuilder) {
|
|
85
|
+ this.selectRuleChainFormGroup = this.fb.group({
|
|
86
|
+ ruleChainId: [null]
|
|
87
|
+ });
|
|
88
|
+ }
|
|
89
|
+
|
|
90
|
+ registerOnChange(fn: any): void {
|
|
91
|
+ this.propagateChange = fn;
|
|
92
|
+ }
|
|
93
|
+
|
|
94
|
+ registerOnTouched(fn: any): void {
|
|
95
|
+ }
|
|
96
|
+
|
|
97
|
+ ngOnInit() {
|
|
98
|
+ this.filteredRuleChains = this.selectRuleChainFormGroup.get('ruleChainId').valueChanges
|
|
99
|
+ .pipe(
|
|
100
|
+ tap(value => {
|
|
101
|
+ let modelValue;
|
|
102
|
+ if (typeof value === 'string' || !value) {
|
|
103
|
+ modelValue = null;
|
|
104
|
+ } else {
|
|
105
|
+ modelValue = value.id.id;
|
|
106
|
+ }
|
|
107
|
+ this.updateView(modelValue);
|
|
108
|
+ if (value === null) {
|
|
109
|
+ this.clear();
|
|
110
|
+ }
|
|
111
|
+ }), map(value => value ? (typeof value === 'string' ? value : value.name) : ''),
|
|
112
|
+ mergeMap(name => this.fetchRuleChain(name) ),
|
|
113
|
+ share()
|
|
114
|
+ );
|
|
115
|
+ }
|
|
116
|
+
|
|
117
|
+ ngAfterViewInit(): void {}
|
|
118
|
+
|
|
119
|
+ getCurrentEntity(): BaseData<EntityId> | null {
|
|
120
|
+ const currentEntity = this.selectRuleChainFormGroup.get('ruleChainId').value;
|
|
121
|
+ if (currentEntity && typeof currentEntity !== 'string') {
|
|
122
|
+ return currentEntity as BaseData<EntityId>;
|
|
123
|
+ } else {
|
|
124
|
+ return null;
|
|
125
|
+ }
|
|
126
|
+ }
|
|
127
|
+
|
|
128
|
+ setDisabledState(isDisabled: boolean): void {
|
|
129
|
+ this.disabled = isDisabled;
|
|
130
|
+ if (this.disabled) {
|
|
131
|
+ this.selectRuleChainFormGroup.disable({emitEvent: false});
|
|
132
|
+ } else {
|
|
133
|
+ this.selectRuleChainFormGroup.enable({emitEvent: false});
|
|
134
|
+ }
|
|
135
|
+ }
|
|
136
|
+
|
|
137
|
+ textIsNotEmpty(text: string): boolean {
|
|
138
|
+ return (text && text.length > 0);
|
|
139
|
+ }
|
|
140
|
+
|
|
141
|
+ writeValue(value: string | null): void {
|
|
142
|
+ this.searchText = '';
|
|
143
|
+ if (value != null) {
|
|
144
|
+ const targetEntityType = EntityType.RULE_CHAIN;
|
|
145
|
+ this.entityService.getEntity(targetEntityType, value, {ignoreLoading: true, ignoreErrors: true}).subscribe(
|
|
146
|
+ (entity) => {
|
|
147
|
+ this.modelValue = entity.id.id;
|
|
148
|
+ this.selectRuleChainFormGroup.get('ruleChainId').patchValue(entity, {emitEvent: false});
|
|
149
|
+ },
|
|
150
|
+ () => {
|
|
151
|
+ this.modelValue = null;
|
|
152
|
+ this.selectRuleChainFormGroup.get('ruleChainId').patchValue('', {emitEvent: false});
|
|
153
|
+ if (value !== null) {
|
|
154
|
+ this.propagateChange(this.modelValue);
|
|
155
|
+ }
|
|
156
|
+ }
|
|
157
|
+ );
|
|
158
|
+ } else {
|
|
159
|
+ this.modelValue = null;
|
|
160
|
+ this.selectRuleChainFormGroup.get('ruleChainId').patchValue('', {emitEvent: false});
|
|
161
|
+ }
|
|
162
|
+ this.dirty = true;
|
|
163
|
+ }
|
|
164
|
+
|
|
165
|
+ onFocus() {
|
|
166
|
+ if (this.dirty) {
|
|
167
|
+ this.selectRuleChainFormGroup.get('ruleChainId').updateValueAndValidity({onlySelf: true, emitEvent: true});
|
|
168
|
+ this.dirty = false;
|
|
169
|
+ }
|
|
170
|
+ }
|
|
171
|
+
|
|
172
|
+ reset() {
|
|
173
|
+ this.selectRuleChainFormGroup.get('ruleChainId').patchValue('', {emitEvent: false});
|
|
174
|
+ }
|
|
175
|
+
|
|
176
|
+ updateView(value: string | null) {
|
|
177
|
+ if (this.modelValue !== value) {
|
|
178
|
+ this.modelValue = value;
|
|
179
|
+ this.propagateChange(this.modelValue);
|
|
180
|
+ }
|
|
181
|
+ }
|
|
182
|
+
|
|
183
|
+ displayEntityFn(entity?: BaseData<EntityId>): string | undefined {
|
|
184
|
+ return entity ? entity.name : undefined;
|
|
185
|
+ }
|
|
186
|
+
|
|
187
|
+ fetchRuleChain(searchText?: string): Observable<Array<BaseData<EntityId>>> {
|
|
188
|
+ this.searchText = searchText;
|
|
189
|
+ return this.entityService.getEntitiesByNameFilter(EntityType.RULE_CHAIN, searchText,
|
|
190
|
+ 50, null, {ignoreLoading: true});
|
|
191
|
+ }
|
|
192
|
+
|
|
193
|
+ clear() {
|
|
194
|
+ this.selectRuleChainFormGroup.get('ruleChainId').patchValue('', {emitEvent: true});
|
|
195
|
+ setTimeout(() => {
|
|
196
|
+ this.entityInput.nativeElement.blur();
|
|
197
|
+ this.entityInput.nativeElement.focus();
|
|
198
|
+ }, 0);
|
|
199
|
+ }
|
|
200
|
+
|
|
201
|
+ createDefaultRuleChain($event: Event, ruleChainName: string) {
|
|
202
|
+ this.ruleChainService.createDefaultRuleChain(ruleChainName).subscribe((ruleChain) => {
|
|
203
|
+ this.updateView(ruleChain.id.id);
|
|
204
|
+ });
|
|
205
|
+ }
|
|
206
|
+} |
...
|
...
|
|