UI: Implement progress on single entity version create request.

This commit is contained in:
Igor Kulikov 2022-06-20 19:48:29 +03:00
parent 5c240469b2
commit 5e9899daad
7 changed files with 92 additions and 31 deletions

View File

@ -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 <E extends ExportableEntity<I>, I extends EntityId> EntityImportResult<E> importEntity(User user, EntityExportData<E> 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<E> importResult = exportImportService.importEntity(ctx, exportData);

View File

@ -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<VersionCreationResult> {
return this.http.post<VersionCreationResult>('/api/entities/vc/version', request, defaultHttpOptionsFromConfig(config)).pipe(
tap(() => {
this.store.dispatch(new ActionLoadStart());
return this.http.post<string>('/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<VersionCreationResult> {
return this.http.get<VersionCreationResult>(`/api/entities/vc/version/${requestId}/status`,
defaultHttpOptionsFromConfig({...config, ...{ignoreLoading: true}}));
}
public listEntityVersions(pageLink: PageLink, branch: string,
externalEntityId: EntityId,
config?: RequestConfig): Observable<PageData<EntityVersion>> {

View File

@ -16,7 +16,7 @@
-->
<section style="min-width: 400px;">
<section *ngIf="!resultMessage">
<section *ngIf="!versionCreateResult$">
<mat-toolbar>
<h2>{{ 'version-control.create-entity-version' | translate }}</h2>
<span fxFlex></span>
@ -65,15 +65,27 @@
</button>
</div>
</section>
<section *ngIf="resultMessage">
<div class="mat-title vc-result-message">{{ resultMessage }}</div>
<div fxLayoutAlign="end center" fxLayoutGap="8px">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.close' | translate }}
</button>
</div>
<section *ngIf="versionCreateResult$">
<section *ngIf="(versionCreateResult$ | async)?.done; else progress">
<section *ngIf="resultMessage">
<div class="mat-title vc-result-message">{{ resultMessage }}</div>
<div fxLayoutAlign="end center" fxLayoutGap="8px">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.close' | translate }}
</button>
</div>
</section>
</section>
<ng-template #progress>
<section fxLayout="column" fxLayoutAlign="center center">
<div class="mat-title vc-result-message progress">
<span translate>version-control.creating-version</span>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
</section>
</ng-template>
</section>
</section>

View File

@ -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<VersionCreationResult>;
private versionCreateResultSubscription: Subscription;
constructor(protected store: Store<AppState>,
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);
}
});
});
}
}

View File

@ -27,5 +27,8 @@
text-align: start;
font-weight: 400;
}
&.progress {
padding-bottom: 32px;
}
}
}

View File

@ -165,6 +165,8 @@ export interface VersionCreationResult {
added: number;
modified: number;
removed: number;
error: string;
done: boolean;
}
export interface EntityTypeLoadResult {

View File

@ -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}}'",