UI: Device connectivity ui implementation
This commit is contained in:
parent
7fc04e4b24
commit
4cdd5ce6d4
@ -15,7 +15,6 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div>
|
||||
<mat-card appearance="outlined" class="settings-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
@ -29,7 +28,7 @@
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<mat-card-content>
|
||||
<form [formGroup]="generalSettings" (ngSubmit)="save()">
|
||||
<fieldset [disabled]="isLoading$ | async">
|
||||
<fieldset [disabled]="isLoading$ | async" style="margin-bottom: 10px">
|
||||
<mat-form-field class="mat-block">
|
||||
<mat-label translate>admin.base-url</mat-label>
|
||||
<input matInput formControlName="baseUrl" required/>
|
||||
@ -37,17 +36,185 @@
|
||||
{{ 'admin.base-url-required' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<tb-checkbox formControlName="prohibitDifferentUrl" style="display: block;">
|
||||
<div class="tb-form-row" tb-hint-tooltip-icon="{{ 'admin.prohibit-different-url-hint' | translate }}">
|
||||
<mat-slide-toggle class="mat-slide" formControlName="prohibitDifferentUrl">
|
||||
{{ 'admin.prohibit-different-url' | translate }}
|
||||
</tb-checkbox>
|
||||
<div class="tb-hint" style="padding-left: 10px;" translate>admin.prohibit-different-url-hint</div>
|
||||
<div fxLayout="row" fxLayoutAlign="end center" style="width: 100%;" class="layout-wrap">
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px" class="layout-wrap">
|
||||
<button mat-button color="primary"
|
||||
[disabled]="generalSettings.pristine"
|
||||
(click)="discardGeneralSettings()"
|
||||
type="button">{{'action.undo' | translate}}
|
||||
</button>
|
||||
<button mat-button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || generalSettings.invalid || !generalSettings.dirty"
|
||||
type="submit">{{'action.save' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card appearance="outlined" class="settings-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<span class="mat-headline-5" translate>admin.device-connectivity.device-connectivity</span>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
||||
</mat-progress-bar>
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<mat-card-content style="padding-top: 16px">
|
||||
<tb-toggle-select class="toggle-group" appearance="fill" selectMediaBreakpoint="xs" [(ngModel)]="protocol">
|
||||
<tb-toggle-option value="http">{{ "admin.device-connectivity.http-https" | translate }}</tb-toggle-option>
|
||||
<tb-toggle-option value="mqtt">{{ 'admin.device-connectivity.mqtt-mqtts' | translate }}</tb-toggle-option>
|
||||
<tb-toggle-option value="coap">{{ 'admin.device-connectivity.coap-coaps' | translate }}</tb-toggle-option>
|
||||
</tb-toggle-select>
|
||||
<mat-hint class="tb-form-hint tb-primary-fill hint">{{ 'admin.device-connectivity.hint' | translate }}</mat-hint>
|
||||
<form [formGroup]="deviceConnectivitySettingsForm" (ngSubmit)="saveDeviceConnectivitySettings()">
|
||||
<fieldset *ngIf="protocol === 'http'" [disabled]="isLoading$ | async" formGroupName="http" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.http' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('http.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('http.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('http.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset *ngIf="protocol === 'http'" [disabled]="isLoading$ | async" formGroupName="https" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.https' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('https.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('https.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('https.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset *ngIf="protocol === 'mqtt'" [disabled]="isLoading$ | async" formGroupName="mqtt" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.mqtt' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('mqtt.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('mqtt.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('mqtt.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset *ngIf="protocol === 'mqtt'" [disabled]="isLoading$ | async" formGroupName="mqtts" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.mqtts' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('mqtts.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('mqtts.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('mqtts.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset *ngIf="protocol === 'coap'" [disabled]="isLoading$ | async" formGroupName="coap" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.coap' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('coap.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('coap.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('coap.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset *ngIf="protocol === 'coap'" [disabled]="isLoading$ | async" formGroupName="coaps" class="fields-group">
|
||||
<mat-slide-toggle class="slide" formControlName="enabled">
|
||||
{{ 'admin.device-connectivity.coaps' | translate }}
|
||||
</mat-slide-toggle>
|
||||
<div class="fields-row">
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.host</mat-label>
|
||||
<input matInput formControlName="host"/>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="mat-block" fxFlex>
|
||||
<mat-label translate>admin.device-connectivity.port</mat-label>
|
||||
<input matInput type="number" min="0" max="65535" formControlName="port"/>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('coaps.port').hasError('pattern')">
|
||||
{{ 'admin.device-connectivity.port-pattern' | translate }}
|
||||
</mat-error>
|
||||
<mat-error *ngIf="deviceConnectivitySettingsForm.get('coaps.port').hasError('min') ||
|
||||
deviceConnectivitySettingsForm.get('coaps.port').hasError('max')">
|
||||
{{ 'admin.device-connectivity.port-range' | translate }}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px" class="layout-wrap">
|
||||
<button mat-button color="primary"
|
||||
[disabled]="deviceConnectivitySettingsForm.pristine"
|
||||
(click)="discardDeviceConnectivitySettings()"
|
||||
type="button">{{'action.undo' | translate}}
|
||||
</button>
|
||||
<button mat-raised-button color="primary"
|
||||
[disabled]="(isLoading$ | async) || deviceConnectivitySettingsForm.invalid || !deviceConnectivitySettingsForm.dirty"
|
||||
type="submit">{{'action.save' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
@ -14,6 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
:host {
|
||||
.settings-card {
|
||||
.toggle-group {
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.hint {
|
||||
display: block;
|
||||
}
|
||||
.fields-group {
|
||||
.slide {
|
||||
padding: 16px 0;
|
||||
}
|
||||
.fields-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
|
||||
@ -14,13 +14,13 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { PageComponent } from '@shared/components/page.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { AdminSettings, GeneralSettings } from '@shared/models/settings.models';
|
||||
import { AdminSettings, DeviceConnectivitySettings, GeneralSettings } from '@shared/models/settings.models';
|
||||
import { AdminService } from '@core/http/admin.service';
|
||||
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
|
||||
|
||||
@ -29,26 +29,27 @@ import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
|
||||
templateUrl: './general-settings.component.html',
|
||||
styleUrls: ['./general-settings.component.scss', './settings-card.scss']
|
||||
})
|
||||
export class GeneralSettingsComponent extends PageComponent implements OnInit, HasConfirmForm {
|
||||
export class GeneralSettingsComponent extends PageComponent implements HasConfirmForm {
|
||||
|
||||
generalSettings: UntypedFormGroup;
|
||||
adminSettings: AdminSettings<GeneralSettings>;
|
||||
private adminSettings: AdminSettings<GeneralSettings>;
|
||||
|
||||
deviceConnectivitySettingsForm: UntypedFormGroup;
|
||||
private deviceConnectivitySettings: AdminSettings<DeviceConnectivitySettings>;
|
||||
|
||||
protocol = 'http';
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
private router: Router,
|
||||
private adminService: AdminService,
|
||||
public fb: UntypedFormBuilder) {
|
||||
super(store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildGeneralServerSettingsForm();
|
||||
this.adminService.getAdminSettings<GeneralSettings>('general').subscribe(
|
||||
(adminSettings) => {
|
||||
this.adminSettings = adminSettings;
|
||||
this.generalSettings.reset(this.adminSettings.jsonValue);
|
||||
}
|
||||
);
|
||||
this.adminService.getAdminSettings<GeneralSettings>('general')
|
||||
.subscribe(adminSettings => this.processGeneralSettings(adminSettings));
|
||||
this.buildDeviceConnectivitySettingsForm();
|
||||
this.adminService.getAdminSettings<DeviceConnectivitySettings>('connectivity')
|
||||
.subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings));
|
||||
}
|
||||
|
||||
buildGeneralServerSettingsForm() {
|
||||
@ -58,18 +59,73 @@ export class GeneralSettingsComponent extends PageComponent implements OnInit, H
|
||||
});
|
||||
}
|
||||
|
||||
buildDeviceConnectivitySettingsForm() {
|
||||
this.deviceConnectivitySettingsForm = this.fb.group({
|
||||
http: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
https: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
mqtt: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
mqtts: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
coap: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
coaps: this.fb.group({
|
||||
enabled: [false, []],
|
||||
host: ['', []],
|
||||
port: [null, [Validators.min(1), Validators.max(65535), Validators.pattern('[0-9]*')]]
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
save(): void {
|
||||
this.adminSettings.jsonValue = {...this.adminSettings.jsonValue, ...this.generalSettings.value};
|
||||
this.adminService.saveAdminSettings(this.adminSettings).subscribe(
|
||||
(adminSettings) => {
|
||||
this.adminSettings = adminSettings;
|
||||
this.adminService.saveAdminSettings(this.adminSettings)
|
||||
.subscribe(adminSettings => this.processGeneralSettings(adminSettings));
|
||||
}
|
||||
|
||||
saveDeviceConnectivitySettings(): void {
|
||||
this.deviceConnectivitySettings.jsonValue = {...this.deviceConnectivitySettings.jsonValue, ...this.deviceConnectivitySettingsForm.value};
|
||||
this.adminService.saveAdminSettings<DeviceConnectivitySettings>(this.deviceConnectivitySettings)
|
||||
.subscribe(deviceConnectivitySettings => this.processDeviceConnectivitySettings(deviceConnectivitySettings));
|
||||
}
|
||||
|
||||
discardGeneralSettings(): void {
|
||||
this.generalSettings.reset(this.adminSettings.jsonValue);
|
||||
}
|
||||
);
|
||||
|
||||
discardDeviceConnectivitySettings(): void {
|
||||
this.deviceConnectivitySettingsForm.reset(this.deviceConnectivitySettings.jsonValue);
|
||||
}
|
||||
|
||||
private processGeneralSettings(generalSettings: AdminSettings<GeneralSettings>): void {
|
||||
this.adminSettings = generalSettings;
|
||||
this.generalSettings.reset(this.adminSettings.jsonValue);
|
||||
}
|
||||
|
||||
private processDeviceConnectivitySettings(deviceConnectivitySettings: AdminSettings<DeviceConnectivitySettings>): void {
|
||||
this.deviceConnectivitySettings = deviceConnectivitySettings;
|
||||
this.deviceConnectivitySettingsForm.reset(this.deviceConnectivitySettings.jsonValue);
|
||||
}
|
||||
|
||||
confirmForm(): UntypedFormGroup {
|
||||
return this.generalSettings;
|
||||
return this.generalSettings.dirty ? this.generalSettings : this.deviceConnectivitySettingsForm;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -87,6 +87,39 @@ export interface GeneralSettings {
|
||||
baseUrl: string;
|
||||
}
|
||||
|
||||
export interface DeviceConnectivitySettings {
|
||||
http: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
},
|
||||
https: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
},
|
||||
mqtt: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
},
|
||||
mqtts: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
},
|
||||
coap: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
},
|
||||
coaps: {
|
||||
enabled: boolean;
|
||||
host: string;
|
||||
port: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserPasswordPolicy {
|
||||
minimumLength: number;
|
||||
minimumUppercaseLetters: number;
|
||||
|
||||
@ -105,6 +105,23 @@
|
||||
"base-url-required": "Base URL is required.",
|
||||
"prohibit-different-url": "Prohibit to use hostname from the client request headers",
|
||||
"prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled",
|
||||
"device-connectivity": {
|
||||
"device-connectivity": "Device connectivity",
|
||||
"http-https": "HTTP/HTTPS",
|
||||
"mqtt-mqtts": "MQTT/MQTTS",
|
||||
"coap-coaps": "COAP/COAPS",
|
||||
"http": "HTPP",
|
||||
"https": "HTTPS",
|
||||
"mqtt": "MQTT",
|
||||
"mqtts": "MQTTS",
|
||||
"coap": "COAP",
|
||||
"coaps": "COAPS",
|
||||
"hint": "If host or port fields are empty will be used default protocol value.",
|
||||
"host": "Host",
|
||||
"port": "Port",
|
||||
"port-pattern": "Port must be a positive integer.",
|
||||
"port-range": "Port should be in a range from 1 to 65535."
|
||||
},
|
||||
"mail-from": "Mail From",
|
||||
"mail-from-required": "Mail From is required.",
|
||||
"smtp-protocol": "SMTP protocol",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user