UI: Initial implementation of entity versions diff component

This commit is contained in:
Igor Kulikov 2022-05-27 13:14:18 +03:00
parent c46b5b6448
commit e86b37b4af
11 changed files with 223 additions and 6 deletions

View File

@ -79,7 +79,8 @@
"node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css",
"node_modules/@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css",
"node_modules/prismjs/themes/prism.css",
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css"
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
"node_modules/ace-diff/dist/ace-diff.min.css"
],
"stylePreprocessorOptions": {
"includePaths": [
@ -130,7 +131,8 @@
"jstree",
"qrcode",
"wcwidth",
"leaflet-polylinedecorator"
"leaflet-polylinedecorator",
"ace-diff"
]
},
"configurations": {

View File

@ -41,6 +41,7 @@
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"ace-builds": "^1.4.13",
"ace-diff": "^3.0.3",
"angular-gridster2": "~12.1.1",
"angular2-hotkeys": "^2.4.0",
"canvas-gauges": "^2.1.7",
@ -105,6 +106,7 @@
"@angular/compiler-cli": "^12.2.13",
"@angular/language-service": "^12.2.13",
"@ngtools/webpack": "~12.2.13",
"@types/ace-diff": "^2.1.1",
"@types/canvas-gauges": "^2.1.4",
"@types/flot": "^0.0.32",
"@types/jasmine": "~3.10.2",

View File

@ -158,6 +158,7 @@ import { VersionControlComponent } from '@home/components/vc/version-control.com
import { EntityVersionsTableComponent } from '@home/components/vc/entity-versions-table.component';
import { EntityVersionExportComponent } from '@home/components/vc/entity-version-export.component';
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
@NgModule({
declarations:
@ -286,7 +287,8 @@ import { EntityVersionRestoreComponent } from '@home/components/vc/entity-versio
VersionControlComponent,
EntityVersionsTableComponent,
EntityVersionExportComponent,
EntityVersionRestoreComponent
EntityVersionRestoreComponent,
EntityVersionDiffComponent
],
imports: [
CommonModule,
@ -409,7 +411,8 @@ import { EntityVersionRestoreComponent } from '@home/components/vc/entity-versio
VersionControlComponent,
EntityVersionsTableComponent,
EntityVersionExportComponent,
EntityVersionRestoreComponent
EntityVersionRestoreComponent,
EntityVersionDiffComponent
],
providers: [
WidgetComponentService,

View File

@ -0,0 +1,35 @@
<!--
Copyright © 2016-2022 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<section style="min-width: 400px; width: 800px; position: relative;">
<mat-toolbar>
<h2>{{ 'version-control.diff-entity-with-version' | translate: {versionName} }}</h2>
<span fxFlex></span>
</mat-toolbar>
<mat-progress-bar color="warn" style="z-index: 10; width: 100%; margin-bottom: -4px;" mode="indeterminate"
*ngIf="isLoading$ | async">
</mat-progress-bar>
<div class="diff-viewer" #diffViewer style="height: 350px;"></div>
<div fxLayoutAlign="end center" fxLayoutGap="8px">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="close()" cdkFocusInitial>
{{ 'action.close' | translate }}
</button>
</div>
</section>

View File

@ -0,0 +1,23 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.diff-viewer {
position: relative;
border: 1px solid #c0c0c0;
margin-top: 16px;
margin-bottom: 16px;
}
}

View File

@ -0,0 +1,92 @@
///
/// Copyright © 2016-2022 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { FormBuilder } from '@angular/forms';
import { Store } from '@ngrx/store';
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 { getAceDiff } from '@shared/models/ace/ace.models';
@Component({
selector: 'tb-entity-version-diff',
templateUrl: './entity-version-diff.component.html',
styleUrls: ['./entity-version-diff.component.scss']
})
export class EntityVersionDiffComponent extends PageComponent implements OnInit, OnDestroy {
@ViewChild('diffViewer', {static: true})
diffViewerElmRef: ElementRef<HTMLElement>;
@Input()
branch: string;
@Input()
versionName: string;
@Input()
versionId: string;
@Input()
externalEntityId: EntityId;
@Input()
onClose: () => void;
differ: AceDiff;
constructor(protected store: Store<AppState>,
private entitiesVersionControlService: EntitiesVersionControlService,
private translate: TranslateService,
private fb: FormBuilder) {
super(store);
}
ngOnInit(): void {
getAceDiff().subscribe((aceDiff) => {
this.differ = new aceDiff.default(
{
element: this.diffViewerElmRef.nativeElement,
left: {
copyLinkEnabled: false,
editable: false,
content: 'Left content!'
},
right: {
copyLinkEnabled: false,
editable: false,
content: 'Right content!'
}
} as AceDiff.AceDiffConstructorOpts
);
});
}
ngOnDestroy(): void {
if (this.differ) {
this.differ.destroy();
}
}
close(): void {
if (this.onClose) {
this.onClose();
}
}
}

View File

@ -100,10 +100,17 @@
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef style="min-width: 40px; max-width: 40px; width: 40px">
<mat-header-cell *matHeaderCellDef style="min-width: 80px; max-width: 80px; width: 80px">
</mat-header-cell>
<mat-cell *matCellDef="let entityVersion">
<div fxFlex fxLayout="row" fxLayoutAlign="end">
<button *ngIf="singleEntityMode" mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'version-control.show-version-diff' | translate }}"
matTooltipPosition="above"
#diffVersionButton
(click)="toggleShowVersionDiff($event, diffVersionButton, entityVersion)">
<mat-icon>difference</mat-icon>
</button>
<button *ngIf="singleEntityMode" mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'version-control.restore-version' | translate }}"
matTooltipPosition="above"

View File

@ -47,6 +47,7 @@ import { EntityVersionExportComponent } from '@home/components/vc/entity-version
import { MatButton } from '@angular/material/button';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
@Component({
selector: 'tb-entity-versions-table',
@ -209,6 +210,28 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
}
}
toggleShowVersionDiff($event: Event, diffVersionButton: MatButton, entityVersion: EntityVersion) {
if ($event) {
$event.stopPropagation();
}
const trigger = diffVersionButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
const diffVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionDiffComponent, 'left', true, null,
{
branch: this.branch,
versionName: entityVersion.name,
versionId: entityVersion.id,
externalEntityId: this.externalEntityIdValue,
onClose: () => {
diffVersionPopover.hide();
}
}, {}, {}, {}, false);
}
}
toggleRestoreEntityVersion($event: Event, restoreVersionButton: MatButton, entityVersion: EntityVersion) {
if ($event) {
$event.stopPropagation();

View File

@ -21,6 +21,7 @@ import { map, mergeMap, tap } from 'rxjs/operators';
let aceDependenciesLoaded = false;
let aceModule: any;
let aceDiffModule: any;
function loadAceDependencies(): Observable<any> {
if (aceDependenciesLoaded) {
@ -74,6 +75,21 @@ export function getAce(): Observable<any> {
}
}
export function getAceDiff(): Observable<any> {
if (aceDiffModule) {
return of(aceDiffModule);
} else {
return getAce().pipe(
mergeMap((ace) => {
return from(import('ace-diff'));
}),
tap((module) => {
aceDiffModule = module;
})
);
}
}
export class Range implements Ace.Range {
public start: Ace.Point;

View File

@ -3131,7 +3131,9 @@
"nothing-to-commit": "No changes to commit",
"restore-version": "Restore version",
"restore-entity-from-version": "Restore entity from version '{{versionName}}'",
"load-entity-relations": "Load entity relations"
"load-entity-relations": "Load entity relations",
"show-version-diff": "Show version diff",
"diff-entity-with-version": "Diff with entity version '{{versionName}}'"
},
"widget": {
"widget-library": "Widgets Library",

View File

@ -1751,6 +1751,11 @@
"@turf/helpers" "^6.5.0"
"@turf/meta" "^6.5.0"
"@types/ace-diff@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@types/ace-diff/-/ace-diff-2.1.1.tgz#1c08919aae8f9c429fcb139dc564c89dd093cbee"
integrity sha512-O27fCo2Y0njNslOFSewyRhTyXfLhVhleEU5aTI6ZqFTKENJ8L/LA+Y+ZfcHsHTtwrTWjBXqORmqEHH6Qytqw1w==
"@types/canvas-gauges@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@types/canvas-gauges/-/canvas-gauges-2.1.4.tgz#063881264597d098e78cf5ad921e8ed20ae2ad16"
@ -2190,6 +2195,13 @@ ace-builds@^1.4.13:
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.4.13.tgz#186f42d3849ebcc6a48b93088a058489897514c1"
integrity sha512-SOLzdaQkY6ecPKYRDDg+MY1WoGgXA34cIvYJNNoBMGGUswHmlauU2Hy0UL96vW0Fs/LgFbMUjD+6vqzWTldIYQ==
ace-diff@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/ace-diff/-/ace-diff-3.0.3.tgz#84f685ff3d0b1910539fc39259ac73d8b6581e28"
integrity sha512-CJaV9Oi6BWLWGL2Kj//h5BNXlRCRu1GYHPOT7o+ZSAuJv9PaL9FWr/cCf16IuSVDo7oj6VriO+qgoHR8G9McLA==
dependencies:
diff-match-patch "^1.0.5"
acorn-import-assertions@^1.7.6:
version "1.8.0"
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"