diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java index 9b34eaae25..e516d5e131 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java @@ -82,6 +82,7 @@ import org.thingsboard.server.service.sync.vc.data.SimpleEntitiesExportCtx; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -433,7 +434,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest } protected , I extends EntityId> EntityImportResult importEntity(User user, EntityExportData exportData, EntityImportSettings importSettings) throws Exception { - EntitiesImportCtx ctx = new EntitiesImportCtx(getSecurityUser(user), null, importSettings); + EntitiesImportCtx ctx = new EntitiesImportCtx(UUID.randomUUID(), getSecurityUser(user), null, importSettings); ctx.setFinalImportAttempt(true); exportData = JacksonUtil.treeToValue(JacksonUtil.valueToTree(exportData), EntityExportData.class); EntityImportResult importResult = exportImportService.importEntity(ctx, exportData); 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 bb4a10e4e5..bded799c4b 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 @@ -17,13 +17,19 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; -import { Observable, of } from 'rxjs'; +import { Observable, of, timer } from 'rxjs'; import { - BranchInfo, EntityDataDiff, EntityDataInfo, EntityLoadError, entityLoadErrorTranslationMap, EntityLoadErrorType, + BranchInfo, + EntityDataDiff, + EntityDataInfo, + EntityLoadError, + entityLoadErrorTranslationMap, + EntityLoadErrorType, EntityVersion, VersionCreateRequest, VersionCreationResult, - VersionLoadRequest, VersionLoadResult + VersionLoadRequest, + VersionLoadResult } from '@shared/models/vc.models'; import { PageLink } from '@shared/models/page/page-link'; import { PageData } from '@shared/models/page/page-data'; @@ -32,9 +38,10 @@ import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.m 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 { catchError, finalize, switchMap, takeWhile, tap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { ActionLoadFinish, ActionLoadStart } from '@core/interceptors/load.actions'; @Injectable({ providedIn: 'root' @@ -83,16 +90,30 @@ export class EntitiesVersionControlService { } public saveEntitiesVersion(request: VersionCreateRequest, config?: RequestConfig): Observable { - return this.http.post('/api/entities/vc/version', request, defaultHttpOptionsFromConfig(config)).pipe( - tap(() => { + this.store.dispatch(new ActionLoadStart()); + return this.http.post('/api/entities/vc/version', request, + defaultHttpOptionsFromConfig({...config, ...{ignoreLoading: true}})).pipe( + switchMap((requestId) => { + return timer(0, 2000).pipe( + switchMap(() => this.getVersionCreateRequestStatus(requestId, config)), + takeWhile((res) => !res.done, true) + ); + }), + finalize(() => { const branch = request.branch; if (this.branchList && !this.branchList.find(b => b.name === branch)) { this.branchList = null; } - }) + this.store.dispatch(new ActionLoadFinish()); + }), ); } + private getVersionCreateRequestStatus(requestId: string, config?: RequestConfig): Observable { + return this.http.get(`/api/entities/vc/version/${requestId}/status`, + defaultHttpOptionsFromConfig({...config, ...{ignoreLoading: true}})); + } + public listEntityVersions(pageLink: PageLink, branch: string, externalEntityId: EntityId, config?: RequestConfig): Observable> { diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html index 270d42d328..157dcf56a1 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.html @@ -16,7 +16,7 @@ -->
-
+

{{ 'version-control.create-entity-version' | translate }}

@@ -65,15 +65,27 @@
-
-
{{ resultMessage }}
-
- -
+
+
+
+
{{ resultMessage }}
+
+ +
+
+
+ +
+
+ version-control.creating-version + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts index e3bf44560b..469ff49a0c 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { @@ -27,16 +27,17 @@ import { AppState } from '@core/core.state'; import { EntitiesVersionControlService } from '@core/http/entities-version-control.service'; import { EntityId } from '@shared/models/id/entity-id'; import { TranslateService } from '@ngx-translate/core'; -import { Observable, of } from 'rxjs'; +import { Observable, of, Subscription } from 'rxjs'; import { EntityType } from '@shared/models/entity-type.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; +import { share } from 'rxjs/operators'; @Component({ selector: 'tb-entity-version-create', templateUrl: './entity-version-create.component.html', styleUrls: ['./version-control.scss'] }) -export class EntityVersionCreateComponent extends PageComponent implements OnInit { +export class EntityVersionCreateComponent extends PageComponent implements OnInit, OnDestroy { @Input() branch: string; @@ -62,6 +63,10 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni resultMessage: string; + versionCreateResult$: Observable; + + private versionCreateResultSubscription: Subscription; + constructor(protected store: Store, private entitiesVersionControlService: EntitiesVersionControlService, private cd: ChangeDetectorRef, @@ -81,6 +86,13 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni }); } + ngOnDestroy() { + super.ngOnDestroy(); + if (this.versionCreateResultSubscription) { + this.versionCreateResultSubscription.unsubscribe(); + } + } + cancel(): void { if (this.onClose) { this.onClose(null, null); @@ -101,18 +113,27 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni }, type: VersionCreateRequestType.SINGLE_ENTITY }; - this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => { - if (!result.added && !result.modified) { - this.resultMessage = this.translate.instant('version-control.nothing-to-commit'); - this.cd.detectChanges(); - if (this.popoverComponent) { - this.popoverComponent.updatePosition(); + this.versionCreateResult$ = this.entitiesVersionControlService.saveEntitiesVersion(request).pipe( + share() + ); + this.cd.detectChanges(); + if (this.popoverComponent) { + this.popoverComponent.updatePosition(); + } + + this.versionCreateResultSubscription = this.versionCreateResult$.subscribe((result) => { + if (result.done) { + if (!result.added && !result.modified || result.error) { + this.resultMessage = result.error ? result.error : this.translate.instant('version-control.nothing-to-commit'); + this.cd.detectChanges(); + if (this.popoverComponent) { + this.popoverComponent.updatePosition(); + } + } else if (this.onClose) { + this.onClose(result, request.branch); } - } else if (this.onClose) { - this.onClose(result, request.branch); } }); }); } } - diff --git a/ui-ngx/src/app/modules/home/components/vc/version-control.scss b/ui-ngx/src/app/modules/home/components/vc/version-control.scss index 01aaae5455..d0d96be941 100644 --- a/ui-ngx/src/app/modules/home/components/vc/version-control.scss +++ b/ui-ngx/src/app/modules/home/components/vc/version-control.scss @@ -27,5 +27,8 @@ text-align: start; font-weight: 400; } + &.progress { + padding-bottom: 32px; + } } } diff --git a/ui-ngx/src/app/shared/models/vc.models.ts b/ui-ngx/src/app/shared/models/vc.models.ts index 5ef0a18b08..15b75c4c10 100644 --- a/ui-ngx/src/app/shared/models/vc.models.ts +++ b/ui-ngx/src/app/shared/models/vc.models.ts @@ -165,6 +165,8 @@ export interface VersionCreationResult { added: number; modified: number; removed: number; + error: string; + done: boolean; } export interface EntityTypeLoadResult { 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 0ab99ccd79..f361574e63 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3306,6 +3306,7 @@ "no-versions-text": "No versions found", "copy-full-version-id": "Copy full version id", "create-version": "Create version", + "creating-version": "Creating version... Please wait", "nothing-to-commit": "No changes to commit", "restore-version": "Restore version", "restore-entity-from-version": "Restore entity from version '{{versionName}}'",