UI: Implement auto-commit settings

This commit is contained in:
Igor Kulikov 2022-05-31 18:42:33 +03:00
parent 09402f40ac
commit 7841c5ff6f
19 changed files with 548 additions and 22 deletions

View File

@ -273,7 +273,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Get auto commit settings (getAutoCommitSettings)", @ApiOperation(value = "Get auto commit settings (getAutoCommitSettings)",
notes = "Get the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH) notes = "Get the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/vc/autoCommitSettings") @GetMapping("/autoCommitSettings")
@ResponseBody @ResponseBody
public AutoCommitSettings getAutoCommitSettings() throws ThingsboardException { public AutoCommitSettings getAutoCommitSettings() throws ThingsboardException {
try { try {
@ -287,7 +287,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Check auto commit settings exists (autoCommitSettingsExists)", @ApiOperation(value = "Check auto commit settings exists (autoCommitSettingsExists)",
notes = "Check whether the auto commit settings exists. " + TENANT_AUTHORITY_PARAGRAPH) notes = "Check whether the auto commit settings exists. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@GetMapping("/vc/autoCommitSettings/exists") @GetMapping("/autoCommitSettings/exists")
@ResponseBody @ResponseBody
public Boolean autoCommitSettingsExists() throws ThingsboardException { public Boolean autoCommitSettingsExists() throws ThingsboardException {
try { try {
@ -301,7 +301,7 @@ public class AdminController extends BaseController {
@ApiOperation(value = "Creates or Updates the auto commit settings (saveAutoCommitSettings)", @ApiOperation(value = "Creates or Updates the auto commit settings (saveAutoCommitSettings)",
notes = "Creates or Updates the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH) notes = "Creates or Updates the auto commit settings object. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@PostMapping("/vc/autoCommitSettings") @PostMapping("/autoCommitSettings")
public AutoCommitSettings saveAutoCommitSettings(@RequestBody AutoCommitSettings settings) throws ThingsboardException { public AutoCommitSettings saveAutoCommitSettings(@RequestBody AutoCommitSettings settings) throws ThingsboardException {
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE); accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
return autoCommitSettingsService.save(getTenantId(), settings); return autoCommitSettingsService.save(getTenantId(), settings);
@ -311,7 +311,7 @@ public class AdminController extends BaseController {
notes = "Deletes the auto commit settings." notes = "Deletes the auto commit settings."
+ TENANT_AUTHORITY_PARAGRAPH) + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/vc/autoCommitSettings", method = RequestMethod.DELETE) @RequestMapping(value = "/autoCommitSettings", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @ResponseStatus(value = HttpStatus.OK)
public void deleteAutoCommitSettings() throws ThingsboardException { public void deleteAutoCommitSettings() throws ThingsboardException {
try { try {

View File

@ -101,7 +101,7 @@ export class AdminService {
return this.http.get<AutoCommitSettings>(`/api/admin/autoCommitSettings`, defaultHttpOptionsFromConfig(config)); return this.http.get<AutoCommitSettings>(`/api/admin/autoCommitSettings`, defaultHttpOptionsFromConfig(config));
} }
private autoCommitSettingsExists(config?: RequestConfig): Observable<boolean> { public autoCommitSettingsExists(config?: RequestConfig): Observable<boolean> {
return this.http.get<boolean>('/api/admin/autoCommitSettings/exists', defaultHttpOptionsFromConfig(config)); return this.http.get<boolean>('/api/admin/autoCommitSettings/exists', defaultHttpOptionsFromConfig(config));
} }

View File

@ -369,7 +369,7 @@ export class MenuService {
name: 'admin.system-settings', name: 'admin.system-settings',
type: 'toggle', type: 'toggle',
path: '/settings', path: '/settings',
height: '120px', height: '160px',
icon: 'settings', icon: 'settings',
pages: [ pages: [
{ {
@ -392,6 +392,13 @@ export class MenuService {
type: 'link', type: 'link',
path: '/settings/repository', path: '/settings/repository',
icon: 'manage_history' icon: 'manage_history'
},
{
id: guid(),
name: 'admin.auto-commit-settings',
type: 'link',
path: '/settings/auto-commit',
icon: 'settings_backup_restore'
} }
] ]
} }
@ -541,6 +548,11 @@ export class MenuService {
name: 'admin.repository-settings', name: 'admin.repository-settings',
icon: 'manage_history', icon: 'manage_history',
path: '/settings/repository', path: '/settings/repository',
},
{
name: 'admin.auto-commit-settings',
icon: 'settings_backup_restore',
path: '/settings/auto-commit'
} }
] ]
} }

View File

@ -164,6 +164,7 @@ import { EntityTypesVersionCreateComponent } from '@home/components/vc/entity-ty
import { EntityTypesVersionLoadComponent } from '@home/components/vc/entity-types-version-load.component'; import { EntityTypesVersionLoadComponent } from '@home/components/vc/entity-types-version-load.component';
import { ComplexVersionLoadComponent } from '@home/components/vc/complex-version-load.component'; import { ComplexVersionLoadComponent } from '@home/components/vc/complex-version-load.component';
import { RemoveOtherEntitiesConfirmComponent } from '@home/components/vc/remove-other-entities-confirm.component'; import { RemoveOtherEntitiesConfirmComponent } from '@home/components/vc/remove-other-entities-confirm.component';
import { AutoCommitSettingsComponent } from '@home/components/vc/auto-commit-settings.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -298,7 +299,8 @@ import { RemoveOtherEntitiesConfirmComponent } from '@home/components/vc/remove-
EntityTypesVersionCreateComponent, EntityTypesVersionCreateComponent,
EntityTypesVersionLoadComponent, EntityTypesVersionLoadComponent,
ComplexVersionLoadComponent, ComplexVersionLoadComponent,
RemoveOtherEntitiesConfirmComponent RemoveOtherEntitiesConfirmComponent,
AutoCommitSettingsComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -427,7 +429,8 @@ import { RemoveOtherEntitiesConfirmComponent } from '@home/components/vc/remove-
EntityTypesVersionCreateComponent, EntityTypesVersionCreateComponent,
EntityTypesVersionLoadComponent, EntityTypesVersionLoadComponent,
ComplexVersionLoadComponent, ComplexVersionLoadComponent,
RemoveOtherEntitiesConfirmComponent RemoveOtherEntitiesConfirmComponent,
AutoCommitSettingsComponent
], ],
providers: [ providers: [
WidgetComponentService, WidgetComponentService,

View File

@ -0,0 +1,125 @@
<!--
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>
<mat-card class="auto-commit-settings settings-card">
<mat-card-title>
<div fxLayout="row">
<span class="mat-headline" translate>admin.auto-commit-settings</span>
<span fxFlex></span>
<div tb-help="autoCommitSettings"></div>
</div>
</mat-card-title>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<mat-card-content style="padding-top: 16px;">
<form [formGroup]="autoCommitSettingsForm" #formDirective="ngForm" (ngSubmit)="save()">
<fieldset class="fields-group" [disabled]="isLoading$ | async">
<legend class="group-title" translate>admin.auto-commit-entities</legend>
<div fxLayout="column">
<div class="tb-control-list">
<div *ngFor="let entityTypeFormGroup of entityTypesFormGroupArray(); trackBy: trackByEntityType;
let $index = index; last as isLast;"
fxLayout="row" fxLayoutAlign="start center" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}">
<mat-expansion-panel class="entity-type-config" fxFlex [formGroup]="entityTypeFormGroup" [expanded]="entityTypesFormGroupExpanded(entityTypeFormGroup)">
<mat-expansion-panel-header>
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-panel-title>
<div fxLayout="row" fxFlex fxLayoutAlign="start center">
<div [innerHTML]="entityTypeText(entityTypeFormGroup)"></div>
</div>
</mat-panel-title>
<span fxFlex></span>
<button mat-icon-button style="min-width: 40px;"
type="button"
(click)="removeEntityType($index)"
matTooltip="{{ 'action.remove' | translate }}"
matTooltipPosition="above">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="entity-type-config-content" fxLayout="column" fxLayoutGap="0.5em">
<mat-divider></mat-divider>
<div fxLayout="column" fxLayout.gt-lg="row" fxLayoutGap.gt-lg="16px">
<div fxLayout="row" fxLayoutGap="16px">
<tb-entity-type-select
showLabel
formControlName="entityType"
required
[filterAllowedEntityTypes]="false"
[allowedEntityTypes]="allowedEntityTypes(entityTypeFormGroup)">
</tb-entity-type-select>
<div formGroupName="config">
<tb-branch-autocomplete
emptyPlaceholder="{{ 'version-control.default' | translate }}"
[selectDefaultBranch]="false"
formControlName="branch">
</tb-branch-autocomplete>
</div>
</div>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px" formGroupName="config">
<mat-checkbox formControlName="saveRelations">
{{ 'version-control.export-entity-relations' | translate }}
</mat-checkbox>
<mat-checkbox formControlName="saveAttributes">
{{ 'version-control.export-entity-attributes' | translate }}
</mat-checkbox>
</div>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
</div>
<div *ngIf="!entityTypesFormGroupArray().length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">admin.no-auto-commit-entities-prompt</span>
</div>
<div style="padding-top: 16px;" fxLayout="row">
<button mat-raised-button color="primary"
type="button"
[disabled]="!addEnabled()"
(click)="addEntityType()">
<span translate>version-control.add-entity-type</span>
</button>
<span fxFlex></span>
<button mat-raised-button color="primary"
type="button"
[disabled]="!entityTypesFormGroupArray().length"
(click)="removeAll()">
<span translate>version-control.remove-all</span>
</button>
</div>
</div>
</fieldset>
<div fxLayout="row" fxLayoutAlign="end center" fxLayout.xs="column" fxLayoutAlign.xs="end" fxLayoutGap="16px">
<button mat-raised-button color="warn" type="button" [fxShow]="settings !== null"
[disabled]="(isLoading$ | async)" (click)="delete(formDirective)">
{{'action.delete' | translate}}
</button>
<span fxFlex></span>
<button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || autoCommitSettingsForm.invalid || !autoCommitSettingsForm.dirty"
type="submit">{{'action.save' | translate}}
</button>
</div>
</form>
</mat-card-content>
</mat-card>
</div>

View File

@ -0,0 +1,74 @@
/**
* 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 {
mat-card.auto-commit-settings {
margin: 8px;
.mat-divider {
position: relative;
}
}
.fields-group {
padding: 0 16px 8px;
margin-bottom: 10px;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
legend {
color: rgba(0, 0, 0, .7);
width: fit-content;
}
legend + * {
display: block;
margin-top: 16px;
}
}
.tb-control-list {
overflow-y: auto;
max-height: 600px;
}
.tb-prompt {
margin: 30px 0;
}
mat-expansion-panel.entity-type-config {
box-shadow: none;
border: 1px groove rgba(0, 0, 0, .25);
.mat-expansion-panel-header {
padding: 0 24px 0 8px;
height: 48px;
}
.entity-type-config-content {
padding: 0 8px 8px;
tb-branch-autocomplete {
min-width: 200px;
max-width: 200px;
display: block;
}
}
}
}
:host ::ng-deep {
.mat-expansion-panel.entity-type-config {
.mat-expansion-panel-body {
padding: 0;
}
}
}

View File

@ -0,0 +1,210 @@
///
/// 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 } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { AbstractControl, FormArray, FormBuilder, FormGroup, FormGroupDirective, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { AdminService } from '@core/http/admin.service';
import { AutoCommitSettings, AutoVersionCreateConfig } from '@shared/models/settings.models';
import { TranslateService } from '@ngx-translate/core';
import { DialogService } from '@core/services/dialog.service';
import { catchError, mergeMap } from 'rxjs/operators';
import { of } from 'rxjs';
import { EntityTypeVersionCreateConfig, exportableEntityTypes } from '@shared/models/vc.models';
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Component({
selector: 'tb-auto-commit-settings',
templateUrl: './auto-commit-settings.component.html',
styleUrls: ['./auto-commit-settings.component.scss', './../../pages/admin/settings-card.scss']
})
export class AutoCommitSettingsComponent extends PageComponent implements OnInit {
autoCommitSettingsForm: FormGroup;
settings: AutoCommitSettings = null;
constructor(protected store: Store<AppState>,
private adminService: AdminService,
private dialogService: DialogService,
private sanitizer: DomSanitizer,
private translate: TranslateService,
public fb: FormBuilder) {
super(store);
}
ngOnInit() {
this.autoCommitSettingsForm = this.fb.group({
entityTypes: this.fb.array([], [])
});
this.adminService.autoCommitSettingsExists().pipe(
catchError(() => of(false)),
mergeMap((hasAutoCommitSettings) => {
if (hasAutoCommitSettings) {
return this.adminService.getAutoCommitSettings({ignoreErrors: true}).pipe(
catchError(() => of(null))
);
} else {
return of(null);
}
})
).subscribe(
(settings) => {
this.settings = settings;
this.autoCommitSettingsForm.setControl('entityTypes',
this.prepareEntityTypesFormArray(settings), {emitEvent: false});
});
}
entityTypesFormGroupArray(): FormGroup[] {
return (this.autoCommitSettingsForm.get('entityTypes') as FormArray).controls as FormGroup[];
}
entityTypesFormGroupExpanded(entityTypeControl: AbstractControl): boolean {
return !!(entityTypeControl as any).expanded;
}
public trackByEntityType(index: number, entityTypeControl: AbstractControl): any {
return entityTypeControl;
}
public removeEntityType(index: number) {
(this.autoCommitSettingsForm.get('entityTypes') as FormArray).removeAt(index);
this.autoCommitSettingsForm.markAsDirty();
}
public addEnabled(): boolean {
const entityTypesArray = this.autoCommitSettingsForm.get('entityTypes') as FormArray;
return entityTypesArray.length < exportableEntityTypes.length;
}
public addEntityType() {
const entityTypesArray = this.autoCommitSettingsForm.get('entityTypes') as FormArray;
const config: AutoVersionCreateConfig = {
branch: null,
saveRelations: false,
saveAttributes: false
};
const allowed = this.allowedEntityTypes();
let entityType: EntityType = null;
if (allowed.length) {
entityType = allowed[0];
}
const entityTypeControl = this.createEntityTypeControl(entityType, config);
(entityTypeControl as any).expanded = true;
entityTypesArray.push(entityTypeControl);
this.autoCommitSettingsForm.updateValueAndValidity();
this.autoCommitSettingsForm.markAsDirty();
}
public removeAll() {
const entityTypesArray = this.autoCommitSettingsForm.get('entityTypes') as FormArray;
entityTypesArray.clear();
this.autoCommitSettingsForm.updateValueAndValidity();
this.autoCommitSettingsForm.markAsDirty();
}
entityTypeText(entityTypeControl: AbstractControl): SafeHtml {
const entityType: EntityType = entityTypeControl.get('entityType').value;
const config: AutoVersionCreateConfig = entityTypeControl.get('config').value;
let message = entityType ? this.translate.instant(entityTypeTranslations.get(entityType).typePlural) : 'Undefined';
let branchName;
if (config.branch) {
branchName = config.branch;
} else {
branchName = this.translate.instant('version-control.default');
}
message += ` (<small>${this.translate.instant('version-control.auto-commit-to-branch', {branch: branchName})}</small>)`;
return this.sanitizer.bypassSecurityTrustHtml(message);
}
allowedEntityTypes(entityTypeControl?: AbstractControl): Array<EntityType> {
let res = [...exportableEntityTypes];
const currentEntityType: EntityType = entityTypeControl?.get('entityType')?.value;
const value: [{entityType: string, config: EntityTypeVersionCreateConfig}] =
this.autoCommitSettingsForm.get('entityTypes').value || [];
const usedEntityTypes = value.map(val => val.entityType).filter(val => val);
res = res.filter(entityType => !usedEntityTypes.includes(entityType) || entityType === currentEntityType);
return res;
}
save(): void {
const value: [{entityType: string, config: AutoVersionCreateConfig}] =
this.autoCommitSettingsForm.get('entityTypes').value || [];
const settings: AutoCommitSettings = {};
if (value && value.length) {
value.forEach((val) => {
settings[val.entityType] = val.config;
});
}
this.adminService.saveAutoCommitSettings(settings).subscribe(
(savedSettings) => {
this.settings = savedSettings;
this.autoCommitSettingsForm.setControl('entityTypes',
this.prepareEntityTypesFormArray(savedSettings), {emitEvent: false});
this.autoCommitSettingsForm.markAsPristine();
}
);
}
delete(formDirective: FormGroupDirective): void {
this.dialogService.confirm(
this.translate.instant('admin.delete-auto-commit-settings-title', ),
this.translate.instant('admin.delete-auto-commit-settings-text'), null,
this.translate.instant('action.delete')
).subscribe((data) => {
if (data) {
this.adminService.deleteAutoCommitSettings().subscribe(
() => {
this.settings = null;
this.autoCommitSettingsForm.setControl('entityTypes',
this.prepareEntityTypesFormArray(this.settings), {emitEvent: false});
this.autoCommitSettingsForm.markAsPristine();
}
);
}
});
}
private prepareEntityTypesFormArray(settings: AutoCommitSettings | null): FormArray {
const entityTypesControls: Array<AbstractControl> = [];
if (settings) {
for (const entityType of Object.keys(settings)) {
const config = settings[entityType];
entityTypesControls.push(this.createEntityTypeControl(entityType as EntityType, config));
}
}
return this.fb.array(entityTypesControls);
}
private createEntityTypeControl(entityType: EntityType, config: AutoVersionCreateConfig): AbstractControl {
const entityTypeControl = this.fb.group(
{
entityType: [entityType, [Validators.required]],
config: this.fb.group({
branch: [config.branch, []],
saveRelations: [config.saveRelations, []],
saveAttributes: [config.saveAttributes, []]
})
}
);
return entityTypeControl;
}
}

View File

@ -17,7 +17,7 @@
--> -->
<section class="entity-types-version-create" [formGroup]="entityTypesVersionCreateFormGroup" fxLayout="column"> <section class="entity-types-version-create" [formGroup]="entityTypesVersionCreateFormGroup" fxLayout="column">
<fieldset class="fields-group"> <fieldset class="fields-group">
<legend class="group-title" translate>version-control.entity-types</legend> <legend class="group-title" translate>version-control.entities-to-export</legend>
<div fxLayout="column"> <div fxLayout="column">
<div class="tb-control-list"> <div class="tb-control-list">
<div *ngFor="let entityTypeFormGroup of entityTypesFormGroupArray(); trackBy: trackByEntityType; <div *ngFor="let entityTypeFormGroup of entityTypesFormGroupArray(); trackBy: trackByEntityType;
@ -94,7 +94,7 @@
</div> </div>
<div *ngIf="!entityTypesFormGroupArray().length"> <div *ngIf="!entityTypesFormGroupArray().length">
<span translate fxLayoutAlign="center center" <span translate fxLayoutAlign="center center"
class="tb-prompt">version-control.no-entity-types</span> class="tb-prompt">version-control.no-entities-to-export-prompt</span>
</div> </div>
<div style="padding-top: 16px;" fxLayout="row"> <div style="padding-top: 16px;" fxLayout="row">
<button mat-raised-button color="primary" <button mat-raised-button color="primary"

View File

@ -80,7 +80,7 @@ export class EntityTypesVersionCreateComponent extends PageComponent implements
ngOnInit(): void { ngOnInit(): void {
this.entityTypesVersionCreateFormGroup = this.fb.group({ this.entityTypesVersionCreateFormGroup = this.fb.group({
entityTypes: [this.fb.array([]), []] entityTypes: this.fb.array([], [])
}); });
this.entityTypesVersionCreateFormGroup.valueChanges.subscribe(() => { this.entityTypesVersionCreateFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();

View File

@ -17,7 +17,7 @@
--> -->
<section class="entity-types-version-load" [formGroup]="entityTypesVersionLoadFormGroup" fxLayout="column"> <section class="entity-types-version-load" [formGroup]="entityTypesVersionLoadFormGroup" fxLayout="column">
<fieldset class="fields-group"> <fieldset class="fields-group">
<legend class="group-title" translate>version-control.entity-types</legend> <legend class="group-title" translate>version-control.entities-to-restore</legend>
<div fxLayout="column"> <div fxLayout="column">
<div class="tb-control-list"> <div class="tb-control-list">
<div *ngFor="let entityTypeFormGroup of entityTypesFormGroupArray(); trackBy: trackByEntityType; <div *ngFor="let entityTypeFormGroup of entityTypesFormGroupArray(); trackBy: trackByEntityType;
@ -80,7 +80,7 @@
</div> </div>
<div *ngIf="!entityTypesFormGroupArray().length"> <div *ngIf="!entityTypesFormGroupArray().length">
<span translate fxLayoutAlign="center center" <span translate fxLayoutAlign="center center"
class="tb-prompt">version-control.no-entity-types</span> class="tb-prompt">version-control.no-entities-to-restore-prompt</span>
</div> </div>
<div style="padding-top: 16px;" fxLayout="row"> <div style="padding-top: 16px;" fxLayout="row">
<button mat-raised-button color="primary" <button mat-raised-button color="primary"

View File

@ -77,7 +77,7 @@ export class EntityTypesVersionLoadComponent extends PageComponent implements On
ngOnInit(): void { ngOnInit(): void {
this.entityTypesVersionLoadFormGroup = this.fb.group({ this.entityTypesVersionLoadFormGroup = this.fb.group({
entityTypes: [this.fb.array([]), []] entityTypes: this.fb.array([], [])
}); });
this.entityTypesVersionLoadFormGroup.valueChanges.subscribe(() => { this.entityTypesVersionLoadFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();

View File

@ -34,6 +34,7 @@ import { entityDetailsPageBreadcrumbLabelFunction } from '@home/pages/home-pages
import { BreadCrumbConfig } from '@shared/components/breadcrumb'; import { BreadCrumbConfig } from '@shared/components/breadcrumb';
import { QueuesTableConfigResolver } from '@home/pages/admin/queue/queues-table-config.resolver'; import { QueuesTableConfigResolver } from '@home/pages/admin/queue/queues-table-config.resolver';
import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component';
import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component';
@Injectable() @Injectable()
export class OAuth2LoginProcessingUrlResolver implements Resolve<string> { export class OAuth2LoginProcessingUrlResolver implements Resolve<string> {
@ -236,6 +237,19 @@ const routes: Routes = [
icon: 'manage_history' icon: 'manage_history'
} }
} }
},
{
path: 'auto-commit',
component: AutoCommitAdminSettingsComponent,
canDeactivate: [ConfirmOnExitGuard],
data: {
auth: [Authority.TENANT_ADMIN],
title: 'admin.auto-commit-settings',
breadcrumb: {
label: 'admin.auto-commit-settings',
icon: 'settings_backup_restore'
}
}
} }
] ]
} }

View File

@ -30,6 +30,7 @@ import { HomeSettingsComponent } from '@home/pages/admin/home-settings.component
import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources-library.component'; import { ResourcesLibraryComponent } from '@home/pages/admin/resource/resources-library.component';
import { QueueComponent} from '@home/pages/admin/queue/queue.component'; import { QueueComponent} from '@home/pages/admin/queue/queue.component';
import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component'; import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-admin-settings.component';
import { AutoCommitAdminSettingsComponent } from '@home/pages/admin/auto-commit-admin-settings.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -43,7 +44,8 @@ import { RepositoryAdminSettingsComponent } from '@home/pages/admin/repository-a
HomeSettingsComponent, HomeSettingsComponent,
ResourcesLibraryComponent, ResourcesLibraryComponent,
QueueComponent, QueueComponent,
RepositoryAdminSettingsComponent RepositoryAdminSettingsComponent,
AutoCommitAdminSettingsComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,

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.
-->
<tb-repository-settings #repositorySettingsComponent
*ngIf="!(hasRepository$ | async); else autoCommitSettings">
</tb-repository-settings>
<ng-template #autoCommitSettings>
<tb-auto-commit-settings #autoCommitSettingsComponent></tb-auto-commit-settings>
</ng-template>

View File

@ -0,0 +1,51 @@
///
/// 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 { select, Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { FormGroup } from '@angular/forms';
import { AutoCommitSettingsComponent } from '@home/components/vc/auto-commit-settings.component';
import { selectHasRepository } from '@core/auth/auth.selectors';
import { RepositorySettingsComponent } from '@home/components/vc/repository-settings.component';
@Component({
selector: 'tb-auto-commit-admin-settings',
templateUrl: './auto-commit-admin-settings.component.html',
styleUrls: []
})
export class AutoCommitAdminSettingsComponent extends PageComponent implements OnInit, HasConfirmForm {
@ViewChild('repositorySettingsComponent', {static: false}) repositorySettingsComponent: RepositorySettingsComponent;
@ViewChild('autoCommitSettingsComponent', {static: false}) autoCommitSettingsComponent: AutoCommitSettingsComponent;
hasRepository$ = this.store.pipe(select(selectHasRepository));
constructor(protected store: Store<AppState>) {
super(store);
}
ngOnInit() {
}
confirmForm(): FormGroup {
return this.repositorySettingsComponent ?
this.repositorySettingsComponent?.repositorySettingsForm :
this.autoCommitSettingsComponent?.autoCommitSettingsForm;
}
}

View File

@ -15,9 +15,9 @@
limitations under the License. limitations under the License.
--> -->
<mat-form-field [formGroup]="branchFormGroup" class="mat-block" [floatLabel]="selectionMode ? 'always' : 'auto'"> <mat-form-field [formGroup]="branchFormGroup" class="mat-block" [floatLabel]="(selectionMode || emptyPlaceholder) ? 'always' : 'auto'">
<mat-label>{{ 'version-control.branch' | translate }}</mat-label> <mat-label>{{ 'version-control.branch' | translate }}</mat-label>
<input matInput type="text" placeholder="{{(loading ? 'common.loading' : 'version-control.select-branch') | translate}}" <input matInput type="text" placeholder="{{emptyPlaceholder || ((loading ? 'common.loading' : 'version-control.select-branch') | translate)}}"
#branchInput #branchInput
formControlName="branch" formControlName="branch"
(keydown.enter)="branchInput.blur(); autoCompleteTrigger.closePanel();" (keydown.enter)="branchInput.blur(); autoCompleteTrigger.closePanel();"

View File

@ -86,6 +86,9 @@ export class BranchAutocompleteComponent implements ControlValueAccessor, OnInit
@Input() @Input()
selectionMode = false; selectionMode = false;
@Input()
emptyPlaceholder: string;
@ViewChild('branchAutocomplete') matAutocomplete: MatAutocomplete; @ViewChild('branchAutocomplete') matAutocomplete: MatAutocomplete;
@ViewChild('branchInput', { read: MatAutocompleteTrigger, static: true }) autoCompleteTrigger: MatAutocompleteTrigger; @ViewChild('branchInput', { read: MatAutocompleteTrigger, static: true }) autoCompleteTrigger: MatAutocompleteTrigger;
@ViewChild('branchInput', {static: true}) branchInput: ElementRef; @ViewChild('branchInput', {static: true}) branchInput: ElementRef;

View File

@ -135,7 +135,8 @@ export const HelpLinks = {
ruleNodePushToCloud: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-cloud', ruleNodePushToCloud: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-cloud',
ruleNodePushToEdge: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-edge', ruleNodePushToEdge: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#push-to-edge',
queue: helpBaseUrl + '/docs/user-guide/queue', queue: helpBaseUrl + '/docs/user-guide/queue',
repositorySettings: helpBaseUrl + '/docs/user-guide/ui/repository-settings' repositorySettings: helpBaseUrl + '/docs/user-guide/ui/repository-settings',
autoCommitSettings: helpBaseUrl + '/docs/user-guide/ui/auto-commit-settings',
} }
}; };

View File

@ -340,7 +340,12 @@
"check-access": "Check access", "check-access": "Check access",
"check-repository-access-success": "Repository access successfully verified!", "check-repository-access-success": "Repository access successfully verified!",
"delete-repository-settings-title": "Are you sure you want to delete repository settings?", "delete-repository-settings-title": "Are you sure you want to delete repository settings?",
"delete-repository-settings-text": "Be careful, after the confirmation the repository settings will be removed and version control feature will be unavailable." "delete-repository-settings-text": "Be careful, after the confirmation the repository settings will be removed and version control feature will be unavailable.",
"auto-commit-settings": "Auto-commit settings",
"auto-commit-entities": "Auto-commit entities",
"no-auto-commit-entities-prompt": "No entities configured for auto-commit",
"delete-auto-commit-settings-title": "Are you sure you want to delete auto-commit settings?",
"delete-auto-commit-settings-text": "Be careful, after the confirmation the auto-commit settings will be removed and auto-commit will be disabled for all entities."
}, },
"alarm": { "alarm": {
"alarm": "Alarm", "alarm": "Alarm",
@ -3145,10 +3150,12 @@
"default-sync-strategy": "Default sync strategy", "default-sync-strategy": "Default sync strategy",
"sync-strategy-merge": "Merge", "sync-strategy-merge": "Merge",
"sync-strategy-overwrite": "Overwrite", "sync-strategy-overwrite": "Overwrite",
"entity-types": "Entity types", "entities-to-export": "Entities to export",
"entities-to-restore": "Entities to restore",
"sync-strategy": "Sync strategy", "sync-strategy": "Sync strategy",
"all-entities": "All entities", "all-entities": "All entities",
"no-entity-types": "No entity types configured", "no-entities-to-export-prompt": "Please specify entities to export",
"no-entities-to-restore-prompt": "Please specify entities to restore",
"add-entity-type": "Add entity type", "add-entity-type": "Add entity type",
"remove-all": "Remove all", "remove-all": "Remove all",
"version-create-result": "{ added, plural, 0 {No entities} 1 {1 entity} other {# entities} } added.\n{ modified, plural, 0 {No entities} 1 {1 entity} other {# entities} } modified.\n{ removed, plural, 0 {No entities} 1 {1 entity} other {# entities} } removed.", "version-create-result": "{ added, plural, 0 {No entities} 1 {1 entity} other {# entities} } added.\n{ modified, plural, 0 {No entities} 1 {1 entity} other {# entities} } modified.\n{ removed, plural, 0 {No entities} 1 {1 entity} other {# entities} } removed.",
@ -3161,7 +3168,8 @@
"created": "{{created}} created", "created": "{{created}} created",
"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"
}, },
"widget": { "widget": {
"widget-library": "Widgets Library", "widget-library": "Widgets Library",