UI: Implement progress on single entity version create request.
This commit is contained in:
parent
5c240469b2
commit
5e9899daad
@ -82,6 +82,7 @@ import org.thingsboard.server.service.sync.vc.data.SimpleEntitiesExportCtx;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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 {
|
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);
|
ctx.setFinalImportAttempt(true);
|
||||||
exportData = JacksonUtil.treeToValue(JacksonUtil.valueToTree(exportData), EntityExportData.class);
|
exportData = JacksonUtil.treeToValue(JacksonUtil.valueToTree(exportData), EntityExportData.class);
|
||||||
EntityImportResult<E> importResult = exportImportService.importEntity(ctx, exportData);
|
EntityImportResult<E> importResult = exportImportService.importEntity(ctx, exportData);
|
||||||
|
|||||||
@ -17,13 +17,19 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils';
|
import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of, timer } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
BranchInfo, EntityDataDiff, EntityDataInfo, EntityLoadError, entityLoadErrorTranslationMap, EntityLoadErrorType,
|
BranchInfo,
|
||||||
|
EntityDataDiff,
|
||||||
|
EntityDataInfo,
|
||||||
|
EntityLoadError,
|
||||||
|
entityLoadErrorTranslationMap,
|
||||||
|
EntityLoadErrorType,
|
||||||
EntityVersion,
|
EntityVersion,
|
||||||
VersionCreateRequest,
|
VersionCreateRequest,
|
||||||
VersionCreationResult,
|
VersionCreationResult,
|
||||||
VersionLoadRequest, VersionLoadResult
|
VersionLoadRequest,
|
||||||
|
VersionLoadResult
|
||||||
} from '@shared/models/vc.models';
|
} from '@shared/models/vc.models';
|
||||||
import { PageLink } from '@shared/models/page/page-link';
|
import { PageLink } from '@shared/models/page/page-link';
|
||||||
import { PageData } from '@shared/models/page/page-data';
|
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 { select, Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { selectIsUserLoaded } from '@core/auth/auth.selectors';
|
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 { TranslateService } from '@ngx-translate/core';
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||||
|
import { ActionLoadFinish, ActionLoadStart } from '@core/interceptors/load.actions';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -83,16 +90,30 @@ export class EntitiesVersionControlService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public saveEntitiesVersion(request: VersionCreateRequest, config?: RequestConfig): Observable<VersionCreationResult> {
|
public saveEntitiesVersion(request: VersionCreateRequest, config?: RequestConfig): Observable<VersionCreationResult> {
|
||||||
return this.http.post<VersionCreationResult>('/api/entities/vc/version', request, defaultHttpOptionsFromConfig(config)).pipe(
|
this.store.dispatch(new ActionLoadStart());
|
||||||
tap(() => {
|
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;
|
const branch = request.branch;
|
||||||
if (this.branchList && !this.branchList.find(b => b.name === branch)) {
|
if (this.branchList && !this.branchList.find(b => b.name === branch)) {
|
||||||
this.branchList = null;
|
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,
|
public listEntityVersions(pageLink: PageLink, branch: string,
|
||||||
externalEntityId: EntityId,
|
externalEntityId: EntityId,
|
||||||
config?: RequestConfig): Observable<PageData<EntityVersion>> {
|
config?: RequestConfig): Observable<PageData<EntityVersion>> {
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<section style="min-width: 400px;">
|
<section style="min-width: 400px;">
|
||||||
<section *ngIf="!resultMessage">
|
<section *ngIf="!versionCreateResult$">
|
||||||
<mat-toolbar>
|
<mat-toolbar>
|
||||||
<h2>{{ 'version-control.create-entity-version' | translate }}</h2>
|
<h2>{{ 'version-control.create-entity-version' | translate }}</h2>
|
||||||
<span fxFlex></span>
|
<span fxFlex></span>
|
||||||
@ -65,6 +65,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section *ngIf="versionCreateResult$">
|
||||||
|
<section *ngIf="(versionCreateResult$ | async)?.done; else progress">
|
||||||
<section *ngIf="resultMessage">
|
<section *ngIf="resultMessage">
|
||||||
<div class="mat-title vc-result-message">{{ resultMessage }}</div>
|
<div class="mat-title vc-result-message">{{ resultMessage }}</div>
|
||||||
<div fxLayoutAlign="end center" fxLayoutGap="8px">
|
<div fxLayoutAlign="end center" fxLayoutGap="8px">
|
||||||
@ -77,3 +79,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</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>
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
/// limitations under the License.
|
/// 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 { PageComponent } from '@shared/components/page.component';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import {
|
import {
|
||||||
@ -27,16 +27,17 @@ import { AppState } from '@core/core.state';
|
|||||||
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
|
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
|
||||||
import { EntityId } from '@shared/models/id/entity-id';
|
import { EntityId } from '@shared/models/id/entity-id';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
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 { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
|
import { share } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entity-version-create',
|
selector: 'tb-entity-version-create',
|
||||||
templateUrl: './entity-version-create.component.html',
|
templateUrl: './entity-version-create.component.html',
|
||||||
styleUrls: ['./version-control.scss']
|
styleUrls: ['./version-control.scss']
|
||||||
})
|
})
|
||||||
export class EntityVersionCreateComponent extends PageComponent implements OnInit {
|
export class EntityVersionCreateComponent extends PageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
branch: string;
|
branch: string;
|
||||||
@ -62,6 +63,10 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
|
|||||||
|
|
||||||
resultMessage: string;
|
resultMessage: string;
|
||||||
|
|
||||||
|
versionCreateResult$: Observable<VersionCreationResult>;
|
||||||
|
|
||||||
|
private versionCreateResultSubscription: Subscription;
|
||||||
|
|
||||||
constructor(protected store: Store<AppState>,
|
constructor(protected store: Store<AppState>,
|
||||||
private entitiesVersionControlService: EntitiesVersionControlService,
|
private entitiesVersionControlService: EntitiesVersionControlService,
|
||||||
private cd: ChangeDetectorRef,
|
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 {
|
cancel(): void {
|
||||||
if (this.onClose) {
|
if (this.onClose) {
|
||||||
this.onClose(null, null);
|
this.onClose(null, null);
|
||||||
@ -101,9 +113,18 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
|
|||||||
},
|
},
|
||||||
type: VersionCreateRequestType.SINGLE_ENTITY
|
type: VersionCreateRequestType.SINGLE_ENTITY
|
||||||
};
|
};
|
||||||
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
|
this.versionCreateResult$ = this.entitiesVersionControlService.saveEntitiesVersion(request).pipe(
|
||||||
if (!result.added && !result.modified) {
|
share()
|
||||||
this.resultMessage = this.translate.instant('version-control.nothing-to-commit');
|
);
|
||||||
|
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();
|
this.cd.detectChanges();
|
||||||
if (this.popoverComponent) {
|
if (this.popoverComponent) {
|
||||||
this.popoverComponent.updatePosition();
|
this.popoverComponent.updatePosition();
|
||||||
@ -111,8 +132,8 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
|
|||||||
} else if (this.onClose) {
|
} else if (this.onClose) {
|
||||||
this.onClose(result, request.branch);
|
this.onClose(result, request.branch);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,5 +27,8 @@
|
|||||||
text-align: start;
|
text-align: start;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
&.progress {
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -165,6 +165,8 @@ export interface VersionCreationResult {
|
|||||||
added: number;
|
added: number;
|
||||||
modified: number;
|
modified: number;
|
||||||
removed: number;
|
removed: number;
|
||||||
|
error: string;
|
||||||
|
done: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EntityTypeLoadResult {
|
export interface EntityTypeLoadResult {
|
||||||
|
|||||||
@ -3306,6 +3306,7 @@
|
|||||||
"no-versions-text": "No versions found",
|
"no-versions-text": "No versions found",
|
||||||
"copy-full-version-id": "Copy full version id",
|
"copy-full-version-id": "Copy full version id",
|
||||||
"create-version": "Create version",
|
"create-version": "Create version",
|
||||||
|
"creating-version": "Creating version... Please wait",
|
||||||
"nothing-to-commit": "No changes to commit",
|
"nothing-to-commit": "No changes to commit",
|
||||||
"restore-version": "Restore version",
|
"restore-version": "Restore version",
|
||||||
"restore-entity-from-version": "Restore entity from version '{{versionName}}'",
|
"restore-entity-from-version": "Restore entity from version '{{versionName}}'",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user