Browse Source

Merge branch 'feature/lts-4.3-iot-hub' of github.com:thingsboard/thingsboard into feature/lts-4.3-iot-hub

pull/15540/head
Igor Kulikov 5 days ago
parent
commit
d45ff1b239
  1. 81
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-install-dialog.component.html
  2. 95
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-install-dialog.component.ts
  3. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json

81
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-install-dialog.component.html

@ -19,26 +19,55 @@
@switch (state) {
@case ('confirm') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.install-confirm-title' | translate:{ name: item.name } }}</h2>
@if (item.type === ItemType.RULE_CHAIN) {
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.rule-chain-install-desc' | translate }}</p>
} @else {
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.install-desc' | translate }}</p>
}
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.install-desc' | translate }}</p>
}
@case ('select-entity') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.install-confirm-title' | translate:{ name: item.name } }}</h2>
@if (activeSelectEntityConfig?.promptKey) {
<p class="tb-iot-hub-install-desc"
[innerHTML]="activeSelectEntityConfig.promptKey | translate:{ name: item.name }"></p>
@if (item.type === ItemType.RULE_CHAIN) {
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.rule-chain-install-subtitle' | translate }}</p>
<form [formGroup]="ruleChainInstallForm">
<div class="tb-form-panel stroked">
<mat-slide-toggle class="mat-slide flex" formControlName="setAsDefault">
<div tb-hint-tooltip-icon="{{ 'iot-hub.rule-chain-set-as-profile-default-tooltip' | translate }}">
{{ 'iot-hub.rule-chain-set-as-profile-default-toggle' | translate }}
</div>
</mat-slide-toggle>
@if (ruleChainInstallForm.controls.setAsDefault.value) {
<div class="flex flex-row gap-4 xs:flex-col xs:gap-0">
<tb-entity-type-select
class="flex-1"
appearance="outline"
[showLabel]="true"
[required]="true"
[allowedEntityTypes]="[EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE]"
[filterAllowedEntityTypes]="false"
formControlName="entityType">
</tb-entity-type-select>
<tb-entity-autocomplete
class="flex-1"
appearance="outline"
[required]="true"
[entityType]="ruleChainInstallForm.controls.entityType.value"
formControlName="entityId">
</tb-entity-autocomplete>
</div>
}
</div>
</form>
} @else {
@if (activeSelectEntityConfig?.promptKey) {
<p class="tb-iot-hub-install-desc"
[innerHTML]="activeSelectEntityConfig.promptKey | translate:{ name: item.name }"></p>
}
<tb-entity-select
[(ngModel)]="selectedEntityId"
[allowedEntityTypes]="activeSelectEntityConfig.allowed"
[defaultEntityType]="activeSelectEntityConfig.defaultType"
[filterAllowedEntityTypes]="false"
appearance="outline"
[required]="activeSelectEntityConfig.required">
</tb-entity-select>
}
<tb-entity-select
[(ngModel)]="selectedEntityId"
[allowedEntityTypes]="activeSelectEntityConfig.allowed"
[defaultEntityType]="activeSelectEntityConfig.defaultType"
[filterAllowedEntityTypes]="false"
appearance="outline"
[required]="activeSelectEntityConfig.required">
</tb-entity-select>
}
@case ('confirm-overwrite') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.rule-chain-overwrite-title' | translate }}</h2>
@ -59,7 +88,7 @@
@case ('error') {
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.install-error-title' | translate }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.install-error-message' | translate:{ name: item.name } }}</p>
@if (item?.type === ItemType.SOLUTION_TEMPLATE) {
@if (item.type === ItemType.SOLUTION_TEMPLATE) {
<tb-iot-hub-markdown class="tb-iot-hub-error-details-markdown" [data]="errorMessage"></tb-iot-hub-markdown>
} @else {
<div class="tb-iot-hub-error-details">
@ -73,28 +102,20 @@
@switch (state) {
@case ('confirm') {
<button mat-button (click)="cancel()">{{ 'action.cancel' | translate }}</button>
@if (item.type === ItemType.RULE_CHAIN) {
<button mat-stroked-button (click)="install()">{{ 'iot-hub.install' | translate }}</button>
<button mat-flat-button color="primary" (click)="installAsEntityProfileDefault()">
{{ 'iot-hub.rule-chain-install-as-default' | translate }}
</button>
} @else {
<button mat-flat-button color="primary" (click)="install()">{{ 'iot-hub.install' | translate }}</button>
}
<button mat-flat-button color="primary" (click)="install()">{{ 'iot-hub.install' | translate }}</button>
}
@case ('select-entity') {
<button mat-button (click)="cancel()">{{ 'action.cancel' | translate }}</button>
@if (item.type === ItemType.RULE_CHAIN) {
<button mat-button (click)="selectEntityBack()">{{ 'action.back' | translate }}</button>
<button mat-flat-button color="primary"
[disabled]="!selectedEntityId"
(click)="onSelectEntityInstall()">
[disabled]="ruleChainInstallForm.invalid"
(click)="onRuleChainInstall()">
{{ 'iot-hub.install' | translate }}
</button>
} @else {
<button mat-flat-button color="primary"
[disabled]="activeSelectEntityConfig?.required && !selectedEntityId"
(click)="onSelectEntityInstall()">
[disabled]="activeSelectEntityConfig.required && !selectedEntityId"
(click)="onEntitySelectInstall()">
{{ 'iot-hub.install' | translate }}
</button>
}

95
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-install-dialog.component.ts

@ -14,9 +14,11 @@
/// limitations under the License.
///
import { Component, Inject } from '@angular/core';
import { Component, DestroyRef, Inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { DialogComponent } from '@shared/components/dialog.component';
@ -70,15 +72,21 @@ export type InstallState =
export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInstallDialogComponent> {
ItemType = ItemType;
EntityType = EntityType;
item: MpItemVersionView;
typeTranslations = itemTypeTranslations;
state: InstallState = 'confirm';
state!: InstallState;
errorMessage = '';
entityDetailsUrl: string | null = null;
selectedEntityId: EntityId | null = null;
pendingOverwrite: PendingOverwrite | null = null;
ruleChainInstallForm!: FormGroup<{
setAsDefault: FormControl<boolean>;
entityType: FormControl<EntityType>;
entityId: FormControl<string | null>;
}>;
private readonly selectEntityConfig: Partial<Record<ItemType, SelectEntityConfig>> = {
[ItemType.CALCULATED_FIELD]: {
@ -92,13 +100,7 @@ export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInst
defaultType: EntityType.DEVICE_PROFILE,
required: true,
promptKey: 'iot-hub.select-entity-for-alarm-rule',
},
[ItemType.RULE_CHAIN]: {
allowed: [EntityType.DEVICE_PROFILE, EntityType.ASSET_PROFILE],
defaultType: EntityType.DEVICE_PROFILE,
required: true,
promptKey: 'iot-hub.select-profile-for-rule-chain',
},
}
};
get activeSelectEntityConfig(): SelectEntityConfig | null {
@ -115,10 +117,47 @@ export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInst
private iotHubApiService: IotHubApiService,
private deviceProfileService: DeviceProfileService,
private assetProfileService: AssetProfileService,
private ruleChainService: RuleChainService
private ruleChainService: RuleChainService,
private fb: FormBuilder,
private destroyRef: DestroyRef
) {
super(store, router, dialogRef);
this.item = data.item;
this.state = this.computeInitialState();
if (this.item.type === ItemType.RULE_CHAIN) {
this.initRuleChainForm();
}
}
private computeInitialState(): InstallState {
return this.activeSelectEntityConfig || this.item.type === ItemType.RULE_CHAIN
? 'select-entity'
: 'confirm';
}
private initRuleChainForm(): void {
this.ruleChainInstallForm = this.fb.group({
setAsDefault: this.fb.nonNullable.control<boolean>(false),
entityType: this.fb.nonNullable.control<EntityType>(EntityType.DEVICE_PROFILE),
entityId: this.fb.control<string | null>(null)
});
this.ruleChainInstallForm.controls.setAsDefault.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(setAsDefault => {
const entityIdCtrl = this.ruleChainInstallForm.controls.entityId;
if (setAsDefault) {
entityIdCtrl.setValidators(Validators.required);
} else {
entityIdCtrl.clearValidators();
entityIdCtrl.setValue(null);
}
entityIdCtrl.updateValueAndValidity();
});
this.ruleChainInstallForm.controls.entityType.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.ruleChainInstallForm.controls.entityId.setValue(null);
});
}
getTypeLabel(): string {
@ -126,39 +165,33 @@ export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInst
return key ? this.translate.instant(key) : '';
}
install(): void {
if (this.item.type === ItemType.CALCULATED_FIELD || this.item.type === ItemType.ALARM_RULE) {
this.state = 'select-entity';
onEntitySelectInstall(): void {
if (!this.selectedEntityId) {
return;
}
this.doInstall();
this.install();
}
installAsEntityProfileDefault(): void {
this.state = 'select-entity';
}
selectEntityBack(): void {
this.selectedEntityId = null;
this.state = 'confirm';
}
onSelectEntityInstall(): void {
if (!this.selectedEntityId) {
onRuleChainInstall(): void {
const { setAsDefault, entityType, entityId } = this.ruleChainInstallForm.getRawValue();
if (!setAsDefault) {
this.selectedEntityId = null;
this.install();
return;
}
if (this.item.type !== ItemType.RULE_CHAIN) {
this.doInstall();
if (!entityId) {
return;
}
this.resolveOverwrite(this.selectedEntityId).subscribe({
const profileEntityId: EntityId = { entityType, id: entityId };
this.selectedEntityId = profileEntityId;
this.resolveOverwrite(profileEntityId).subscribe({
next: (pending) => {
if (pending) {
this.pendingOverwrite = pending;
this.state = 'confirm-overwrite';
} else {
this.pendingOverwrite = null;
this.doInstall();
this.install();
}
},
error: (err) => {
@ -170,7 +203,7 @@ export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInst
}
confirmOverwriteReplace(): void {
this.doInstall();
this.install();
}
confirmOverwriteCancel(): void {
@ -204,7 +237,7 @@ export class TbIotHubInstallDialogComponent extends DialogComponent<TbIotHubInst
);
}
doInstall(): void {
install(): void {
this.state = 'installing';
const versionId = this.item.id as string;
const data = this.selectedEntityId ? { entityId: this.selectedEntityId } : undefined;

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -4307,9 +4307,9 @@
"remove-anyway": "Remove anyway",
"select-entity-for-cf": "Select entity for calculated field '{{name}}'",
"select-entity-for-alarm-rule": "Select entity for alarm rule '{{name}}'",
"rule-chain-install-desc": "Installing this will automatically create the rule chain within your tenant. Use 'Set for profile' to also set it as default for Device or Asset profile.",
"rule-chain-install-as-default": "Set for profile",
"select-profile-for-rule-chain": "Select profile for rule chain '{{name}}'",
"rule-chain-install-subtitle": "Installing automatically creates the rule chain within your tenant. Optionally set it as a profile's default so entities of that profile route through it.",
"rule-chain-set-as-profile-default-toggle": "Set as profile default rule chain",
"rule-chain-set-as-profile-default-tooltip": "If enabled, all entities of the selected profile will route messages through this rule chain.",
"rule-chain-overwrite-title": "Replace existing default rule chain?",
"rule-chain-overwrite-body": "Profile <b>{{profile}}</b> currently uses <b>{{existing}}</b> as its default rule chain. Installing will replace it with this rule chain.",
"rule-chain-overwrite-replace": "Replace",

Loading…
Cancel
Save