123 changed files with 1447 additions and 573 deletions
@ -1,36 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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. |
|||
*/ |
|||
package org.thingsboard.server.queue.edqs; |
|||
|
|||
import lombok.Getter; |
|||
|
|||
@Getter |
|||
public enum EdqsQueue { |
|||
|
|||
EVENTS("edqs.events", false, false), |
|||
STATE("edqs.state", true, true); |
|||
|
|||
private final String topic; |
|||
private final boolean readFromBeginning; |
|||
private final boolean stopWhenRead; |
|||
|
|||
EdqsQueue(String topic, boolean readFromBeginning, boolean stopWhenRead) { |
|||
this.topic = topic; |
|||
this.readFromBeginning = readFromBeginning; |
|||
this.stopWhenRead = stopWhenRead; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2025 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]="dataSourceFormGroup" class="tb-form-table-row tb-additional-map-data-source-row"> |
|||
<div class="tb-source-field"> |
|||
<mat-form-field class="tb-ds-type-field tb-inline-field" appearance="outline" subscriptSizing="dynamic"> |
|||
<mat-select formControlName="dsType"> |
|||
<mat-option *ngFor="let type of datasourceTypes" [value]="type"> |
|||
{{ datasourceTypesTranslations.get(type) | translate }} |
|||
</mat-option> |
|||
</mat-select> |
|||
</mat-form-field> |
|||
<mat-form-field |
|||
*ngIf="dataSourceFormGroup.get('dsType').value === DatasourceType.function" |
|||
class="tb-label-field tb-inline-field" appearance="outline" subscriptSizing="dynamic"> |
|||
<input matInput formControlName="dsLabel" placeholder="{{ 'widget-config.set' | translate }}"> |
|||
</mat-form-field> |
|||
<tb-entity-autocomplete |
|||
class="tb-device-field" |
|||
*ngIf="dataSourceFormGroup.get('dsType').value === DatasourceType.device" |
|||
required |
|||
inlineField |
|||
placeholder="{{ 'device.select-device' | translate }}" |
|||
[entityType]="EntityType.DEVICE" |
|||
formControlName="dsDeviceId"> |
|||
</tb-entity-autocomplete> |
|||
<tb-entity-alias-select |
|||
class="tb-entity-alias-field" |
|||
*ngIf="dataSourceFormGroup.get('dsType').value === DatasourceType.entity" |
|||
inlineField |
|||
tbRequired |
|||
[aliasController]="context.aliasController" |
|||
formControlName="dsEntityAliasId" |
|||
[callbacks]="context.callbacks"> |
|||
</tb-entity-alias-select> |
|||
</div> |
|||
<tb-data-keys |
|||
class="tb-data-keys-field" |
|||
formControlName="dataKeys" |
|||
inlineField |
|||
hideDataKeyColor |
|||
hideDataKeyDecimals |
|||
hideDataKeyUnits |
|||
disableDrag |
|||
[required]="true" |
|||
[widgetType]="widgetType.latest" |
|||
[widget]="context.widget" |
|||
[datasourceType]="dataSourceFormGroup.get('dsType').value" |
|||
[entityAliasId]="dataSourceFormGroup.get('dsEntityAliasId').value" |
|||
[deviceId]="dataSourceFormGroup.get('dsDeviceId').value" |
|||
[aliasController]="context.aliasController" |
|||
[callbacks]="context.callbacks" |
|||
[generateKey]="generateAdditionalDataKey"> |
|||
</tb-data-keys> |
|||
<div class="tb-form-table-row-cell-buttons"> |
|||
<div class="tb-remove-button"> |
|||
<button type="button" |
|||
mat-icon-button |
|||
(click)="dataSourceRemoved.emit()" |
|||
matTooltip="{{ 'widgets.maps.data-layer.remove-datasource' | translate }}" |
|||
matTooltipPosition="above"> |
|||
<mat-icon>delete</mat-icon> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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 '../../../../../../../../../scss/constants'; |
|||
|
|||
.tb-form-table-row.tb-additional-map-data-source-row { |
|||
|
|||
.tb-source-field { |
|||
flex: 1 1 50%; |
|||
display: flex; |
|||
gap: 12px; |
|||
.tb-ds-type-field, .tb-label-field, .tb-device-field, .tb-entity-alias-field { |
|||
flex: 1; |
|||
} |
|||
} |
|||
|
|||
.tb-data-keys-field { |
|||
flex: 1 1 50%; |
|||
min-width: 0; |
|||
} |
|||
|
|||
.tb-remove-button { |
|||
width: 40px; |
|||
min-width: 40px; |
|||
} |
|||
|
|||
@media #{$mat-lt-lg} { |
|||
.tb-source-field { |
|||
flex-direction: column; |
|||
flex: 1 1 30%; |
|||
} |
|||
.tb-data-keys-field { |
|||
flex: 1 1 70%; |
|||
} |
|||
@media #{$mat-lt-md} { |
|||
.tb-source-field { |
|||
flex: 1 1 50%; |
|||
} |
|||
.tb-data-keys-field { |
|||
flex: 1 1 50%; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,207 @@ |
|||
///
|
|||
/// Copyright © 2016-2025 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 { |
|||
ChangeDetectorRef, |
|||
Component, |
|||
DestroyRef, |
|||
EventEmitter, |
|||
forwardRef, |
|||
Input, |
|||
OnInit, |
|||
Output, |
|||
ViewEncapsulation |
|||
} from '@angular/core'; |
|||
import { |
|||
ControlValueAccessor, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormBuilder, |
|||
UntypedFormGroup, |
|||
Validators |
|||
} from '@angular/forms'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
import { AdditionalMapDataSourceSettings } from '@shared/models/widget/maps/map.models'; |
|||
import { DataKey, DatasourceType, datasourceTypeTranslationMap, widgetType } from '@shared/models/widget.models'; |
|||
import { EntityType } from '@shared/models/entity-type.models'; |
|||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
|||
import { genNextLabelForDataKeys } from '@core/utils'; |
|||
import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-additional-map-data-source-row', |
|||
templateUrl: './additional-map-data-source-row.component.html', |
|||
styleUrls: ['./additional-map-data-source-row.component.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => AdditionalMapDataSourceRowComponent), |
|||
multi: true |
|||
} |
|||
], |
|||
encapsulation: ViewEncapsulation.None |
|||
}) |
|||
export class AdditionalMapDataSourceRowComponent implements ControlValueAccessor, OnInit { |
|||
|
|||
DatasourceType = DatasourceType; |
|||
DataKeyType = DataKeyType; |
|||
|
|||
EntityType = EntityType; |
|||
|
|||
widgetType = widgetType; |
|||
|
|||
datasourceTypes: Array<DatasourceType> = []; |
|||
datasourceTypesTranslations = datasourceTypeTranslationMap; |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
@Input() |
|||
context: MapSettingsContext; |
|||
|
|||
@Output() |
|||
dataSourceRemoved = new EventEmitter(); |
|||
|
|||
dataSourceFormGroup: UntypedFormGroup; |
|||
|
|||
generateAdditionalDataKey = this.generateDataKey.bind(this); |
|||
|
|||
modelValue: AdditionalMapDataSourceSettings; |
|||
|
|||
private propagateChange = (_val: any) => {}; |
|||
|
|||
constructor(private fb: UntypedFormBuilder, |
|||
private cd: ChangeDetectorRef, |
|||
private destroyRef: DestroyRef) { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
if (this.context.functionsOnly) { |
|||
this.datasourceTypes = [DatasourceType.function]; |
|||
} else { |
|||
this.datasourceTypes = [DatasourceType.function, DatasourceType.device, DatasourceType.entity]; |
|||
} |
|||
this.dataSourceFormGroup = this.fb.group({ |
|||
dsType: [null, [Validators.required]], |
|||
dsLabel: [null, []], |
|||
dsDeviceId: [null, [Validators.required]], |
|||
dsEntityAliasId: [null, [Validators.required]], |
|||
dataKeys: [null, [Validators.required]] |
|||
}); |
|||
this.dataSourceFormGroup.valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe( |
|||
() => this.updateModel() |
|||
); |
|||
this.dataSourceFormGroup.get('dsType').valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe( |
|||
(newDsType: DatasourceType) => this.onDsTypeChanged(newDsType) |
|||
); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(_fn: any): void { |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (isDisabled) { |
|||
this.dataSourceFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.dataSourceFormGroup.enable({emitEvent: false}); |
|||
this.updateValidators(); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: AdditionalMapDataSourceSettings): void { |
|||
this.modelValue = value; |
|||
this.dataSourceFormGroup.patchValue( |
|||
{ |
|||
dsType: value?.dsType, |
|||
dsLabel: value?.dsLabel, |
|||
dsDeviceId: value?.dsDeviceId, |
|||
dsEntityAliasId: value?.dsEntityAliasId, |
|||
dataKeys: value?.dataKeys |
|||
}, {emitEvent: false} |
|||
); |
|||
this.updateValidators(); |
|||
this.cd.markForCheck(); |
|||
} |
|||
|
|||
private generateDataKey(key: DataKey): DataKey { |
|||
const dataKey = this.context.callbacks.generateDataKey(key.name, key.type, null, false, null); |
|||
const dataKeys: DataKey[] = this.dataSourceFormGroup.get('dataKeys').value || []; |
|||
dataKey.label = genNextLabelForDataKeys(dataKey.label, dataKeys); |
|||
return dataKey; |
|||
} |
|||
|
|||
private onDsTypeChanged(newDsType: DatasourceType) { |
|||
let updateModel = false; |
|||
const dataKeys: DataKey[] = this.dataSourceFormGroup.get('dataKeys').value; |
|||
if (dataKeys?.length) { |
|||
for (const key of dataKeys) { |
|||
updateModel = this.updateDataKeyToNewDsType(key, newDsType) || updateModel; |
|||
} |
|||
if (updateModel) { |
|||
this.dataSourceFormGroup.get('dataKeys').patchValue(dataKeys, {emitEvent: false}); |
|||
} |
|||
} |
|||
this.updateValidators(); |
|||
if (updateModel) { |
|||
this.updateModel(); |
|||
} |
|||
} |
|||
|
|||
private updateDataKeyToNewDsType(dataKey: DataKey, newDsType: DatasourceType): boolean { |
|||
if (newDsType === DatasourceType.function) { |
|||
if (dataKey.type !== DataKeyType.function) { |
|||
dataKey.type = DataKeyType.function; |
|||
return true; |
|||
} |
|||
} else { |
|||
if (dataKey.type === DataKeyType.function) { |
|||
dataKey.type = DataKeyType.attribute; |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
private updateValidators() { |
|||
const dsType: DatasourceType = this.dataSourceFormGroup.get('dsType').value; |
|||
if (dsType === DatasourceType.function) { |
|||
this.dataSourceFormGroup.get('dsLabel').enable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsDeviceId').disable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsEntityAliasId').disable({emitEvent: false}); |
|||
} else if (dsType === DatasourceType.device) { |
|||
this.dataSourceFormGroup.get('dsLabel').disable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsDeviceId').enable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsEntityAliasId').disable({emitEvent: false}); |
|||
} else { |
|||
this.dataSourceFormGroup.get('dsLabel').disable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsDeviceId').disable({emitEvent: false}); |
|||
this.dataSourceFormGroup.get('dsEntityAliasId').enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
private updateModel() { |
|||
this.modelValue = {...this.modelValue, ...this.dataSourceFormGroup.value}; |
|||
this.propagateChange(this.modelValue); |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2025 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-form-panel no-padding no-border"> |
|||
<div class="tb-form-table tb-additional-map-data-sources"> |
|||
<div class="tb-form-table-header no-padding-right"> |
|||
<div class="tb-form-table-header-cell tb-source-header" translate>widgets.maps.data-layer.source</div> |
|||
<div class="tb-form-table-header-cell tb-data-keys-header" translate>widgets.maps.data-layer.data-keys</div> |
|||
<div class="tb-form-table-header-cell tb-actions-header"></div> |
|||
</div> |
|||
<div *ngIf="dataSourcesFormArray().controls.length; else noDataSources" class="tb-form-table-body"> |
|||
<div *ngFor="let dataSourceControl of dataSourcesFormArray().controls; trackBy: trackByDataSource; let $index = index;"> |
|||
<tb-additional-map-data-source-row class="flex-1" |
|||
[context]="context" |
|||
[formControl]="dataSourceControl" |
|||
(dataSourceRemoved)="removeDataSource($index)"> |
|||
</tb-additional-map-data-source-row> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
<button type="button" mat-stroked-button color="primary" (click)="addDataSource()"> |
|||
{{ 'widgets.maps.data-layer.add-datasource' | translate }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
<ng-template #noDataSources> |
|||
<span class="tb-prompt flex items-center justify-center">{{ 'widgets.maps.data-layer.no-datasources' | translate }}</span> |
|||
</ng-template> |
|||
@ -0,0 +1,53 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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 '../../../../../../../../../scss/constants'; |
|||
|
|||
.tb-additional-map-data-sources { |
|||
.tb-form-table-header-cell { |
|||
&.tb-source-header { |
|||
flex: 1 1 50%; |
|||
} |
|||
&.tb-data-keys-header { |
|||
flex: 1 1 50%; |
|||
} |
|||
&.tb-actions-header { |
|||
width: 40px; |
|||
min-width: 40px; |
|||
} |
|||
@media #{$mat-lt-lg} { |
|||
&.tb-source-header { |
|||
flex: 1 1 30%; |
|||
} |
|||
&.tb-data-keys-header { |
|||
flex: 1 1 70%; |
|||
} |
|||
@media #{$mat-lt-md} { |
|||
&.tb-source-header { |
|||
flex: 1 1 50%; |
|||
} |
|||
&.tb-data-keys-header { |
|||
flex: 1 1 50%; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.tb-form-table-body { |
|||
tb-additional-map-data-source-row { |
|||
overflow: hidden; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,147 @@ |
|||
///
|
|||
/// Copyright © 2016-2025 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, DestroyRef, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; |
|||
import { |
|||
AbstractControl, |
|||
ControlValueAccessor, |
|||
NG_VALIDATORS, |
|||
NG_VALUE_ACCESSOR, |
|||
UntypedFormArray, |
|||
UntypedFormBuilder, |
|||
UntypedFormControl, |
|||
UntypedFormGroup, |
|||
Validator |
|||
} from '@angular/forms'; |
|||
import { mergeDeep } from '@core/utils'; |
|||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|||
import { |
|||
AdditionalMapDataSourceSettings, |
|||
additionalMapDataSourceValid, |
|||
additionalMapDataSourceValidator, |
|||
defaultAdditionalMapDataSourceSettings |
|||
} from '@shared/models/widget/maps/map.models'; |
|||
import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-additional-map-data-sources', |
|||
templateUrl: './additional-map-data-sources.component.html', |
|||
styleUrls: ['./additional-map-data-sources.component.scss'], |
|||
providers: [ |
|||
{ |
|||
provide: NG_VALUE_ACCESSOR, |
|||
useExisting: forwardRef(() => AdditionalMapDataSourcesComponent), |
|||
multi: true |
|||
}, |
|||
{ |
|||
provide: NG_VALIDATORS, |
|||
useExisting: forwardRef(() => AdditionalMapDataSourcesComponent), |
|||
multi: true |
|||
} |
|||
], |
|||
encapsulation: ViewEncapsulation.None |
|||
}) |
|||
export class AdditionalMapDataSourcesComponent implements ControlValueAccessor, OnInit, Validator { |
|||
|
|||
@Input() |
|||
disabled: boolean; |
|||
|
|||
@Input() |
|||
context: MapSettingsContext; |
|||
|
|||
dataSourcesFormGroup: UntypedFormGroup; |
|||
|
|||
private propagateChange = (_val: any) => {}; |
|||
|
|||
constructor(private fb: UntypedFormBuilder, |
|||
private destroyRef: DestroyRef) { |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.dataSourcesFormGroup = this.fb.group({ |
|||
dataSources: [this.fb.array([]), []] |
|||
}); |
|||
this.dataSourcesFormGroup.valueChanges.pipe( |
|||
takeUntilDestroyed(this.destroyRef) |
|||
).subscribe( |
|||
() => { |
|||
let dataSources: AdditionalMapDataSourceSettings[] = this.dataSourcesFormGroup.get('dataSources').value; |
|||
if (dataSources) { |
|||
dataSources = dataSources.filter(dataSource => additionalMapDataSourceValid(dataSource)); |
|||
} |
|||
this.propagateChange(dataSources); |
|||
} |
|||
); |
|||
} |
|||
|
|||
registerOnChange(fn: any): void { |
|||
this.propagateChange = fn; |
|||
} |
|||
|
|||
registerOnTouched(fn: any): void { |
|||
} |
|||
|
|||
setDisabledState(isDisabled: boolean): void { |
|||
this.disabled = isDisabled; |
|||
if (isDisabled) { |
|||
this.dataSourcesFormGroup.disable({emitEvent: false}); |
|||
} else { |
|||
this.dataSourcesFormGroup.enable({emitEvent: false}); |
|||
} |
|||
} |
|||
|
|||
writeValue(value: AdditionalMapDataSourceSettings[] | undefined): void { |
|||
const dataSources: AdditionalMapDataSourceSettings[] = value || []; |
|||
this.dataSourcesFormGroup.setControl('dataSources', this.prepareDataSourcesFormArray(dataSources), {emitEvent: false}); |
|||
} |
|||
|
|||
public validate(c: UntypedFormControl) { |
|||
const valid = this.dataSourcesFormGroup.valid; |
|||
return valid ? null : { |
|||
dataSources: { |
|||
valid: false, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
dataSourcesFormArray(): UntypedFormArray { |
|||
return this.dataSourcesFormGroup.get('dataSources') as UntypedFormArray; |
|||
} |
|||
|
|||
trackByDataSource(index: number, dataSourceControl: AbstractControl): any { |
|||
return dataSourceControl; |
|||
} |
|||
|
|||
removeDataSource(index: number) { |
|||
(this.dataSourcesFormGroup.get('dataSources') as UntypedFormArray).removeAt(index); |
|||
} |
|||
|
|||
addDataSource() { |
|||
const dataSource = mergeDeep<AdditionalMapDataSourceSettings>({} as AdditionalMapDataSourceSettings, |
|||
defaultAdditionalMapDataSourceSettings(this.context.functionsOnly)); |
|||
const dataSourcesArray = this.dataSourcesFormGroup.get('dataSources') as UntypedFormArray; |
|||
const dataSourceControl = this.fb.control(dataSource, [additionalMapDataSourceValidator]); |
|||
dataSourcesArray.push(dataSourceControl); |
|||
} |
|||
|
|||
private prepareDataSourcesFormArray(dataSources: AdditionalMapDataSourceSettings[]): UntypedFormArray { |
|||
const dataSourcesControls: Array<AbstractControl> = []; |
|||
dataSources.forEach((dataSource) => { |
|||
dataSourcesControls.push(this.fb.control(dataSource, [additionalMapDataSourceValidator])); |
|||
}); |
|||
return this.fb.array(dataSourcesControls); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue