Browse Source

UI: Entity versions table improvement. Create entity version popover.

pull/6615/head
Igor Kulikov 4 years ago
parent
commit
9d17ff1285
  1. 10
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  2. 6
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.html
  3. 60
      ui-ngx/src/app/modules/home/components/vc/entity-version-export.component.html
  4. 84
      ui-ngx/src/app/modules/home/components/vc/entity-version-export.component.ts
  5. 8
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html
  6. 2
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss
  7. 46
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts
  8. 77
      ui-ngx/src/app/modules/home/components/vc/vc-entity-export-dialog.component.html
  9. 105
      ui-ngx/src/app/modules/home/components/vc/vc-entity-export-dialog.component.ts
  10. 1
      ui-ngx/src/app/modules/home/components/vc/version-control.component.html
  11. 3
      ui-ngx/src/app/modules/home/components/vc/version-control.component.ts
  12. 16
      ui-ngx/src/app/modules/home/dialogs/home-dialogs.service.ts
  13. 5
      ui-ngx/src/app/modules/home/pages/asset/asset-tabs.component.html
  14. 6
      ui-ngx/src/app/modules/home/pages/asset/asset.component.html
  15. 10
      ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts
  16. 5
      ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html
  17. 6
      ui-ngx/src/app/modules/home/pages/customer/customer.component.html
  18. 10
      ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts
  19. 6
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html
  20. 5
      ui-ngx/src/app/modules/home/pages/dashboard/dashboard-tabs.component.html
  21. 10
      ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts
  22. 5
      ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html
  23. 10
      ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts
  24. 2
      ui-ngx/src/app/modules/home/pages/device/device-tabs.component.html
  25. 6
      ui-ngx/src/app/modules/home/pages/device/device.component.html
  26. 10
      ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts
  27. 5
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain-tabs.component.html
  28. 6
      ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html
  29. 10
      ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts
  30. 3
      ui-ngx/src/app/shared/components/popover.component.ts
  31. 4
      ui-ngx/src/app/shared/components/popover.service.ts
  32. 5
      ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.html
  33. 30
      ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.scss
  34. 57
      ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.ts
  35. 9
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

@ -153,10 +153,10 @@ import { TenantProfileQueuesComponent } from '@home/components/profile/queue/ten
import { QueueFormComponent } from '@home/components/queue/queue-form.component';
import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module';
import { WidgetSettingsComponent } from '@home/components/widget/widget-settings.component';
import { VcEntityExportDialogComponent } from '@home/components/vc/vc-entity-export-dialog.component';
import { VersionControlSettingsComponent } from '@home/components/vc/version-control-settings.component';
import { VersionControlComponent } from '@home/components/vc/version-control.component';
import { EntityVersionsTableComponent } from '@home/components/vc/entity-versions-table.component';
import { EntityVersionExportComponent } from '@home/components/vc/entity-version-export.component';
@NgModule({
declarations:
@ -281,10 +281,10 @@ import { EntityVersionsTableComponent } from '@home/components/vc/entity-version
DisplayWidgetTypesPanelComponent,
TenantProfileQueuesComponent,
QueueFormComponent,
VcEntityExportDialogComponent,
VersionControlSettingsComponent,
VersionControlComponent,
EntityVersionsTableComponent
EntityVersionsTableComponent,
EntityVersionExportComponent
],
imports: [
CommonModule,
@ -403,10 +403,10 @@ import { EntityVersionsTableComponent } from '@home/components/vc/entity-version
DisplayWidgetTypesPanelComponent,
TenantProfileQueuesComponent,
QueueFormComponent,
VcEntityExportDialogComponent,
VersionControlSettingsComponent,
VersionControlComponent,
EntityVersionsTableComponent
EntityVersionsTableComponent,
EntityVersionExportComponent
],
providers: [
WidgetComponentService,

6
ui-ngx/src/app/modules/home/components/profile/device-profile.component.html

@ -34,12 +34,6 @@
[fxShow]="!isEdit && !entity?.default">
{{'device-profile.set-default' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

60
ui-ngx/src/app/modules/home/components/vc/entity-version-export.component.html

@ -0,0 +1,60 @@
<!--
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;">
<mat-toolbar>
<h2>{{ 'version-control.create-entity-version' | translate }}</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>
<form [formGroup]="exportFormGroup" style="padding-top: 16px;">
<fieldset [disabled]="isLoading$ | async">
<div fxFlex fxLayout="column">
<tb-branch-autocomplete
required
formControlName="branch">
</tb-branch-autocomplete>
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>version-control.version-name</mat-label>
<input required matInput formControlName="versionName">
<mat-error *ngIf="exportFormGroup.get('versionName').hasError('required')">
{{ 'version-control.version-name-required' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox formControlName="saveRelations" style="margin-bottom: 16px;">
{{ 'version-control.export-entity-relations' | translate }}
</mat-checkbox>
</div>
</fieldset>
</form>
<div fxLayoutAlign="end center" fxLayoutGap="8px">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
<button mat-raised-button color="primary"
type="button"
(click)="export()"
[disabled]="(isLoading$ | async) || exportFormGroup.invalid || !exportFormGroup.dirty">
{{ 'action.create' | translate }}
</button>
</div>
</section>

84
ui-ngx/src/app/modules/home/components/vc/entity-version-export.component.ts

@ -0,0 +1,84 @@
///
/// 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, Input, OnInit } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import {
SingleEntityVersionCreateRequest,
VersionCreateRequestType,
VersionCreationResult
} from '@shared/models/vc.models';
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';
@Component({
selector: 'tb-entity-version-export',
templateUrl: './entity-version-export.component.html',
styleUrls: []
})
export class EntityVersionExportComponent extends PageComponent implements OnInit {
@Input()
branch: string;
@Input()
entityId: EntityId;
@Input()
onClose: (result: VersionCreationResult | null, branch: string | null) => void;
exportFormGroup: FormGroup;
constructor(protected store: Store<AppState>,
private entitiesVersionControlService: EntitiesVersionControlService,
private fb: FormBuilder) {
super(store);
}
ngOnInit(): void {
this.exportFormGroup = this.fb.group({
branch: [this.branch, [Validators.required]],
versionName: [null, [Validators.required]],
saveRelations: [false, []]
});
}
cancel(): void {
if (this.onClose) {
this.onClose(null, null);
}
}
export(): void {
const request: SingleEntityVersionCreateRequest = {
entityId: this.entityId,
branch: this.exportFormGroup.get('branch').value,
versionName: this.exportFormGroup.get('versionName').value,
config: {
saveRelations: this.exportFormGroup.get('saveRelations').value
},
type: VersionCreateRequestType.SINGLE_ENTITY
};
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
if (this.onClose) {
this.onClose(result, request.branch);
}
});
}
}

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

@ -31,10 +31,12 @@
</tb-branch-autocomplete>
</div>
<span fxFlex></span>
<button *ngIf="singleEntityMode" mat-raised-button color="primary"
<button *ngIf="singleEntityMode" mat-stroked-button color="primary"
#exportButton
[disabled]="(isLoading$ | async)"
(click)="vcExport($event)">
{{'version-control.export-to-git' | translate }}
(click)="toggleVcExport($event, exportButton)">
<mat-icon>update</mat-icon>
{{'version-control.create-version' | translate }}
</button>
</div>
</mat-toolbar>

2
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.scss

@ -78,7 +78,7 @@
tb-branch-autocomplete {
mat-form-field {
font-size: 16px;
width: 200px;
width: 250px;
.mat-form-field-wrapper {
padding-bottom: 0;

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

@ -21,8 +21,8 @@ import {
ElementRef,
Input,
OnDestroy,
OnInit,
ViewChild
OnInit, Renderer2,
ViewChild, ViewContainerRef
} from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
@ -33,7 +33,7 @@ import { BehaviorSubject, merge, Observable, of, ReplaySubject } from 'rxjs';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import { PageLink } from '@shared/models/page/page-link';
import { catchError, map, tap } from 'rxjs/operators';
import { EntityVersion } from '@shared/models/vc.models';
import { EntityVersion, VersionCreationResult } from '@shared/models/vc.models';
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
@ -42,6 +42,10 @@ import { hidePageSizePixelValue } from '@shared/models/constants';
import { Direction, SortOrder } from '@shared/models/page/sort-order';
import { BranchAutocompleteComponent } from '@shared/components/vc/branch-autocomplete.component';
import { isNotEmptyStr } from '@core/utils';
import { TbPopoverService } from '@shared/components/popover.service';
import { EntityVersionExportComponent } from '@home/components/vc/entity-version-export.component';
import { MatButton } from '@angular/material/button';
import { TbPopoverComponent } from '@shared/components/popover.component';
@Component({
selector: 'tb-entity-versions-table',
@ -68,6 +72,8 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
viewsInited = false;
vcExportPopover: TbPopoverComponent;
private componentResize$: ResizeObserver;
@Input()
@ -94,12 +100,18 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
}
}
@Input()
entityId: EntityId;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(protected store: Store<AppState>,
private entitiesVersionControlService: EntitiesVersionControlService,
private popoverService: TbPopoverService,
private renderer: Renderer2,
private cd: ChangeDetectorRef,
private viewContainerRef: ViewContainerRef,
private elementRef: ElementRef) {
super(store);
this.dirtyValue = !this.activeValue;
@ -148,10 +160,36 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
}
}
vcExport($event: Event) {
toggleVcExport($event: Event, exportButton: MatButton) {
if ($event) {
$event.stopPropagation();
}
const trigger = exportButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
this.vcExportPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionExportComponent, 'bottom', true, null,
{
branch: this.branch,
entityId: this.entityId,
onClose: (result: VersionCreationResult | null, branch: string | null) => {
this.vcExportPopover.hide();
if (result) {
if (this.branch !== branch) {
this.branchChanged(branch);
} else {
this.updateData();
}
}
}
}, {}, {}, {}, false);
this.vcExportPopover.tbVisibleChange.subscribe((visible: boolean) => {
if (!visible) {
this.vcExportPopover = null;
}
});
}
}
versionIdContent(entityVersion: EntityVersion): string {

77
ui-ngx/src/app/modules/home/components/vc/vc-entity-export-dialog.component.html

@ -1,77 +0,0 @@
<!--
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;">
<mat-toolbar color="primary">
<h2>{{ (createResult ? 'version-control.entity-version-exported' : 'version-control.export-entity-version') | translate }}</h2>
<span fxFlex></span>
<button mat-button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div mat-dialog-content>
<form *ngIf="!createResult" [formGroup]="exportFormGroup">
<fieldset [disabled]="isLoading$ | async">
<div fxFlex fxLayout="column">
<tb-branch-autocomplete
required
formControlName="branch">
</tb-branch-autocomplete>
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>version-control.version-name</mat-label>
<input required matInput formControlName="versionName">
<mat-error *ngIf="exportFormGroup.get('versionName').hasError('required')">
{{ 'version-control.version-name-required' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox formControlName="saveRelations" style="margin-bottom: 16px;">
{{ 'version-control.export-entity-relations' | translate }}
</mat-checkbox>
</div>
</fieldset>
</form>
<div *ngIf="createResult" fxFlex fxLayout="column" fxLayoutAlign="center">
<div [innerHTML]="createResultMessage"></div>
</div>
</div>
<div *ngIf="!createResult" mat-dialog-actions fxLayoutAlign="end center">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.cancel' | translate }}
</button>
<button mat-raised-button color="primary"
type="button"
(click)="export()"
[disabled]="(isLoading$ | async) || exportFormGroup.invalid || !exportFormGroup.dirty">
{{ 'action.export' | translate }}
</button>
</div>
<div *ngIf="createResult" mat-dialog-actions fxLayoutAlign="end center">
<button mat-button color="primary"
type="button"
[disabled]="(isLoading$ | async)"
(click)="cancel()" cdkFocusInitial>
{{ 'action.close' | translate }}
</button>
</div>
</section>

105
ui-ngx/src/app/modules/home/components/vc/vc-entity-export-dialog.component.ts

@ -1,105 +0,0 @@
///
/// 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, Inject, OnInit, SkipSelf } from '@angular/core';
import { ErrorStateMatcher } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { DialogComponent } from '@app/shared/components/dialog.component';
import { EntityId } from '@shared/models/id/entity-id';
import {
SingleEntityVersionCreateRequest,
VersionCreateRequestType,
VersionCreationResult
} from '@shared/models/vc.models';
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
export interface VcEntityExportDialogData {
entityId: EntityId;
}
@Component({
selector: 'tb-vc-entity-export-dialog',
templateUrl: './vc-entity-export-dialog.component.html',
providers: [{provide: ErrorStateMatcher, useExisting: VcEntityExportDialogComponent}],
styleUrls: []
})
export class VcEntityExportDialogComponent extends DialogComponent<VcEntityExportDialogComponent>
implements OnInit, ErrorStateMatcher {
exportFormGroup: FormGroup;
submitted = false;
createResult: VersionCreationResult;
createResultMessage: SafeHtml;
constructor(protected store: Store<AppState>,
protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: VcEntityExportDialogData,
@SkipSelf() private errorStateMatcher: ErrorStateMatcher,
public dialogRef: MatDialogRef<VcEntityExportDialogComponent>,
private entitiesVersionControlService: EntitiesVersionControlService,
private translate: TranslateService,
private domSanitizer: DomSanitizer,
private fb: FormBuilder) {
super(store, router, dialogRef);
this.exportFormGroup = this.fb.group({
branch: [null, [Validators.required]],
versionName: [null, [Validators.required]],
saveRelations: [false, []]
});
}
ngOnInit(): void {
}
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const originalErrorState = this.errorStateMatcher.isErrorState(control, form);
const customErrorState = !!(control && control.invalid && this.submitted);
return originalErrorState || customErrorState;
}
cancel(): void {
this.dialogRef.close();
}
export(): void {
this.submitted = true;
const request: SingleEntityVersionCreateRequest = {
entityId: this.data.entityId,
branch: this.exportFormGroup.get('branch').value,
versionName: this.exportFormGroup.get('versionName').value,
config: {
saveRelations: this.exportFormGroup.get('saveRelations').value
},
type: VersionCreateRequestType.SINGLE_ENTITY
};
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
this.createResult = result;
const message = this.translate.instant('version-control.export-entity-version-result-message',
{name: result.version.name, commitId: result.version.id});
this.createResultMessage = this.domSanitizer.bypassSecurityTrustHtml(message);
});
}
}

1
ui-ngx/src/app/modules/home/components/vc/version-control.component.html

@ -21,5 +21,6 @@
<ng-template #versionsTable>
<tb-entity-versions-table [singleEntityMode]="singleEntityMode"
[active]="active"
[entityId]="entityId"
[externalEntityId]="externalEntityId"></tb-entity-versions-table>
</ng-template>

3
ui-ngx/src/app/modules/home/components/vc/version-control.component.ts

@ -44,6 +44,9 @@ export class VersionControlComponent implements OnInit, HasConfirmForm {
@Input()
externalEntityId: EntityId;
@Input()
entityId: EntityId;
hasVersionControl$ = this.store.pipe(select(selectHasVersionControl));
constructor(private store: Store<AppState>) {

16
ui-ngx/src/app/modules/home/dialogs/home-dialogs.service.ts

@ -22,11 +22,6 @@ import {
ImportDialogCsvComponent,
ImportDialogCsvData
} from '@home/components/import-export/import-dialog-csv.component';
import { EntityId } from '@shared/models/id/entity-id';
import {
VcEntityExportDialogComponent,
VcEntityExportDialogData
} from '@home/components/vc/vc-entity-export-dialog.component';
@Injectable()
export class HomeDialogsService {
@ -46,17 +41,6 @@ export class HomeDialogsService {
}
}
public exportVcEntity(entityId: EntityId): Observable<void> {
return this.dialog.open<VcEntityExportDialogComponent, VcEntityExportDialogData>(VcEntityExportDialogComponent,
{
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
entityId
}
}).afterClosed();
}
private openImportDialogCSV(entityType: EntityType, importTitle: string, importFileLabel: string): Observable<boolean> {
return this.dialog.open<ImportDialogCsvComponent, ImportDialogCsvData,
any>(ImportDialogCsvComponent, {

5
ui-ngx/src/app/modules/home/pages/asset/asset-tabs.component.html

@ -49,3 +49,8 @@
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

6
ui-ngx/src/app/modules/home/pages/asset/asset.component.html

@ -46,12 +46,6 @@
[fxShow]="!isEdit && assetScope === 'edge'">
{{ 'edge.unassign-from-edge' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit && (assetScope === 'customer' || assetScope === 'tenant')">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

10
ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts

@ -468,13 +468,6 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
);
}
vcExport($event: Event, asset: Asset) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(asset.id);
}
onAssetAction(action: EntityAction<AssetInfo>, config: EntityTableConfig<AssetInfo>): boolean {
switch (action.action) {
case 'open':
@ -492,9 +485,6 @@ export class AssetsTableConfigResolver implements Resolve<EntityTableConfig<Asse
case 'unassignFromEdge':
this.unassignFromEdge(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

5
ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html

@ -49,3 +49,8 @@
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.CUSTOMER" [customerId]="entity.id"></tb-audit-log-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

6
ui-ngx/src/app/modules/home/pages/customer/customer.component.html

@ -53,12 +53,6 @@
*ngIf="edgesSupportEnabled()">
{{'customer.manage-edges' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit && !isPublic">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

10
ui-ngx/src/app/modules/home/pages/customer/customers-table-config.resolver.ts

@ -182,13 +182,6 @@ export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<C
this.router.navigateByUrl(`customers/${customer.id.id}/edgeInstances`);
}
vcExport($event: Event, customer: Customer) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(customer.id);
}
onCustomerAction(action: EntityAction<Customer>, config: EntityTableConfig<Customer>): boolean {
switch (action.action) {
case 'open':
@ -209,9 +202,6 @@ export class CustomersTableConfigResolver implements Resolve<EntityTableConfig<C
case 'manageEdges':
this.manageCustomerEdges(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

6
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html

@ -59,12 +59,6 @@
[fxShow]="!isEdit && dashboardScope === 'edge'">
{{ 'edge.unassign-from-edge' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit && dashboardScope === 'tenant'">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

5
ui-ngx/src/app/modules/home/pages/dashboard/dashboard-tabs.component.html

@ -19,3 +19,8 @@
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id" detailsMode="true"></tb-audit-log-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

10
ui-ngx/src/app/modules/home/pages/dashboard/dashboards-table-config.resolver.ts

@ -539,13 +539,6 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
);
}
vcExport($event: Event, dashboard: DashboardInfo) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(dashboard.id);
}
onDashboardAction(action: EntityAction<DashboardInfo>): boolean {
switch (action.action) {
case 'open':
@ -569,9 +562,6 @@ export class DashboardsTableConfigResolver implements Resolve<EntityTableConfig<
case 'unassignFromEdge':
this.unassignFromEdge(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

5
ui-ngx/src/app/modules/home/pages/device-profile/device-profile-tabs.component.html

@ -75,3 +75,8 @@
label="{{ 'audit-log.audit-logs' | translate }}">
<tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

10
ui-ngx/src/app/modules/home/pages/device-profile/device-profiles-table-config.resolver.ts

@ -206,13 +206,6 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
this.importExport.exportDeviceProfile(deviceProfile.id.id);
}
vcExport($event: Event, deviceProfile: DeviceProfile) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(deviceProfile.id);
}
onDeviceProfileAction(action: EntityAction<DeviceProfile>): boolean {
switch (action.action) {
case 'open':
@ -224,9 +217,6 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
case 'export':
this.exportDeviceProfile(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

2
ui-ngx/src/app/modules/home/pages/device/device-tabs.component.html

@ -52,5 +52,5 @@
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

6
ui-ngx/src/app/modules/home/pages/device/device.component.html

@ -52,12 +52,6 @@
[fxShow]="!isEdit && deviceScope === 'edge'">
{{ 'edge.unassign-from-edge' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit && (deviceScope === 'customer' || deviceScope === 'tenant')">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary" fxFlex.xs
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

10
ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts

@ -547,13 +547,6 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
});
}
vcExport($event: Event, device: Device) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(device.id);
}
onDeviceAction(action: EntityAction<DeviceInfo>, config: EntityTableConfig<DeviceInfo>): boolean {
switch (action.action) {
case 'open':
@ -574,9 +567,6 @@ export class DevicesTableConfigResolver implements Resolve<EntityTableConfig<Dev
case 'manageCredentials':
this.manageCredentials(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

5
ui-ngx/src/app/modules/home/pages/rulechain/rulechain-tabs.component.html

@ -52,3 +52,8 @@
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table detailsMode="true" [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.ENTITY" [entityId]="entity.id"></tb-audit-log-table>
</mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN"
label="{{ 'version-control.version-control' | translate }}" #versionControlTab="matTab">
<tb-version-control detailsMode="true" singleEntityMode="true"
[active]="versionControlTab.isActive" [entityId]="entity.id" [externalEntityId]="entity.externalId || entity.id"></tb-version-control>
</mat-tab>

6
ui-ngx/src/app/modules/home/pages/rulechain/rulechain.component.html

@ -58,12 +58,6 @@
[fxShow]="!isEdit && !isEdgeRootRuleChain() && ruleChainScope === 'edge'">
{{'edge.unassign-from-edge' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'vcExport')"
[fxShow]="!isEdit">
{{'version-control.export-to-git' | translate }}
</button>
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'delete')"

10
ui-ngx/src/app/modules/home/pages/rulechain/rulechains-table-config.resolver.ts

@ -360,13 +360,6 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
);
}
vcExport($event: Event, ruleChain: RuleChain) {
if ($event) {
$event.stopPropagation();
}
this.homeDialogs.exportVcEntity(ruleChain.id);
}
onRuleChainAction(action: EntityAction<RuleChain>): boolean {
switch (action.action) {
case 'open':
@ -390,9 +383,6 @@ export class RuleChainsTableConfigResolver implements Resolve<EntityTableConfig<
case 'unsetAutoAssignToEdge':
this.unsetAutoAssignToEdgeRuleChain(action.event, action.entity);
return true;
case 'vcExport':
this.vcExport(action.event, action.entity);
return true;
}
return false;
}

3
ui-ngx/src/app/shared/components/popover.component.ts

@ -314,7 +314,7 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit {
<span class="tb-popover-arrow-content"></span>
</div>
<div class="tb-popover-inner" [ngStyle]="tbPopoverInnerStyle" role="tooltip">
<div class="tb-popover-close-button" (click)="closeButtonClick($event)">×</div>
<div *ngIf="tbShowCloseButton" class="tb-popover-close-button" (click)="closeButtonClick($event)">×</div>
<div style="width: 100%; height: 100%;">
<div class="tb-popover-inner-content">
<ng-container *ngIf="tbContent">
@ -354,6 +354,7 @@ export class TbPopoverComponent implements OnDestroy, OnInit {
tbMouseEnterDelay?: number;
tbMouseLeaveDelay?: number;
tbHideOnClickOutside = true;
tbShowCloseButton = true;
tbAnimationState = 'active';

4
ui-ngx/src/app/shared/components/popover.service.ts

@ -55,7 +55,8 @@ export class TbPopoverService {
displayPopover<T>(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef,
componentType: Type<T>, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true,
injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any): TbPopoverComponent {
injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any,
showCloseButton = true): TbPopoverComponent {
const componentRef = hostView.createComponent(this.componentFactory);
const component = componentRef.instance;
this.popoverWithTriggers.push({
@ -76,6 +77,7 @@ export class TbPopoverService {
component.tbPopoverInnerStyle = popoverStyle;
component.tbComponentStyle = style;
component.tbHideOnClickOutside = hideOnClickOutside;
component.tbShowCloseButton = showCloseButton;
component.tbVisibleChange.subscribe((visible: boolean) => {
if (!visible) {
component.tbAnimationDone.subscribe(() => {

5
ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.html

@ -36,8 +36,11 @@
(closed)="onPanelClosed()"
#branchAutocomplete="matAutocomplete"
[displayWith]="displayBranchFn">
<mat-option *ngFor="let branch of filteredBranches | async" [value]="branch">
<mat-option *ngFor="let branch of filteredBranches | async" [value]="branch" class="branch-option">
<mat-icon class="tb-mat-18" *ngIf="selectionMode && branch.name === modelValue">check</mat-icon>
<span class="check-placeholder" *ngIf="selectionMode && branch.name !== modelValue"></span>
<span [innerHTML]="branch.name | highlight:searchText"></span>
<small *ngIf="branch.default" class="default-branch">{{ 'version-control.default' | translate }}</small>
</mat-option>
</mat-autocomplete>
<mat-error *ngIf="branchFormGroup.get('branch').hasError('required')">

30
ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.scss

@ -0,0 +1,30 @@
/**
* 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.
*/
.mat-option.branch-option {
.mat-icon, .check-placeholder {
margin-right: 8px;
}
.check-placeholder {
width: 18px;
display: inline-block;
}
.mat-option-text {
width: 100%;
.default-branch {
float: right;
}
}
}

57
ui-ngx/src/app/shared/components/vc/branch-autocomplete.component.ts

@ -14,9 +14,19 @@
/// limitations under the License.
///
import { AfterViewInit, Component, ElementRef, forwardRef, Input, NgZone, OnInit, ViewChild } from '@angular/core';
import {
AfterViewInit,
Component,
ElementRef,
forwardRef,
Input,
NgZone,
OnInit,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
@ -29,12 +39,13 @@ import { MatAutocomplete, MatAutocompleteTrigger } from '@angular/material/autoc
@Component({
selector: 'tb-branch-autocomplete',
templateUrl: './branch-autocomplete.component.html',
styleUrls: [],
styleUrls: ['./branch-autocomplete.component.scss'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => BranchAutocompleteComponent),
multi: true
}]
}],
encapsulation: ViewEncapsulation.None
})
export class BranchAutocompleteComponent implements ControlValueAccessor, OnInit, AfterViewInit {
@ -216,30 +227,22 @@ export class BranchAutocompleteComponent implements ControlValueAccessor, OnInit
selectAvailableValue() {
if (this.selectionMode) {
const branch = this.branchFormGroup.get('branch').value;
let branchInfo: Observable<BranchInfo> = null;
if (isNotEmptyStr(branch)) {
branchInfo = this.getBranches().pipe(
map(branches => {
let foundBranch = branches.find(b => b.name === branch);
if (!foundBranch && isNotEmptyStr(this.modelValue)) {
foundBranch = branches.find(b => b.name === this.modelValue);
}
return foundBranch;
})
);
} else if (!branch) {
branchInfo = of(null);
}
if (branchInfo) {
branchInfo.subscribe((val) => {
if (!val && this.defaultBranch) {
val = this.defaultBranch;
this.getBranches().pipe(
map(branches => {
let foundBranch = branches.find(b => b.name === branch);
if (!foundBranch && isNotEmptyStr(this.modelValue)) {
foundBranch = branches.find(b => b.name === this.modelValue);
}
this.zone.run(() => {
this.branchFormGroup.get('branch').patchValue(val, {emitEvent: true});
}, 0);
});
}
return foundBranch;
})
).subscribe((val) => {
if (!val && this.defaultBranch) {
val = this.defaultBranch;
}
this.zone.run(() => {
this.branchFormGroup.get('branch').patchValue(val, {emitEvent: true});
}, 0);
});
}
}

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

@ -3112,22 +3112,21 @@
"version-control": "Version control",
"management": "Version control management",
"branch": "Branch",
"default": "Default",
"select-branch": "Select branch",
"branch-required": "Branch is required",
"export-entity-version": "Export entity version",
"entity-version-exported": "Entity version successfully exported",
"create-entity-version": "Create entity version",
"version-name": "Version name",
"version-name-required": "Version name is required",
"export-entity-relations": "Export entity relations",
"export-entity-version-result-message": "Entity exported with version '{{name}}' and commit id '{{commitId}}'.",
"export-to-git": "Export to Git",
"entity-versions": "Entity versions",
"versions": "Versions",
"created-time": "Created time",
"version-id": "Version ID",
"no-entity-versions-text": "No entity 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"
},
"widget": {
"widget-library": "Widgets Library",

Loading…
Cancel
Save