diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts
index 46c84087ee..eb640a3af8 100644
--- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts
@@ -77,8 +77,8 @@ import {
} from '@shared/models/rule-node.models';
import { FcRuleNodeModel, FcRuleNodeTypeModel, RuleChainMenuContextInfo } from './rulechain-page.models';
import { RuleChainService } from '@core/http/rule-chain.service';
-import { NEVER, Observable, of, ReplaySubject, skip, startWith, Subject } from 'rxjs';
-import { debounceTime, distinctUntilChanged, mergeMap, takeUntil, tap } from 'rxjs/operators';
+import { NEVER, Observable, of, ReplaySubject, skip, startWith, Subject, throwError } from 'rxjs';
+import { catchError, debounceTime, distinctUntilChanged, mergeMap, takeUntil, tap } from 'rxjs/operators';
import { ISearchableComponent } from '../../models/searchable-component.models';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import { RuleNodeDetailsComponent } from '@home/pages/rulechain/rule-node-details.component';
@@ -93,6 +93,7 @@ import { TbPopoverService } from '@shared/components/popover.service';
import { VersionControlComponent } from '@home/components/vc/version-control.component';
import { ComponentClusteringMode } from '@shared/models/component-descriptor.models';
import { MatDrawer } from '@angular/material/sidenav';
+import { HttpStatusCode } from '@angular/common/http';
import Timeout = NodeJS.Timeout;
@Component({
@@ -1282,7 +1283,9 @@ export class RuleChainPageComponent extends PageComponent
onDebugEventSelected(debugEventBody: DebugRuleNodeEventBody) {
const ruleNodeConfigComponent = this.ruleNodeComponent.ruleNodeConfigComponent;
const ruleNodeConfigDefinedComponent = ruleNodeConfigComponent.definedConfigComponent;
- if (ruleNodeConfigComponent.useDefinedDirective() && ruleNodeConfigDefinedComponent.hasScript && ruleNodeConfigDefinedComponent.testScript) {
+ if (ruleNodeConfigComponent.useDefinedDirective()
+ && ruleNodeConfigDefinedComponent.hasScript
+ && ruleNodeConfigDefinedComponent.testScript) {
ruleNodeConfigDefinedComponent.testScript(debugEventBody);
}
}
@@ -1456,7 +1459,8 @@ export class RuleChainPageComponent extends PageComponent
const ruleChainMetaData: RuleChainMetaData = {
ruleChainId: this.ruleChain.id,
nodes: [],
- connections: []
+ connections: [],
+ version: ruleChain.version
};
const nodes: FcRuleNode[] = [];
this.ruleChainModel.nodes.forEach((node) => {
@@ -1465,7 +1469,9 @@ export class RuleChainPageComponent extends PageComponent
id: node.ruleNodeId,
type: node.component.clazz,
name: node.name,
- configurationVersion: isDefinedAndNotNull(node.configurationVersion) ? node.configurationVersion : node.component.configurationVersion,
+ configurationVersion: isDefinedAndNotNull(node.configurationVersion)
+ ? node.configurationVersion
+ : node.component.configurationVersion,
configuration: node.configuration,
additionalInfo: node.additionalInfo ? node.additionalInfo : {},
debugMode: node.debugMode,
@@ -1500,20 +1506,30 @@ export class RuleChainPageComponent extends PageComponent
});
}
});
- this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData).subscribe((savedRuleChainMetaData) => {
- this.ruleChainMetaData = savedRuleChainMetaData;
- if (this.isImport) {
- this.isDirtyValue = false;
- this.isImport = false;
- if (this.ruleChainType !== RuleChainType.EDGE) {
- this.router.navigateByUrl(`ruleChains/${this.ruleChain.id.id}`);
+ this.ruleChainService.saveRuleChainMetadata(ruleChainMetaData)
+ .pipe(
+ catchError(err => {
+ if (err.status === HttpStatusCode.Conflict) {
+ return this.ruleChainService.getRuleChainMetadata(ruleChainMetaData.ruleChainId.id);
+ }
+ return throwError(() => err);
+ })
+ )
+ .subscribe((savedRuleChainMetaData) => {
+ this.ruleChain.version = savedRuleChainMetaData.version;
+ this.ruleChainMetaData = savedRuleChainMetaData;
+ if (this.isImport) {
+ this.isDirtyValue = false;
+ this.isImport = false;
+ if (this.ruleChainType !== RuleChainType.EDGE) {
+ this.router.navigateByUrl(`ruleChains/${this.ruleChain.id.id}`);
+ } else {
+ this.router.navigateByUrl(`edgeManagement/ruleChains/${this.ruleChain.id.id}`);
+ }
} else {
- this.router.navigateByUrl(`edgeManagement/ruleChains/${this.ruleChain.id.id}`);
+ this.createRuleChainModel();
}
- } else {
- this.createRuleChainModel();
- }
- saveResult.next();
+ saveResult.next();
});
});
return saveResult;
diff --git a/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html
index ba09311895..2e16f04498 100644
--- a/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html
+++ b/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.html
@@ -30,7 +30,7 @@
{{ 'entity.version-conflict.link' | translate:
- { entityType: (entityTypeTranslations.get(data.entity.id.entityType).type | translate) }
+ { entityType: (entityTypeTranslations.get(entityId.entityType).type | translate) }
}}
{{ 'entity.link' | translate }}.
diff --git a/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.ts
index 37275bd79c..b4f34ed232 100644
--- a/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.ts
+++ b/ui-ngx/src/app/shared/components/dialog/entity-conflict-dialog/entity-conflict-dialog.component.ts
@@ -21,10 +21,12 @@ import { ImportExportService } from '@shared/import-export/import-export.service
import { CommonModule } from '@angular/common';
import { entityTypeTranslations } from '@shared/models/entity-type.models';
import { EntityInfoData } from '@shared/models/entity.models';
+import { EntityId } from '@shared/models/id/entity-id';
+import { RuleChainMetaData } from '@shared/models/rule-chain.models';
interface EntityConflictDialogData {
message: string;
- entity: EntityInfoData;
+ entity: EntityInfoData | RuleChainMetaData;
}
@Component({
@@ -38,13 +40,18 @@ interface EntityConflictDialogData {
],
})
export class EntityConflictDialogComponent {
+
+ entityId: EntityId;
+
readonly entityTypeTranslations = entityTypeTranslations;
constructor(
@Inject(MAT_DIALOG_DATA) public data: EntityConflictDialogData,
private dialogRef: MatDialogRef
,
private importExportService: ImportExportService,
- ) {}
+ ) {
+ this.entityId = (data.entity as EntityInfoData).id ?? (data.entity as RuleChainMetaData).ruleChainId;
+ }
onCancel(): void {
this.dialogRef.close();
diff --git a/ui-ngx/src/app/shared/import-export/import-export.service.ts b/ui-ngx/src/app/shared/import-export/import-export.service.ts
index 4746365c50..5f246873d7 100644
--- a/ui-ngx/src/app/shared/import-export/import-export.service.ts
+++ b/ui-ngx/src/app/shared/import-export/import-export.service.ts
@@ -55,7 +55,11 @@ import { EntityType } from '@shared/models/entity-type.models';
import { UtilsService } from '@core/services/utils.service';
import { WidgetService } from '@core/http/widget.service';
import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
-import { EntityInfoData, ImportEntitiesResultInfo, ImportEntityData } from '@shared/models/entity.models';
+import {
+ EntityInfoData,
+ ImportEntitiesResultInfo,
+ ImportEntityData
+} from '@shared/models/entity.models';
import { RequestConfig } from '@core/http/http-utils';
import { RuleChain, RuleChainImport, RuleChainMetaData, RuleChainType } from '@shared/models/rule-chain.models';
import { RuleChainService } from '@core/http/rule-chain.service';
@@ -360,25 +364,26 @@ export class ImportExportService {
});
}
- public exportEntity(entityData: EntityInfoData): void {
+ public exportEntity(entityData: EntityInfoData | RuleChainMetaData): void {
+ const id = (entityData as EntityInfoData).id ?? (entityData as RuleChainMetaData).ruleChainId;
let preparedData;
- switch (entityData.id.entityType) {
+ switch (id.entityType) {
case EntityType.DEVICE_PROFILE:
case EntityType.ASSET_PROFILE:
preparedData = this.prepareProfileExport(entityData as DeviceProfile | AssetProfile);
break;
case EntityType.RULE_CHAIN:
- this.ruleChainService.getRuleChainMetadata(entityData.id.id)
+ forkJoin([this.ruleChainService.getRuleChainMetadata(id.id), this.ruleChainService.getRuleChain(id.id)])
.pipe(
take(1),
- map((ruleChainMetaData) => {
+ map(([ruleChainMetaData, ruleChain]) => {
const ruleChainExport: RuleChainImport = {
- ruleChain: this.prepareRuleChain(entityData as RuleChain),
+ ruleChain: this.prepareRuleChain(ruleChain),
metadata: this.prepareRuleChainMetaData(ruleChainMetaData)
};
return ruleChainExport;
}))
- .subscribe(ruleChainData => this.exportToPc(ruleChainData, entityData.name));
+ .subscribe(this.onRuleChainExported());
return;
case EntityType.WIDGETS_BUNDLE:
this.exportSelectedWidgetsBundle(entityData as WidgetsBundle);
@@ -389,7 +394,7 @@ export class ImportExportService {
default:
preparedData = this.prepareExport(entityData);
}
- this.exportToPc(preparedData, entityData.name);
+ this.exportToPc(preparedData, (entityData as EntityInfoData).name);
}
private exportSelectedWidgetsBundle(widgetsBundle: WidgetsBundle): void {
@@ -584,8 +589,12 @@ export class ImportExportService {
return ruleChainExport;
})
))
- ).subscribe({
- next: (ruleChainExport) => {
+ ).subscribe(this.onRuleChainExported());
+ }
+
+ private onRuleChainExported() {
+ return {
+ next: (ruleChainExport: RuleChainImport) => {
let name = ruleChainExport.ruleChain.name;
name = name.toLowerCase().replace(/\W/g, '_');
this.exportToPc(ruleChainExport, name);
@@ -593,7 +602,7 @@ export class ImportExportService {
error: (e) => {
this.handleExportError(e, 'rulechain.export-failed-error');
}
- });
+ };
}
public importRuleChain(expectedRuleChainType: RuleChainType): Observable {
diff --git a/ui-ngx/src/app/shared/models/rule-chain.models.ts b/ui-ngx/src/app/shared/models/rule-chain.models.ts
index 0bfdfbc459..bca4ae399e 100644
--- a/ui-ngx/src/app/shared/models/rule-chain.models.ts
+++ b/ui-ngx/src/app/shared/models/rule-chain.models.ts
@@ -34,7 +34,7 @@ export interface RuleChain extends BaseData, HasTenantId, HasVersio
isDefault?: boolean;
}
-export interface RuleChainMetaData {
+export interface RuleChainMetaData extends HasVersion {
ruleChainId: RuleChainId;
firstNodeIndex?: number;
nodes: Array;