Refactoring validation mqtt topic filter; Add help hint
This commit is contained in:
parent
f3a5cb3162
commit
ddf8a3569e
@ -19,7 +19,6 @@
|
||||
<section formGroupName="configuration">
|
||||
<fieldset class="fields-group">
|
||||
<legend class="group-title" translate>device-profile.mqtt-device-topic-filters</legend>
|
||||
<h6 class="mat-body" innerHTML="{{ 'device-profile.support-level-wildcards' | translate }}"></h6>
|
||||
<div fxLayoutGap="8px" fxLayout="column">
|
||||
<div fxLayout="row" fxLayoutGap="8px" fxLayout.xs="column">
|
||||
<mat-form-field fxFlex>
|
||||
@ -30,8 +29,11 @@
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceTelemetryTopic').hasError('required')">
|
||||
{{ 'device-profile.telemetry-topic-filter-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceTelemetryTopic').hasError('pattern')">
|
||||
{{ 'device-profile.not-valid-pattern-topic-filter' | translate}}
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceTelemetryTopic').hasError('invalidSingleTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-single-character' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceTelemetryTopic').hasError('invalidMultiTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-multi-character' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
@ -42,8 +44,11 @@
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcRequestTopic').hasError('required')">
|
||||
{{ 'device-profile.rpc-request-topic-filter-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcRequestTopic').hasError('pattern')">
|
||||
{{ 'device-profile.not-valid-pattern-topic-filter' | translate}}
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcRequestTopic').hasError('invalidSingleTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-single-character' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcRequestTopic').hasError('invalidMultiTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-multi-character' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
@ -56,8 +61,11 @@
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceAttributesTopic').hasError('required')">
|
||||
{{ 'device-profile.attributes-topic-filter-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceAttributesTopic').hasError('pattern')">
|
||||
{{ 'device-profile.not-valid-pattern-topic-filter' | translate}}
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceAttributesTopic').hasError('invalidSingleTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-single-character' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceAttributesTopic').hasError('invalidMultiTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-multi-character' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
@ -68,11 +76,17 @@
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcResponseTopic').hasError('required')">
|
||||
{{ 'device-profile.rpc-response-topic-filter-required' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcResponseTopic').hasError('pattern')">
|
||||
{{ 'device-profile.not-valid-pattern-topic-filter' | translate}}
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcResponseTopic').hasError('invalidSingleTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-single-character' | translate}}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="mqttDeviceProfileTransportConfigurationFormGroup.get('configuration.deviceRpcResponseTopic').hasError('invalidMultiTopicCharacter')">
|
||||
{{ 'device-profile.not-valid-multi-character' | translate}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="tb-hint" innerHTML="{{ 'device-profile.support-level-wildcards' | translate }}"></div>
|
||||
<div class="tb-hint" innerHTML="{{ 'device-profile.single-level-wildcards-hint' | translate }}"></div>
|
||||
<div class="tb-hint" innerHTML="{{ 'device-profile.multi-level-wildcards-hint' | translate }}"></div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</section>
|
||||
|
||||
@ -23,5 +23,9 @@
|
||||
legend {
|
||||
color: rgba(0, 0, 0, .7);
|
||||
}
|
||||
|
||||
.tb-hint{
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,15 +15,24 @@
|
||||
///
|
||||
|
||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
|
||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALUE_ACCESSOR,
|
||||
ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@app/core/core.state';
|
||||
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||
import {
|
||||
DeviceProfileTransportConfiguration,
|
||||
DeviceTransportType, MqttDeviceProfileTransportConfiguration
|
||||
DeviceTransportType,
|
||||
MqttDeviceProfileTransportConfiguration
|
||||
} from '@shared/models/device.models';
|
||||
import { isDefinedAndNotNull } from '../../../../../core/utils';
|
||||
import { isDefinedAndNotNull } from '@core/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-mqtt-device-profile-transport-configuration',
|
||||
@ -41,11 +50,10 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
|
||||
|
||||
private requiredValue: boolean;
|
||||
|
||||
private MQTTTopicPattern = new RegExp('^((?![#+]).)*$|^(.*[^#]\/|^)#$|^(.*\/|^)\+(\/.*|$)$');
|
||||
|
||||
get required(): boolean {
|
||||
return this.requiredValue;
|
||||
}
|
||||
|
||||
@Input()
|
||||
set required(value: boolean) {
|
||||
this.requiredValue = coerceBooleanProperty(value);
|
||||
@ -70,10 +78,10 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
|
||||
ngOnInit() {
|
||||
this.mqttDeviceProfileTransportConfigurationFormGroup = this.fb.group({
|
||||
configuration: this.fb.group({
|
||||
deviceAttributesTopic: [null, [Validators.required, Validators.pattern(this.MQTTTopicPattern)]],
|
||||
deviceTelemetryTopic: [null, [Validators.required, Validators.pattern(this.MQTTTopicPattern)]],
|
||||
deviceRpcRequestTopic: [null, [Validators.required, Validators.pattern(this.MQTTTopicPattern)]],
|
||||
deviceRpcResponseTopic: [null, [Validators.required, Validators.pattern(this.MQTTTopicPattern)]]
|
||||
deviceAttributesTopic: [null, [Validators.required, this.validationMQTTTopic()]],
|
||||
deviceTelemetryTopic: [null, [Validators.required, this.validationMQTTTopic()]],
|
||||
deviceRpcRequestTopic: [null, [Validators.required, this.validationMQTTTopic()]],
|
||||
deviceRpcResponseTopic: [null, [Validators.required, this.validationMQTTTopic()]]
|
||||
})
|
||||
});
|
||||
this.mqttDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
|
||||
@ -104,4 +112,34 @@ export class MqttDeviceProfileTransportConfigurationComponent implements Control
|
||||
}
|
||||
this.propagateChange(configuration);
|
||||
}
|
||||
|
||||
private validationMQTTTopic(): ValidatorFn {
|
||||
return (c: FormControl) => {
|
||||
const newTopic = c.value;
|
||||
const wildcardSymbols = /[#+]/g;
|
||||
let findSymbol = wildcardSymbols.exec(newTopic);
|
||||
while (findSymbol) {
|
||||
const index = findSymbol.index;
|
||||
const currentSymbol = findSymbol[0];
|
||||
const prevSymbol = index > 0 ? newTopic[index - 1] : null;
|
||||
const nextSymbol = index < (newTopic.length - 1) ? newTopic[index + 1] : null;
|
||||
if (currentSymbol === '#' && (index !== (newTopic.length - 1) || (prevSymbol !== null && prevSymbol !== '/'))) {
|
||||
return {
|
||||
invalidMultiTopicCharacter: {
|
||||
valid: false
|
||||
}
|
||||
};
|
||||
}
|
||||
if (currentSymbol === '+' && ((prevSymbol !== null && prevSymbol !== '/') || (nextSymbol !== null && nextSymbol !== '/'))) {
|
||||
return {
|
||||
invalidSingleTopicCharacter: {
|
||||
valid: false
|
||||
}
|
||||
};
|
||||
}
|
||||
findSymbol = wildcardSymbols.exec(newTopic);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -792,7 +792,7 @@
|
||||
"no-device-profiles-found": "No device profiles found.",
|
||||
"create-new-device-profile": "Create a new one!",
|
||||
"mqtt-device-topic-filters": "MQTT device topic filters",
|
||||
"support-level-wildcards": "Support single <code>(+)</code> and multi <code>(#)</code> level wildcards",
|
||||
"support-level-wildcards": "Single <code>[+]</code> and multi-level <code>[#]</code> wildcards supported.",
|
||||
"telemetry-topic-filter": "Telemetry topic filter",
|
||||
"telemetry-topic-filter-required": "Telemetry topic filter is required.",
|
||||
"rpc-request-topic-filter": "RPC request topic filter",
|
||||
@ -801,7 +801,10 @@
|
||||
"attributes-topic-filter-required": "Attributes topic filter is required.",
|
||||
"rpc-response-topic-filter": "RPC response topic filter",
|
||||
"rpc-response-topic-filter-required": "RPC response topic filter is required.",
|
||||
"not-valid-pattern-topic-filter": "Not valid pattern topic filter"
|
||||
"not-valid-single-character": "Invalid use of a single-level wildcard character",
|
||||
"not-valid-multi-character": "Invalid use of a multi-level wildcard character",
|
||||
"single-level-wildcards-hint": "<code>[+]</code> is suitable for any topic level. Ex.: <b>v1/devices/+/telemetry</b> or <b>+/devices/+/attributes</b>.",
|
||||
"multi-level-wildcards-hint": "<code>[#]</code> can replace the topic filter itself and must be the last symbol of the topic. Ex.: <b>#</b> or <b>v1/devices/me/#</b>."
|
||||
},
|
||||
"dialog": {
|
||||
"close": "Close dialog"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user