From 57a9a0a6d3b997441cfa5b3499c5ff97704a5176 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 2 Jun 2022 12:32:10 +0300 Subject: [PATCH] UI: Version load error handling --- .../http/entities-version-control.service.ts | 32 ++++++- .../vc/auto-commit-settings.component.html | 3 + .../vc/auto-commit-settings.component.ts | 8 +- .../vc/complex-version-create.component.html | 2 +- .../vc/complex-version-create.component.scss | 21 ----- .../vc/complex-version-create.component.ts | 23 +++-- .../vc/complex-version-load.component.html | 11 +-- .../vc/complex-version-load.component.ts | 34 +++++--- ...entity-types-version-create.component.html | 5 +- .../entity-types-version-create.component.ts | 4 + .../entity-types-version-load.component.html | 5 +- .../vc/entity-types-version-load.component.ts | 4 + .../vc/entity-version-create.component.html | 5 +- .../vc/entity-version-create.component.scss | 21 ----- .../vc/entity-version-create.component.ts | 22 +++-- .../vc/entity-version-diff.component.ts | 4 +- .../vc/entity-version-restore.component.html | 84 +++++++++++-------- .../vc/entity-version-restore.component.ts | 25 ++++-- .../vc/entity-versions-table.component.html | 4 +- .../vc/entity-versions-table.component.scss | 7 ++ .../vc/entity-versions-table.component.ts | 24 ++---- .../vc/repository-settings.component.html | 2 +- .../vc/repository-settings.component.ts | 7 +- .../vc/version-control.component.html | 3 +- .../vc/version-control.component.ts | 3 +- ...ad.component.scss => version-control.scss} | 6 +- .../rulechain/rulechain-page.component.ts | 4 +- ui-ngx/src/app/shared/models/vc.models.ts | 30 ++++++- .../assets/locale/locale.constant-en_US.json | 8 +- 29 files changed, 257 insertions(+), 154 deletions(-) delete mode 100644 ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.scss delete mode 100644 ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.scss rename ui-ngx/src/app/modules/home/components/vc/{complex-version-load.component.scss => version-control.scss} (89%) diff --git a/ui-ngx/src/app/core/http/entities-version-control.service.ts b/ui-ngx/src/app/core/http/entities-version-control.service.ts index e02db94280..bb4a10e4e5 100644 --- a/ui-ngx/src/app/core/http/entities-version-control.service.ts +++ b/ui-ngx/src/app/core/http/entities-version-control.service.ts @@ -19,7 +19,7 @@ import { HttpClient } from '@angular/common/http'; import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; import { Observable, of } from 'rxjs'; import { - BranchInfo, EntityDataDiff, EntityDataInfo, + BranchInfo, EntityDataDiff, EntityDataInfo, EntityLoadError, entityLoadErrorTranslationMap, EntityLoadErrorType, EntityVersion, VersionCreateRequest, VersionCreationResult, @@ -28,11 +28,13 @@ import { import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; import { EntityId } from '@shared/models/id/entity-id'; -import { EntityType } from '@shared/models/entity-type.models'; +import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; import { select, Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { selectIsUserLoaded } from '@core/auth/auth.selectors'; import { catchError, tap } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; @Injectable({ providedIn: 'root' @@ -43,6 +45,8 @@ export class EntitiesVersionControlService { constructor( private http: HttpClient, + private translate: TranslateService, + private sanitizer: DomSanitizer, private store: Store ) { @@ -109,8 +113,8 @@ export class EntitiesVersionControlService { defaultHttpOptionsFromConfig(config)); } - public loadEntitiesVersion(request: VersionLoadRequest, config?: RequestConfig): Observable> { - return this.http.post>('/api/entities/vc/entity', request, defaultHttpOptionsFromConfig(config)); + public loadEntitiesVersion(request: VersionLoadRequest, config?: RequestConfig): Observable { + return this.http.post('/api/entities/vc/entity', request, defaultHttpOptionsFromConfig(config)); } public compareEntityDataToVersion(branch: string, @@ -120,4 +124,24 @@ export class EntitiesVersionControlService { return this.http.get(`/api/entities/vc/diff/${branch}/${entityId.entityType}/${entityId.id}?versionId=${versionId}`, defaultHttpOptionsFromConfig(config)); } + + public entityLoadErrorToMessage(entityLoadError: EntityLoadError): SafeHtml { + const type = entityLoadError.type; + const messageId = entityLoadErrorTranslationMap.get(type); + const messageArgs = {} as any; + switch (type) { + case EntityLoadErrorType.DEVICE_CREDENTIALS_CONFLICT: + messageArgs.entityId = entityLoadError.source.id; + break; + case EntityLoadErrorType.MISSING_REFERENCED_ENTITY: + messageArgs.sourceEntityTypeName = + (this.translate.instant(entityTypeTranslations.get(entityLoadError.source.entityType).type) as string).toLowerCase(); + messageArgs.sourceEntityId = entityLoadError.source.id; + messageArgs.targetEntityTypeName = + (this.translate.instant(entityTypeTranslations.get(entityLoadError.target.entityType).type) as string).toLowerCase(); + messageArgs.targetEntityId = entityLoadError.target.id; + break; + } + return this.sanitizer.bypassSecurityTrustHtml(this.translate.instant(messageId, messageArgs)); + } } diff --git a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html index e95cfc59fb..b04ab515ae 100644 --- a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.html @@ -75,6 +75,9 @@
+ + {{ 'version-control.export-credentials' | translate }} + {{ 'version-control.export-attributes' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.ts b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.ts index dc009d49cd..fd100f6247 100644 --- a/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/auto-commit-settings.component.ts @@ -39,6 +39,8 @@ export class AutoCommitSettingsComponent extends PageComponent implements OnInit autoCommitSettingsForm: FormGroup; settings: AutoCommitSettings = null; + entityTypes = EntityType; + constructor(protected store: Store, private adminService: AdminService, private dialogService: DialogService, @@ -98,7 +100,8 @@ export class AutoCommitSettingsComponent extends PageComponent implements OnInit const config: AutoVersionCreateConfig = { branch: null, saveAttributes: true, - saveRelations: false + saveRelations: false, + saveCredentials: true }; const allowed = this.allowedEntityTypes(); let entityType: EntityType = null; @@ -199,7 +202,8 @@ export class AutoCommitSettingsComponent extends PageComponent implements OnInit config: this.fb.group({ branch: [config.branch, []], saveRelations: [config.saveRelations, []], - saveAttributes: [config.saveAttributes, []] + saveAttributes: [config.saveAttributes, []], + saveCredentials: [config.saveCredentials, []] }) } ); diff --git a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html index 4ace5e8849..9e15076788 100644 --- a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.html @@ -70,7 +70,7 @@
-
{{ resultMessage }}
+
-
-
+
+
{{ 'version-control.no-entities-restored' | translate }}
-
{{ versionLoadResultMessage(versionLoadResult) }}
+
+
{{ entityTypeLoadResultMessage(entityTypeLoadResult) }}
-
{{ resultMessage }}
+
{{ resultMessage }}
- -
+
+ +

{{ 'version-control.restore-entity-from-version' | translate: {versionName} }}

+ +
+ + + +
+
+
+ + {{ 'version-control.load-credentials' | translate }} + + + {{ 'version-control.load-attributes' | translate }} + + + {{ 'version-control.load-relations' | translate }} + +
+
+
+
+ + +
+
+
+
+
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts index 146a8570c2..c31030f74b 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts @@ -30,11 +30,12 @@ import { EntityId } from '@shared/models/id/entity-id'; import { TranslateService } from '@ngx-translate/core'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { delay } from 'rxjs/operators'; +import { SafeHtml } from '@angular/platform-browser'; @Component({ selector: 'tb-entity-version-restore', templateUrl: './entity-version-restore.component.html', - styleUrls: [] + styleUrls: ['./version-control.scss'] }) export class EntityVersionRestoreComponent extends PageComponent implements OnInit { @@ -51,7 +52,7 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn externalEntityId: EntityId; @Input() - onClose: (result: Array | null) => void; + onClose: (result: VersionLoadResult | null) => void; @Input() popoverComponent: TbPopoverComponent; @@ -60,6 +61,8 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn restoreFormGroup: FormGroup; + errorMessage: SafeHtml; + constructor(protected store: Store, private entitiesVersionControlService: EntitiesVersionControlService, private cd: ChangeDetectorRef, @@ -71,7 +74,8 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn ngOnInit(): void { this.restoreFormGroup = this.fb.group({ loadAttributes: [true, []], - loadRelations: [true, []] + loadRelations: [true, []], + loadCredentials: [true, []] }); this.entitiesVersionControlService.getEntityDataInfo(this.externalEntityId, this.versionId).subscribe((data) => { this.entityDataInfo = data; @@ -95,13 +99,22 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn externalEntityId: this.externalEntityId, config: { loadRelations: this.entityDataInfo.hasRelations ? this.restoreFormGroup.get('loadRelations').value : false, - loadAttributes: this.entityDataInfo.hasAttributes ? this.restoreFormGroup.get('loadAttributes').value : false + loadAttributes: this.entityDataInfo.hasAttributes ? this.restoreFormGroup.get('loadAttributes').value : false, + loadCredentials: this.entityDataInfo.hasCredentials ? this.restoreFormGroup.get('loadCredentials').value : false }, type: VersionLoadRequestType.SINGLE_ENTITY }; this.entitiesVersionControlService.loadEntitiesVersion(request).subscribe((result) => { - if (this.onClose) { - this.onClose(result); + if (result.error) { + this.errorMessage = this.entitiesVersionControlService.entityLoadErrorToMessage(result.error); + this.cd.detectChanges(); + if (this.popoverComponent) { + this.popoverComponent.updatePosition(); + } + } else { + if (this.onClose) { + this.onClose(result); + } } }); } diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html index 79da474200..b6accc40dc 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html @@ -15,8 +15,8 @@ limitations under the License. --> -
-
+
+
diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss index ec5cb02256..3256c3c956 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss @@ -20,6 +20,13 @@ height: 100%; display: block; .tb-entity-table { + + &.tb-popover-mode { + position: relative; + width: 800px; + height: 600px; + } + .tb-entity-table-content { width: 100%; height: 100%; diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts index 38b0a33da4..d776939aaf 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts @@ -49,6 +49,7 @@ import { EntityVersionRestoreComponent } from '@home/components/vc/entity-versio import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component'; import { ComplexVersionCreateComponent } from '@home/components/vc/complex-version-create.component'; import { ComplexVersionLoadComponent } from '@home/components/vc/complex-version-load.component'; +import { TbPopoverComponent } from '@shared/components/popover.component'; @Component({ selector: 'tb-entity-versions-table', @@ -63,7 +64,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni singleEntityMode = false; @Input() - popoverMode = false; + popoverComponent: TbPopoverComponent; @Input() onBeforeCreateVersion: () => Observable; @@ -211,14 +212,9 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.updateData(); } } - }, - onContentUpdated: () => { - createVersionPopover.updatePosition(); - setTimeout(() => { - createVersionPopover.updatePosition(); - }); } }, {}, {}, {}, false); + createVersionPopover.tbComponentRef.instance.popoverComponent = createVersionPopover; } } @@ -243,14 +239,9 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni this.updateData(); } } - }, - onContentUpdated: () => { - complexCreateVersionPopover.updatePosition(); - setTimeout(() => { - complexCreateVersionPopover.updatePosition(); - }); } }, {}, {}, {}, false); + complexCreateVersionPopover.tbComponentRef.instance.popoverComponent = complexCreateVersionPopover; } } @@ -293,9 +284,9 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni versionName: entityVersion.name, versionId: entityVersion.id, externalEntityId: this.externalEntityIdValue, - onClose: (result: Array | null) => { + onClose: (result: VersionLoadResult | null) => { restoreVersionPopover.hide(); - if (result && result.length) { + if (result && !result.error && result.result.length) { this.versionRestored.emit(); } } @@ -318,10 +309,11 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni branch: this.branch, versionName: entityVersion.name, versionId: entityVersion.id, - onClose: (result: Array | null) => { + onClose: (result: VersionLoadResult | null) => { restoreEntitiesVersionPopover.hide(); } }, {}, {}, {}, false); + restoreEntitiesVersionPopover.tbComponentRef.instance.popoverComponent = restoreEntitiesVersionPopover; } } diff --git a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html index bdab6c061b..3e8bd271f3 100644 --- a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.html @@ -16,7 +16,7 @@ -->
- +
admin.repository-settings diff --git a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts index c73cf0e632..1120185db9 100644 --- a/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/repository-settings.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { FormBuilder, FormGroup, FormGroupDirective, Validators } from '@angular/forms'; import { select, Store } from '@ngrx/store'; @@ -33,6 +33,7 @@ import { ActionAuthUpdateHasRepository } from '@core/auth/auth.actions'; import { selectHasRepository } from '@core/auth/auth.selectors'; import { catchError, mergeMap, take } from 'rxjs/operators'; import { of } from 'rxjs'; +import { TbPopoverComponent } from '@shared/components/popover.component'; @Component({ selector: 'tb-repository-settings', @@ -44,6 +45,9 @@ export class RepositorySettingsComponent extends PageComponent implements OnInit @Input() detailsMode = false; + @Input() + popoverComponent: TbPopoverComponent; + repositorySettingsForm: FormGroup; settings: RepositorySettings = null; @@ -61,6 +65,7 @@ export class RepositorySettingsComponent extends PageComponent implements OnInit private adminService: AdminService, private dialogService: DialogService, private translate: TranslateService, + private cd: ChangeDetectorRef, public fb: FormBuilder) { super(store); } diff --git a/ui-ngx/src/app/modules/home/components/vc/version-control.component.html b/ui-ngx/src/app/modules/home/components/vc/version-control.component.html index 0ede98554d..eaf80fd664 100644 --- a/ui-ngx/src/app/modules/home/components/vc/version-control.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/version-control.component.html @@ -16,11 +16,12 @@ --> { this.reloadRuleChain(); }); diff --git a/ui-ngx/src/app/shared/models/vc.models.ts b/ui-ngx/src/app/shared/models/vc.models.ts index ee718c3aec..0c6a667b88 100644 --- a/ui-ngx/src/app/shared/models/vc.models.ts +++ b/ui-ngx/src/app/shared/models/vc.models.ts @@ -33,6 +33,7 @@ export const exportableEntityTypes: Array = [ export interface VersionCreateConfig { saveRelations: boolean; saveAttributes: boolean; + saveCredentials: boolean; } export enum VersionCreateRequestType { @@ -90,6 +91,7 @@ export function createDefaultEntityTypesVersionCreate(): {[entityType: string]: syncStrategy: null, saveAttributes: true, saveRelations: true, + saveCredentials: true, allEntities: true, entityIds: [] }; @@ -100,6 +102,7 @@ export function createDefaultEntityTypesVersionCreate(): {[entityType: string]: export interface VersionLoadConfig { loadRelations: boolean; loadAttributes: boolean; + loadCredentials: boolean; } export enum VersionLoadRequestType { @@ -135,6 +138,7 @@ export function createDefaultEntityTypesVersionLoad(): {[entityType: string]: En res[entityType] = { loadAttributes: true, loadRelations: true, + loadCredentials: true, removeOtherEntities: false, findExistingEntityByName: true }; @@ -161,13 +165,36 @@ export interface VersionCreationResult { removed: number; } -export interface VersionLoadResult { +export interface EntityTypeLoadResult { entityType: EntityType; created: number; updated: number; deleted: number; } +export enum EntityLoadErrorType { + DEVICE_CREDENTIALS_CONFLICT = 'DEVICE_CREDENTIALS_CONFLICT', + MISSING_REFERENCED_ENTITY = 'MISSING_REFERENCED_ENTITY' +} + +export const entityLoadErrorTranslationMap = new Map( + [ + [EntityLoadErrorType.DEVICE_CREDENTIALS_CONFLICT, 'version-control.device-credentials-conflict'], + [EntityLoadErrorType.MISSING_REFERENCED_ENTITY, 'version-control.missing-referenced-entity'] + ] +); + +export interface EntityLoadError { + type: EntityLoadErrorType; + source: EntityId; + target: EntityId; +} + +export interface VersionLoadResult { + result: Array; + error: EntityLoadError; +} + export interface EntityExportData> { entity: E; entityType: EntityType; @@ -195,4 +222,5 @@ export function entityExportDataToJsonString(data: EntityExportData): strin export interface EntityDataInfo { hasRelations: boolean; hasAttributes: boolean; + hasCredentials: boolean; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index ad9ba856ab..8a4d8ff4db 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3127,6 +3127,7 @@ "author": "Author", "export-relations": "Export relations", "export-attributes": "Export attributes", + "export-credentials": "Export credentials", "entity-versions": "Entity versions", "versions": "Versions", "created-time": "Created time", @@ -3140,6 +3141,7 @@ "restore-entity-from-version": "Restore entity from version '{{versionName}}'", "load-relations": "Load relations", "load-attributes": "Load attributes", + "load-credentials": "Load credentials", "show-version-diff": "Show version diff", "diff-entity-with-version": "Diff with entity version '{{versionName}}'", "previous-difference": "Previous Difference", @@ -3158,7 +3160,7 @@ "no-entities-to-restore-prompt": "Please specify entities to restore", "add-entity-type": "Add entity type", "remove-all": "Remove all", - "version-create-result": "{ added, plural, 0 {No entities} 1 {1 entity} other {# entities} } added.\n{ modified, plural, 0 {No entities} 1 {1 entity} other {# entities} } modified.\n{ removed, plural, 0 {No entities} 1 {1 entity} other {# entities} } removed.", + "version-create-result": "{ added, plural, 0 {No entities} 1 {1 entity} other {# entities} } added.
{ modified, plural, 0 {No entities} 1 {1 entity} other {# entities} } modified.
{ removed, plural, 0 {No entities} 1 {1 entity} other {# entities} } removed.", "remove-other-entities": "Remove other entities", "find-existing-entity-by-name": "Find existing entity by name", "restore-entities-from-version": "Restore entities from version '{{versionName}}'", @@ -3170,7 +3172,9 @@ "auto-commit-to-branch": "auto-commit to {{ branch }} branch", "default-create-entity-version-name": "{{entityName}} update", "sync-strategy-merge-hint": "Sync strategy merge hint", - "sync-strategy-overwrite-hint": "Sync strategy overwrite hint" + "sync-strategy-overwrite-hint": "Sync strategy overwrite hint", + "device-credentials-conflict": "Failed to load the device with external id {{entityId}}
due to the same credentials are already present in the database for another device.
Please consider disabling the load credentials setting in the restore form.", + "missing-referenced-entity": "Failed to load the {{sourceEntityTypeName}} with external id {{sourceEntityId}}
because it references missing {{targetEntityTypeName}} with id {{targetEntityId}}." }, "widget": { "widget-library": "Widgets Library",