Browse Source

UI: Initial implementation of entity versions diff component

pull/6615/head
Igor Kulikov 4 years ago
parent
commit
e86b37b4af
  1. 6
      ui-ngx/angular.json
  2. 2
      ui-ngx/package.json
  3. 7
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  4. 35
      ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html
  5. 23
      ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.scss
  6. 92
      ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts
  7. 9
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html
  8. 23
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts
  9. 16
      ui-ngx/src/app/shared/models/ace/ace.models.ts
  10. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  11. 12
      ui-ngx/yarn.lock

6
ui-ngx/angular.json

@ -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": {

2
ui-ngx/package.json

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

7
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -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,

35
ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html

@ -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>

23
ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.scss

@ -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;
}
}

92
ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts

@ -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();
}
}
}

9
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html

@ -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"

23
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts

@ -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();

16
ui-ngx/src/app/shared/models/ace/ace.models.ts

@ -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;

4
ui-ngx/src/assets/locale/locale.constant-en_US.json

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

12
ui-ngx/yarn.lock

@ -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"

Loading…
Cancel
Save