UI: Improve restore and create entity version components.

This commit is contained in:
Igor Kulikov 2022-06-01 13:10:32 +03:00
parent 654305198d
commit df5a235e53
18 changed files with 75 additions and 27 deletions

View File

@ -238,12 +238,12 @@ public class EntitiesVersionControlController extends BaseController {
} }
} }
@GetMapping("/info/{versionId}/{entityType}/{internalEntityUuid}") @GetMapping("/info/{versionId}/{entityType}/{externalEntityUuid}")
public DeferredResult<EntityDataInfo> getEntityDataInfo(@PathVariable String versionId, public DeferredResult<EntityDataInfo> getEntityDataInfo(@PathVariable String versionId,
@PathVariable EntityType entityType, @PathVariable EntityType entityType,
@PathVariable UUID internalEntityUuid) throws ThingsboardException { @PathVariable UUID externalEntityUuid) throws ThingsboardException {
try { try {
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid); EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, externalEntityUuid);
return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId)); return wrapFuture(versionControlService.getEntityDataInfo(getCurrentUser(), entityId, versionId));
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);

View File

@ -19,7 +19,7 @@ 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 } from 'rxjs';
import { import {
BranchInfo, EntityDataDiff, BranchInfo, EntityDataDiff, EntityDataInfo,
EntityVersion, EntityVersion,
VersionCreateRequest, VersionCreateRequest,
VersionCreationResult, VersionCreationResult,
@ -71,6 +71,13 @@ export class EntitiesVersionControlService {
} }
} }
public getEntityDataInfo(externalEntityId: EntityId,
versionId: string,
config?: RequestConfig): Observable<EntityDataInfo> {
return this.http.get<EntityDataInfo>(`/api/entities/vc/info/${versionId}/${externalEntityId.entityType}/${externalEntityId.id}`,
defaultHttpOptionsFromConfig(config));
}
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( return this.http.post<VersionCreationResult>('/api/entities/vc/version', request, defaultHttpOptionsFromConfig(config)).pipe(
tap(() => { tap(() => {

View File

@ -57,7 +57,7 @@
<button mat-raised-button color="primary" <button mat-raised-button color="primary"
type="button" type="button"
(click)="export()" (click)="export()"
[disabled]="(isLoading$ | async) || createVersionFormGroup.invalid || !createVersionFormGroup.dirty"> [disabled]="(isLoading$ | async) || createVersionFormGroup.invalid">
{{ 'action.create' | translate }} {{ 'action.create' | translate }}
</button> </button>
</div> </div>

View File

@ -41,6 +41,9 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
@Input() @Input()
entityId: EntityId; entityId: EntityId;
@Input()
entityName: string;
@Input() @Input()
onClose: (result: VersionCreationResult | null, branch: string | null) => void; onClose: (result: VersionCreationResult | null, branch: string | null) => void;
@ -61,7 +64,8 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni
ngOnInit(): void { ngOnInit(): void {
this.createVersionFormGroup = this.fb.group({ this.createVersionFormGroup = this.fb.group({
branch: [this.branch, [Validators.required]], branch: [this.branch, [Validators.required]],
versionName: [null, [Validators.required]], versionName: [this.translate.instant('version-control.default-create-entity-version-name',
{entityName: this.entityName}), [Validators.required]],
saveRelations: [false, []], saveRelations: [false, []],
saveAttributes: [false, []] saveAttributes: [false, []]
}); });

View File

@ -308,7 +308,7 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit,
this.popoverService.hidePopover(trigger); this.popoverService.hidePopover(trigger);
} else { } else {
const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionRestoreComponent, 'left', true, null, this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null,
{ {
branch: this.branch, branch: this.branch,
versionName: this.versionName, versionName: this.versionName,
@ -322,6 +322,7 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit,
} }
} }
}, {}, {}, {}, false); }, {}, {}, {}, false);
restoreVersionPopover.tbComponentRef.instance.popoverComponent = restoreVersionPopover;
} }
} }
} }

View File

@ -15,27 +15,28 @@
limitations under the License. limitations under the License.
--> -->
<section style="min-width: 400px;"> <section [ngStyle]="entityDataInfo ? {minWidth: '400px'} : {}">
<mat-toolbar> <mat-toolbar *ngIf="entityDataInfo">
<h2>{{ 'version-control.restore-entity-from-version' | translate: {versionName} }}</h2> <h2>{{ 'version-control.restore-entity-from-version' | translate: {versionName} }}</h2>
<span fxFlex></span> <span fxFlex></span>
</mat-toolbar> </mat-toolbar>
<mat-progress-bar color="warn" style="z-index: 10; width: 100%; margin-bottom: -4px;" mode="indeterminate" <mat-progress-bar color="warn" style="z-index: 10; width: 100%; margin-bottom: -4px;" mode="indeterminate"
*ngIf="isLoading$ | async"> *ngIf="entityDataInfo && (isLoading$ | async)">
</mat-progress-bar> </mat-progress-bar>
<form [formGroup]="restoreFormGroup" style="padding-top: 16px;"> <mat-spinner *ngIf="!entityDataInfo" mode="indeterminate" diameter="80"></mat-spinner>
<form *ngIf="entityDataInfo" [formGroup]="restoreFormGroup" style="padding-top: 16px;">
<fieldset [disabled]="isLoading$ | async"> <fieldset [disabled]="isLoading$ | async">
<div fxFlex fxLayout="column"> <div fxFlex fxLayout="column">
<mat-checkbox formControlName="loadRelations" style="margin-bottom: 16px;"> <mat-checkbox *ngIf="entityDataInfo.hasRelations" formControlName="loadRelations" style="margin-bottom: 16px;">
{{ 'version-control.load-entity-relations' | translate }} {{ 'version-control.load-entity-relations' | translate }}
</mat-checkbox> </mat-checkbox>
<mat-checkbox formControlName="loadAttributes" style="margin-bottom: 16px;"> <mat-checkbox *ngIf="entityDataInfo.hasAttributes" formControlName="loadAttributes" style="margin-bottom: 16px;">
{{ 'version-control.load-entity-attributes' | translate }} {{ 'version-control.load-entity-attributes' | translate }}
</mat-checkbox> </mat-checkbox>
</div> </div>
</fieldset> </fieldset>
</form> </form>
<div fxLayoutAlign="end center" fxLayoutGap="8px"> <div *ngIf="entityDataInfo" fxLayoutAlign="end center" fxLayoutGap="8px">
<button mat-button color="primary" <button mat-button color="primary"
type="button" type="button"
[disabled]="(isLoading$ | async)" [disabled]="(isLoading$ | async)"

View File

@ -14,15 +14,22 @@
/// limitations under the License. /// 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 { PageComponent } from '@shared/components/page.component';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
import { SingleEntityVersionLoadRequest, VersionLoadRequestType, VersionLoadResult } from '@shared/models/vc.models'; import {
EntityDataInfo,
SingleEntityVersionLoadRequest,
VersionLoadRequestType,
VersionLoadResult
} from '@shared/models/vc.models';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; 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 { TbPopoverComponent } from '@shared/components/popover.component';
import { delay } from 'rxjs/operators';
@Component({ @Component({
selector: 'tb-entity-version-restore', selector: 'tb-entity-version-restore',
@ -46,10 +53,16 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn
@Input() @Input()
onClose: (result: Array<VersionLoadResult> | null) => void; onClose: (result: Array<VersionLoadResult> | null) => void;
@Input()
popoverComponent: TbPopoverComponent;
entityDataInfo: EntityDataInfo = null;
restoreFormGroup: FormGroup; restoreFormGroup: FormGroup;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private entitiesVersionControlService: EntitiesVersionControlService, private entitiesVersionControlService: EntitiesVersionControlService,
private cd: ChangeDetectorRef,
private translate: TranslateService, private translate: TranslateService,
private fb: FormBuilder) { private fb: FormBuilder) {
super(store); super(store);
@ -57,8 +70,15 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn
ngOnInit(): void { ngOnInit(): void {
this.restoreFormGroup = this.fb.group({ this.restoreFormGroup = this.fb.group({
loadRelations: [false, []], loadRelations: [true, []],
loadAttributes: [false, []] loadAttributes: [true, []]
});
this.entitiesVersionControlService.getEntityDataInfo(this.externalEntityId, this.versionId).subscribe((data) => {
this.entityDataInfo = data;
this.cd.detectChanges();
if (this.popoverComponent) {
this.popoverComponent.updatePosition();
}
}); });
} }
@ -74,8 +94,8 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn
versionId: this.versionId, versionId: this.versionId,
externalEntityId: this.externalEntityId, externalEntityId: this.externalEntityId,
config: { config: {
loadRelations: this.restoreFormGroup.get('loadRelations').value, loadRelations: this.entityDataInfo.hasRelations ? this.restoreFormGroup.get('loadRelations').value : false,
loadAttributes: this.restoreFormGroup.get('loadAttributes').value loadAttributes: this.entityDataInfo.hasAttributes ? this.restoreFormGroup.get('loadAttributes').value : false
}, },
type: VersionLoadRequestType.SINGLE_ENTITY type: VersionLoadRequestType.SINGLE_ENTITY
}; };

View File

@ -105,6 +105,9 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
@Input() @Input()
entityId: EntityId; entityId: EntityId;
@Input()
entityName: string;
@Output() @Output()
versionRestored = new EventEmitter<void>(); versionRestored = new EventEmitter<void>();
@ -191,6 +194,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
{ {
branch: this.branch, branch: this.branch,
entityId: this.entityId, entityId: this.entityId,
entityName: this.entityName,
onClose: (result: VersionCreationResult | null, branch: string | null) => { onClose: (result: VersionCreationResult | null, branch: string | null) => {
createVersionPopover.hide(); createVersionPopover.hide();
if (result) { if (result) {
@ -289,6 +293,7 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
} }
} }
}, {}, {}, {}, false); }, {}, {}, {}, false);
restoreVersionPopover.tbComponentRef.instance.popoverComponent = restoreVersionPopover;
} }
} }

View File

@ -22,6 +22,7 @@
<tb-entity-versions-table [singleEntityMode]="singleEntityMode" <tb-entity-versions-table [singleEntityMode]="singleEntityMode"
[active]="active" [active]="active"
[entityId]="entityId" [entityId]="entityId"
[entityName]="entityName"
[externalEntityId]="externalEntityId" [externalEntityId]="externalEntityId"
(versionRestored)="versionRestored.emit()"></tb-entity-versions-table> (versionRestored)="versionRestored.emit()"></tb-entity-versions-table>
</ng-template> </ng-template>

View File

@ -47,6 +47,9 @@ export class VersionControlComponent implements OnInit, HasConfirmForm {
@Input() @Input()
entityId: EntityId; entityId: EntityId;
@Input()
entityName: string;
@Output() @Output()
versionRestored = new EventEmitter<void>(); versionRestored = new EventEmitter<void>();

View File

@ -53,5 +53,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -53,5 +53,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -23,5 +23,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -79,5 +79,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -53,5 +53,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -56,5 +56,5 @@
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab"> label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true" <tb-version-control detailsMode="true" singleEntityMode="true"
(versionRestored)="entitiesTableConfig.updateData()" (versionRestored)="entitiesTableConfig.updateData()"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control> [active]="versionControlTab.isActive" [entityId]="entity.id" [entityName]="entity.name" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab> </mat-tab>

View File

@ -184,3 +184,8 @@ export interface EntityDataDiff {
export function entityExportDataToJsonString(data: EntityExportData<any>): string { export function entityExportDataToJsonString(data: EntityExportData<any>): string {
return JSON.stringify(data, null, 4); return JSON.stringify(data, null, 4);
} }
export interface EntityDataInfo {
hasRelations: boolean;
hasAttributes: boolean;
}

View File

@ -3169,7 +3169,8 @@
"updated": "{{updated}} updated", "updated": "{{updated}} updated",
"deleted": "{{deleted}} deleted", "deleted": "{{deleted}} deleted",
"remove-other-entities-confirm-text": "Be careful! This will permanently <b>delete</b> <b>all</b> current entities<br/>not present in the version you want to restore.<br/><br/>Please type <b>remove other entities</b> to confirm.", "remove-other-entities-confirm-text": "Be careful! This will permanently <b>delete</b> <b>all</b> current entities<br/>not present in the version you want to restore.<br/><br/>Please type <b>remove other entities</b> to confirm.",
"auto-commit-to-branch": "auto-commit to <b>{{ branch }}</b> branch" "auto-commit-to-branch": "auto-commit to <b>{{ branch }}</b> branch",
"default-create-entity-version-name": "{{entityName}} update"
}, },
"widget": { "widget": {
"widget-library": "Widgets Library", "widget-library": "Widgets Library",