38 changed files with 948 additions and 87 deletions
@ -0,0 +1,81 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<div class="mat-padding tb-entity-table tb-absolute-fill"> |
|||
<div fxFlex fxLayout="column" class="mat-elevation-z1 tb-entity-table-content"> |
|||
<mat-toolbar class="mat-table-toolbar"> |
|||
<div class="mat-toolbar-tools"> |
|||
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs="center start" class="title-container"> |
|||
<span class="tb-entity-table-title">{{(singleEntityMode ? 'version-control.entity-versions' : 'version-control.versions') | translate}}</span> |
|||
<tb-branch-autocomplete |
|||
#branchAutocompleteComponent |
|||
[selectionMode]="true" |
|||
[selectDefaultBranch]="false" |
|||
[disabled]="isLoading$ | async" |
|||
[ngModel]="branch" |
|||
(ngModelChange)="branchChanged($event)"> |
|||
</tb-branch-autocomplete> |
|||
</div> |
|||
<span fxFlex></span> |
|||
<button *ngIf="singleEntityMode" mat-raised-button color="primary" |
|||
[disabled]="(isLoading$ | async)" |
|||
(click)="vcExport($event)"> |
|||
{{'version-control.export-to-git' | translate }} |
|||
</button> |
|||
</div> |
|||
</mat-toolbar> |
|||
<div fxFlex class="table-container"> |
|||
<table mat-table [dataSource]="dataSource" |
|||
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear> |
|||
<ng-container matColumnDef="timestamp"> |
|||
<mat-header-cell *matHeaderCellDef mat-sort-header style="min-width: 150px; max-width: 150px; width: 150px;"> {{ 'version-control.created-time' | translate }} </mat-header-cell> |
|||
<mat-cell *matCellDef="let entityVersion"> |
|||
{{ entityVersion.timestamp | date:'yyyy-MM-dd HH:mm:ss' }} |
|||
</mat-cell> |
|||
</ng-container> |
|||
<ng-container matColumnDef="id"> |
|||
<mat-header-cell *matHeaderCellDef style="width: 40%"> {{ 'version-control.version-id' | translate }} </mat-header-cell> |
|||
<mat-cell *matCellDef="let entityVersion"> |
|||
{{ entityVersion.id }} |
|||
</mat-cell> |
|||
</ng-container> |
|||
<ng-container matColumnDef="name"> |
|||
<mat-header-cell *matHeaderCellDef style="width: 60%"> {{ 'version-control.version-name' | translate }} </mat-header-cell> |
|||
<mat-cell *matCellDef="let entityVersion"> |
|||
{{ entityVersion.name }} |
|||
</mat-cell> |
|||
</ng-container> |
|||
<mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row> |
|||
<mat-row *matRowDef="let entityVersion; columns: displayedColumns;"></mat-row> |
|||
</table> |
|||
<span [fxShow]="dataSource.isEmpty() | async" |
|||
fxLayoutAlign="center center" |
|||
class="no-data-found" translate>{{ |
|||
singleEntityMode |
|||
? 'version-control.no-entity-versions-text' |
|||
: 'version-control.no-versions-text' |
|||
}}</span> |
|||
</div> |
|||
<mat-divider></mat-divider> |
|||
<mat-paginator [length]="dataSource.total() | async" |
|||
[pageIndex]="pageLink.page" |
|||
[pageSize]="pageLink.pageSize" |
|||
[pageSizeOptions]="[10, 20, 30]" |
|||
[hidePageSize]="hidePageSize" |
|||
showFirstLastButtons></mat-paginator> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,100 @@ |
|||
/** |
|||
* 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 '../../../../../scss/constants'; |
|||
|
|||
:host { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: block; |
|||
.tb-entity-table { |
|||
.tb-entity-table-content { |
|||
width: 100%; |
|||
height: 100%; |
|||
background: #fff; |
|||
|
|||
.mat-toolbar-tools{ |
|||
min-height: auto; |
|||
} |
|||
|
|||
.title-container{ |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.tb-entity-table-title { |
|||
padding-right: 20px; |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.table-container { |
|||
overflow: auto; |
|||
} |
|||
|
|||
.tb-entity-table-info{ |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
|
|||
.button-widget-action{ |
|||
margin-left: auto; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@media #{$mat-xs} { |
|||
.mat-toolbar { |
|||
height: auto; |
|||
min-height: 100px; |
|||
|
|||
.tb-entity-table-title{ |
|||
padding-bottom: 5px; |
|||
width: 100%; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
:host ::ng-deep { |
|||
.mat-sort-header-sorted .mat-sort-header-arrow { |
|||
opacity: 1 !important; |
|||
} |
|||
tb-branch-autocomplete { |
|||
mat-form-field { |
|||
font-size: 16px; |
|||
width: 200px; |
|||
|
|||
.mat-form-field-wrapper { |
|||
padding-bottom: 0; |
|||
} |
|||
|
|||
.mat-form-field-underline { |
|||
bottom: 0; |
|||
} |
|||
|
|||
@media #{$mat-xs} { |
|||
width: 100%; |
|||
|
|||
.mat-form-field-infix { |
|||
width: auto !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,244 @@ |
|||
///
|
|||
/// 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 { |
|||
AfterViewInit, |
|||
ChangeDetectorRef, |
|||
Component, |
|||
ElementRef, |
|||
Input, |
|||
OnDestroy, |
|||
OnInit, |
|||
ViewChild |
|||
} from '@angular/core'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { EntityId } from '@shared/models/id/entity-id'; |
|||
import { CollectionViewer, DataSource } from '@angular/cdk/collections'; |
|||
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 { EntitiesVersionControlService } from '@core/http/entities-version-control.service'; |
|||
import { MatPaginator } from '@angular/material/paginator'; |
|||
import { MatSort } from '@angular/material/sort'; |
|||
import { ResizeObserver } from '@juggle/resize-observer'; |
|||
import { hidePageSizePixelValue } from '@shared/models/constants'; |
|||
import { Direction, SortOrder } from '@shared/models/page/sort-order'; |
|||
import { BranchAutocompleteComponent } from '@shared/components/vc/branch-autocomplete.component'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-entity-versions-table', |
|||
templateUrl: './entity-versions-table.component.html', |
|||
styleUrls: ['./entity-versions-table.component.scss'] |
|||
}) |
|||
export class EntityVersionsTableComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy { |
|||
|
|||
@ViewChild('branchAutocompleteComponent') branchAutocompleteComponent: BranchAutocompleteComponent; |
|||
|
|||
@Input() |
|||
singleEntityMode = false; |
|||
|
|||
displayedColumns = ['timestamp', 'id', 'name']; |
|||
pageLink: PageLink; |
|||
dataSource: EntityVersionsDatasource; |
|||
hidePageSize = false; |
|||
|
|||
branch: string = null; |
|||
|
|||
activeValue = false; |
|||
dirtyValue = false; |
|||
externalEntityIdValue: EntityId; |
|||
|
|||
viewsInited = false; |
|||
|
|||
private componentResize$: ResizeObserver; |
|||
|
|||
@Input() |
|||
set active(active: boolean) { |
|||
if (this.activeValue !== active) { |
|||
this.activeValue = active; |
|||
if (this.activeValue && this.dirtyValue) { |
|||
this.dirtyValue = false; |
|||
if (this.viewsInited) { |
|||
this.initFromDefaultBranch(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Input() |
|||
set externalEntityId(externalEntityId: EntityId) { |
|||
if (this.externalEntityIdValue !== externalEntityId) { |
|||
this.externalEntityIdValue = externalEntityId; |
|||
this.resetSortAndFilter(this.activeValue); |
|||
if (!this.activeValue) { |
|||
this.dirtyValue = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ViewChild(MatPaginator) paginator: MatPaginator; |
|||
@ViewChild(MatSort) sort: MatSort; |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
private entitiesVersionControlService: EntitiesVersionControlService, |
|||
private cd: ChangeDetectorRef, |
|||
private elementRef: ElementRef) { |
|||
super(store); |
|||
this.dirtyValue = !this.activeValue; |
|||
const sortOrder: SortOrder = { property: 'timestamp', direction: Direction.DESC }; |
|||
this.pageLink = new PageLink(10, 0, null, sortOrder); |
|||
this.dataSource = new EntityVersionsDatasource(this.entitiesVersionControlService); |
|||
} |
|||
|
|||
ngOnInit() { |
|||
this.componentResize$ = new ResizeObserver(() => { |
|||
const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue; |
|||
if (showHidePageSize !== this.hidePageSize) { |
|||
this.hidePageSize = showHidePageSize; |
|||
this.cd.markForCheck(); |
|||
} |
|||
}); |
|||
this.componentResize$.observe(this.elementRef.nativeElement); |
|||
} |
|||
|
|||
ngOnDestroy() { |
|||
if (this.componentResize$) { |
|||
this.componentResize$.disconnect(); |
|||
} |
|||
} |
|||
|
|||
branchChanged(newBranch: string) { |
|||
this.branch = newBranch; |
|||
this.paginator.pageIndex = 0; |
|||
if (this.activeValue) { |
|||
this.updateData(); |
|||
} |
|||
} |
|||
|
|||
ngAfterViewInit() { |
|||
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0); |
|||
merge(this.sort.sortChange, this.paginator.page) |
|||
.pipe( |
|||
tap(() => this.updateData()) |
|||
) |
|||
.subscribe(); |
|||
this.viewsInited = true; |
|||
if (!this.singleEntityMode) { |
|||
this.initFromDefaultBranch(); |
|||
} |
|||
} |
|||
|
|||
vcExport($event: Event) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
} |
|||
|
|||
private initFromDefaultBranch() { |
|||
this.branchAutocompleteComponent.selectDefaultBranchIfNeeded(false, true); |
|||
} |
|||
|
|||
private updateData() { |
|||
this.pageLink.page = this.paginator.pageIndex; |
|||
this.pageLink.pageSize = this.paginator.pageSize; |
|||
this.pageLink.sortOrder.property = this.sort.active; |
|||
this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()]; |
|||
this.dataSource.loadEntityVersions(this.singleEntityMode, this.branch, this.externalEntityIdValue, this.pageLink); |
|||
} |
|||
|
|||
private resetSortAndFilter(update: boolean) { |
|||
this.branch = null; |
|||
this.pageLink.textSearch = null; |
|||
if (this.viewsInited) { |
|||
this.paginator.pageIndex = 0; |
|||
const sortable = this.sort.sortables.get('timestamp'); |
|||
this.sort.active = sortable.id; |
|||
this.sort.direction = 'desc'; |
|||
if (update) { |
|||
this.initFromDefaultBranch(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
class EntityVersionsDatasource implements DataSource<EntityVersion> { |
|||
|
|||
private entityVersionsSubject = new BehaviorSubject<EntityVersion[]>([]); |
|||
private pageDataSubject = new BehaviorSubject<PageData<EntityVersion>>(emptyPageData<EntityVersion>()); |
|||
|
|||
public pageData$ = this.pageDataSubject.asObservable(); |
|||
|
|||
constructor(private entitiesVersionControlService: EntitiesVersionControlService) {} |
|||
|
|||
connect(collectionViewer: CollectionViewer): Observable<EntityVersion[] | ReadonlyArray<EntityVersion>> { |
|||
return this.entityVersionsSubject.asObservable(); |
|||
} |
|||
|
|||
disconnect(collectionViewer: CollectionViewer): void { |
|||
this.entityVersionsSubject.complete(); |
|||
this.pageDataSubject.complete(); |
|||
} |
|||
|
|||
loadEntityVersions(singleEntityMode: boolean, |
|||
branch: string, externalEntityId: EntityId, |
|||
pageLink: PageLink): Observable<PageData<EntityVersion>> { |
|||
const result = new ReplaySubject<PageData<EntityVersion>>(); |
|||
this.fetchEntityVersions(singleEntityMode, branch, externalEntityId, pageLink).pipe( |
|||
catchError(() => of(emptyPageData<EntityVersion>())), |
|||
).subscribe( |
|||
(pageData) => { |
|||
this.entityVersionsSubject.next(pageData.data); |
|||
this.pageDataSubject.next(pageData); |
|||
result.next(pageData); |
|||
} |
|||
); |
|||
return result; |
|||
} |
|||
|
|||
fetchEntityVersions(singleEntityMode: boolean, |
|||
branch: string, externalEntityId: EntityId, |
|||
pageLink: PageLink): Observable<PageData<EntityVersion>> { |
|||
if (!branch) { |
|||
return of(emptyPageData<EntityVersion>()); |
|||
} else { |
|||
if (singleEntityMode) { |
|||
if (externalEntityId) { |
|||
return this.entitiesVersionControlService.listEntityVersions(pageLink, branch, externalEntityId, {ignoreErrors: true}); |
|||
} else { |
|||
return of(emptyPageData<EntityVersion>()); |
|||
} |
|||
} else { |
|||
return this.entitiesVersionControlService.listVersions(pageLink, branch, {ignoreErrors: true}); |
|||
} |
|||
} |
|||
} |
|||
|
|||
isEmpty(): Observable<boolean> { |
|||
return this.entityVersionsSubject.pipe( |
|||
map((entityVersions) => !entityVersions.length) |
|||
); |
|||
} |
|||
|
|||
total(): Observable<number> { |
|||
return this.pageDataSubject.pipe( |
|||
map((pageData) => pageData.totalElements) |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<tb-version-control-settings #versionControlSettingsComponent [detailsMode]="detailsMode" |
|||
*ngIf="!(hasVersionControl$ | async); else versionsTable"> |
|||
</tb-version-control-settings> |
|||
<ng-template #versionsTable> |
|||
<tb-entity-versions-table [singleEntityMode]="singleEntityMode" |
|||
[active]="active" |
|||
[externalEntityId]="externalEntityId"></tb-entity-versions-table> |
|||
</ng-template> |
|||
@ -0,0 +1,18 @@ |
|||
/** |
|||
* 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 { |
|||
|
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
///
|
|||
/// 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, ViewChild } from '@angular/core'; |
|||
import { select, Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { selectHasVersionControl } from '@core/auth/auth.selectors'; |
|||
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; |
|||
import { VersionControlSettingsComponent } from '@home/components/vc/version-control-settings.component'; |
|||
import { FormGroup } from '@angular/forms'; |
|||
import { EntityId } from '@shared/models/id/entity-id'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-version-control', |
|||
templateUrl: './version-control.component.html', |
|||
styleUrls: ['./version-control.component.scss'] |
|||
}) |
|||
export class VersionControlComponent implements OnInit, HasConfirmForm { |
|||
|
|||
@ViewChild('versionControlSettingsComponent', {static: false}) versionControlSettingsComponent: VersionControlSettingsComponent; |
|||
|
|||
@Input() |
|||
detailsMode = false; |
|||
|
|||
@Input() |
|||
active = true; |
|||
|
|||
@Input() |
|||
singleEntityMode = false; |
|||
|
|||
@Input() |
|||
externalEntityId: EntityId; |
|||
|
|||
hasVersionControl$ = this.store.pipe(select(selectHasVersionControl)); |
|||
|
|||
constructor(private store: Store<AppState>) { |
|||
|
|||
} |
|||
|
|||
ngOnInit() { |
|||
|
|||
} |
|||
|
|||
confirmForm(): FormGroup { |
|||
return this.versionControlSettingsComponent?.versionControlSettingsForm; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<!-- |
|||
|
|||
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. |
|||
|
|||
--> |
|||
<tb-version-control-settings #versionControlSettingsComponent></tb-version-control-settings> |
|||
@ -0,0 +1,44 @@ |
|||
///
|
|||
/// 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, OnInit, ViewChild } from '@angular/core'; |
|||
import { PageComponent } from '@shared/components/page.component'; |
|||
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { FormGroup } from '@angular/forms'; |
|||
import { VersionControlSettingsComponent } from '@home/components/vc/version-control-settings.component'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-version-control-admin-settings', |
|||
templateUrl: './version-control-admin-settings.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class VersionControlAdminSettingsComponent extends PageComponent implements OnInit, HasConfirmForm { |
|||
|
|||
@ViewChild('versionControlSettingsComponent') versionControlSettingsComponent: VersionControlSettingsComponent; |
|||
|
|||
constructor(protected store: Store<AppState>) { |
|||
super(store); |
|||
} |
|||
|
|||
ngOnInit() { |
|||
} |
|||
|
|||
confirmForm(): FormGroup { |
|||
return this.versionControlSettingsComponent?.versionControlSettingsForm; |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
///
|
|||
/// 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 { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; |
|||
import { Authority } from '@shared/models/authority.enum'; |
|||
import { VersionControlComponent } from '@home/components/vc/version-control.component'; |
|||
|
|||
const routes: Routes = [ |
|||
{ |
|||
path: 'vc', |
|||
component: VersionControlComponent, |
|||
canDeactivate: [ConfirmOnExitGuard], |
|||
data: { |
|||
auth: [Authority.TENANT_ADMIN], |
|||
title: 'version-control.version-control', |
|||
breadcrumb: { |
|||
label: 'version-control.version-control', |
|||
icon: 'history' |
|||
} |
|||
} |
|||
} |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
providers: [] |
|||
}) |
|||
export class VcRoutingModule { } |
|||
@ -0,0 +1,31 @@ |
|||
///
|
|||
/// 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 { NgModule } from '@angular/core'; |
|||
import { CommonModule } from '@angular/common'; |
|||
import { SharedModule } from '@shared/shared.module'; |
|||
import { VcRoutingModule } from '@home/pages/vc/vc-routing.module'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ |
|||
], |
|||
imports: [ |
|||
CommonModule, |
|||
SharedModule, |
|||
VcRoutingModule |
|||
] |
|||
}) |
|||
export class VcModule { } |
|||
Loading…
Reference in new issue