UI: Implement complex version create action.
This commit is contained in:
parent
0be0df6015
commit
b6f964a5eb
@ -156,9 +156,11 @@ import { WidgetSettingsComponent } from '@home/components/widget/widget-settings
|
|||||||
import { VersionControlSettingsComponent } from '@home/components/vc/version-control-settings.component';
|
import { VersionControlSettingsComponent } from '@home/components/vc/version-control-settings.component';
|
||||||
import { VersionControlComponent } from '@home/components/vc/version-control.component';
|
import { VersionControlComponent } from '@home/components/vc/version-control.component';
|
||||||
import { EntityVersionsTableComponent } from '@home/components/vc/entity-versions-table.component';
|
import { EntityVersionsTableComponent } from '@home/components/vc/entity-versions-table.component';
|
||||||
import { EntityVersionExportComponent } from '@home/components/vc/entity-version-export.component';
|
import { EntityVersionCreateComponent } from '@home/components/vc/entity-version-create.component';
|
||||||
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
|
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
|
||||||
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
|
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
|
||||||
|
import { ComplexVersionCreateComponent } from '@home/components/vc/complex-version-create.component';
|
||||||
|
import { EntityTypesVersionCreateComponent } from '@home/components/vc/entity-types-version-create.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations:
|
declarations:
|
||||||
@ -286,9 +288,11 @@ import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-d
|
|||||||
VersionControlSettingsComponent,
|
VersionControlSettingsComponent,
|
||||||
VersionControlComponent,
|
VersionControlComponent,
|
||||||
EntityVersionsTableComponent,
|
EntityVersionsTableComponent,
|
||||||
EntityVersionExportComponent,
|
EntityVersionCreateComponent,
|
||||||
EntityVersionRestoreComponent,
|
EntityVersionRestoreComponent,
|
||||||
EntityVersionDiffComponent
|
EntityVersionDiffComponent,
|
||||||
|
ComplexVersionCreateComponent,
|
||||||
|
EntityTypesVersionCreateComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -410,9 +414,11 @@ import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-d
|
|||||||
VersionControlSettingsComponent,
|
VersionControlSettingsComponent,
|
||||||
VersionControlComponent,
|
VersionControlComponent,
|
||||||
EntityVersionsTableComponent,
|
EntityVersionsTableComponent,
|
||||||
EntityVersionExportComponent,
|
EntityVersionCreateComponent,
|
||||||
EntityVersionRestoreComponent,
|
EntityVersionRestoreComponent,
|
||||||
EntityVersionDiffComponent
|
EntityVersionDiffComponent,
|
||||||
|
ComplexVersionCreateComponent,
|
||||||
|
EntityTypesVersionCreateComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
WidgetComponentService,
|
WidgetComponentService,
|
||||||
|
|||||||
@ -0,0 +1,82 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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: 800px;">
|
||||||
|
<section *ngIf="!resultMessage">
|
||||||
|
<mat-toolbar>
|
||||||
|
<h2>{{ 'version-control.create-entities-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]="createVersionFormGroup" style="padding-top: 16px;">
|
||||||
|
<fieldset [disabled]="isLoading$ | async">
|
||||||
|
<div fxFlex fxLayout="column">
|
||||||
|
<tb-branch-autocomplete
|
||||||
|
fxFlex
|
||||||
|
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="createVersionFormGroup.get('versionName').hasError('required')">
|
||||||
|
{{ 'version-control.version-name-required' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field fxFlex class="mat-block">
|
||||||
|
<mat-label translate>version-control.default-sync-strategy</mat-label>
|
||||||
|
<mat-select required formControlName="syncStrategy">
|
||||||
|
<mat-option *ngFor="let strategy of syncStrategies" [value]="strategy">
|
||||||
|
{{syncStrategyTranslations.get(strategy) | translate}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<tb-entity-types-version-create
|
||||||
|
formControlName="entityTypes">
|
||||||
|
</tb-entity-types-version-create>
|
||||||
|
</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) || createVersionFormGroup.invalid || !createVersionFormGroup.dirty">
|
||||||
|
{{ 'action.create' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section *ngIf="resultMessage">
|
||||||
|
<div class="mat-title create-result-message">{{ resultMessage }}</div>
|
||||||
|
<div fxLayoutAlign="end center" fxLayoutGap="8px">
|
||||||
|
<button mat-button color="primary"
|
||||||
|
type="button"
|
||||||
|
[disabled]="(isLoading$ | async)"
|
||||||
|
(click)="cancel()" cdkFocusInitial>
|
||||||
|
{{ 'action.close' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
:host {
|
:host {
|
||||||
.export-result-message {
|
.create-result-message {
|
||||||
padding: 48px 8px 8px;
|
padding: 48px 8px 8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
///
|
||||||
|
/// 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 {
|
||||||
|
ComplexVersionCreateRequest,
|
||||||
|
createDefaultEntityTypesVersionCreate,
|
||||||
|
SyncStrategy, syncStrategyTranslationMap,
|
||||||
|
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 { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-complex-version-create',
|
||||||
|
templateUrl: './complex-version-create.component.html',
|
||||||
|
styleUrls: ['./complex-version-create.component.scss']
|
||||||
|
})
|
||||||
|
export class ComplexVersionCreateComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
branch: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
onClose: (result: VersionCreationResult | null, branch: string | null) => void;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
onContentUpdated: () => void;
|
||||||
|
|
||||||
|
createVersionFormGroup: FormGroup;
|
||||||
|
|
||||||
|
syncStrategies = Object.values(SyncStrategy);
|
||||||
|
|
||||||
|
syncStrategyTranslations = syncStrategyTranslationMap;
|
||||||
|
|
||||||
|
resultMessage: string;
|
||||||
|
|
||||||
|
versionCreateResult: VersionCreationResult = null;
|
||||||
|
|
||||||
|
versionCreateBranch: string = null;
|
||||||
|
|
||||||
|
constructor(protected store: Store<AppState>,
|
||||||
|
private entitiesVersionControlService: EntitiesVersionControlService,
|
||||||
|
private translate: TranslateService,
|
||||||
|
private fb: FormBuilder) {
|
||||||
|
super(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.createVersionFormGroup = this.fb.group({
|
||||||
|
branch: [this.branch, [Validators.required]],
|
||||||
|
versionName: [null, [Validators.required]],
|
||||||
|
syncStrategy: [SyncStrategy.MERGE, Validators.required],
|
||||||
|
entityTypes: [createDefaultEntityTypesVersionCreate(), []],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel(): void {
|
||||||
|
if (this.onClose) {
|
||||||
|
this.onClose(this.versionCreateResult, this.versionCreateBranch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export(): void {
|
||||||
|
const request: ComplexVersionCreateRequest = {
|
||||||
|
branch: this.createVersionFormGroup.get('branch').value,
|
||||||
|
versionName: this.createVersionFormGroup.get('versionName').value,
|
||||||
|
syncStrategy: this.createVersionFormGroup.get('syncStrategy').value,
|
||||||
|
entityTypes: this.createVersionFormGroup.get('entityTypes').value,
|
||||||
|
type: VersionCreateRequestType.COMPLEX
|
||||||
|
};
|
||||||
|
this.entitiesVersionControlService.saveEntitiesVersion(request).subscribe((result) => {
|
||||||
|
if (!result.added && !result.modified && !result.removed) {
|
||||||
|
this.resultMessage = this.translate.instant('version-control.nothing-to-commit');
|
||||||
|
} else {
|
||||||
|
this.resultMessage = this.translate.instant('version-control.version-create-result',
|
||||||
|
{added: result.added, modified: result.modified, removed: result.removed});
|
||||||
|
}
|
||||||
|
this.versionCreateResult = result;
|
||||||
|
this.versionCreateBranch = request.branch;
|
||||||
|
if (this.onContentUpdated) {
|
||||||
|
this.onContentUpdated();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,111 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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 class="entity-types-version-create" [formGroup]="entityTypesVersionCreateFormGroup" fxLayout="column">
|
||||||
|
<fieldset class="fields-group">
|
||||||
|
<legend class="group-title" translate>version-control.entity-types</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>{{ entityTypeText(entityTypeFormGroup) }}</div>
|
||||||
|
</div>
|
||||||
|
</mat-panel-title>
|
||||||
|
<span fxFlex></span>
|
||||||
|
<button *ngIf="!disabled" 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="row" fxLayoutGap="16px">
|
||||||
|
<tb-entity-type-select
|
||||||
|
showLabel
|
||||||
|
formControlName="entityType"
|
||||||
|
required
|
||||||
|
[filterAllowedEntityTypes]="false"
|
||||||
|
[allowedEntityTypes]="allowedEntityTypes(entityTypeFormGroup)">
|
||||||
|
</tb-entity-type-select>
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutGap="16px" fxLayoutAlign="start center" formGroupName="config">
|
||||||
|
<mat-form-field class="mat-block">
|
||||||
|
<mat-label translate>version-control.sync-strategy</mat-label>
|
||||||
|
<mat-select formControlName="syncStrategy">
|
||||||
|
<mat-option [value]="'default'">
|
||||||
|
{{ 'version-control.default' | translate }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option *ngFor="let strategy of syncStrategies" [value]="strategy">
|
||||||
|
{{syncStrategyTranslations.get(strategy) | translate}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-checkbox formControlName="saveRelations">
|
||||||
|
{{ 'version-control.export-entity-relations' | translate }}
|
||||||
|
</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div fxLayout="row" fxLayoutGap="16px" fxLayoutAlign="start center"
|
||||||
|
formGroupName="config" style="height: 60px;">
|
||||||
|
<mat-slide-toggle formControlName="allEntities">
|
||||||
|
{{ 'version-control.all-entities' | translate }}
|
||||||
|
</mat-slide-toggle>
|
||||||
|
<tb-entity-list
|
||||||
|
fxFlex
|
||||||
|
[fxShow]="!entityTypeFormGroup.get('config').get('allEntities').value"
|
||||||
|
[entityType]="entityTypeFormGroup.get('entityType').value"
|
||||||
|
required
|
||||||
|
formControlName="entityIds">
|
||||||
|
</tb-entity-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!entityTypesFormGroupArray().length">
|
||||||
|
<span translate fxLayoutAlign="center center"
|
||||||
|
class="tb-prompt">version-control.no-entity-types</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>
|
||||||
|
</section>
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
.entity-types-version-create {
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep {
|
||||||
|
.mat-expansion-panel.entity-type-config {
|
||||||
|
.mat-expansion-panel-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,247 @@
|
|||||||
|
///
|
||||||
|
/// 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, forwardRef, Input, OnInit } from '@angular/core';
|
||||||
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
ControlValueAccessor,
|
||||||
|
FormArray,
|
||||||
|
FormBuilder,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
|
NG_VALIDATORS,
|
||||||
|
NG_VALUE_ACCESSOR,
|
||||||
|
Validator,
|
||||||
|
Validators
|
||||||
|
} from '@angular/forms';
|
||||||
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
|
import {
|
||||||
|
EntityTypeVersionCreateConfig,
|
||||||
|
exportableEntityTypes,
|
||||||
|
SyncStrategy,
|
||||||
|
syncStrategyTranslationMap
|
||||||
|
} from '@shared/models/vc.models';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '@core/core.state';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||||
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-entity-types-version-create',
|
||||||
|
templateUrl: './entity-types-version-create.component.html',
|
||||||
|
styleUrls: ['./entity-types-version-create.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => EntityTypesVersionCreateComponent),
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: NG_VALIDATORS,
|
||||||
|
useExisting: forwardRef(() => EntityTypesVersionCreateComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class EntityTypesVersionCreateComponent extends PageComponent implements OnInit, ControlValueAccessor, Validator {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
private modelValue: {[entityType: string]: EntityTypeVersionCreateConfig};
|
||||||
|
|
||||||
|
private propagateChange = null;
|
||||||
|
|
||||||
|
public entityTypesVersionCreateFormGroup: FormGroup;
|
||||||
|
|
||||||
|
syncStrategies = Object.values(SyncStrategy);
|
||||||
|
|
||||||
|
syncStrategyTranslations = syncStrategyTranslationMap;
|
||||||
|
|
||||||
|
constructor(protected store: Store<AppState>,
|
||||||
|
private translate: TranslateService,
|
||||||
|
private fb: FormBuilder) {
|
||||||
|
super(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.entityTypesVersionCreateFormGroup = this.fb.group({
|
||||||
|
entityTypes: [this.fb.array([]), [Validators.min(1)]]
|
||||||
|
});
|
||||||
|
this.entityTypesVersionCreateFormGroup.valueChanges.subscribe(() => {
|
||||||
|
this.updateModel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
if (isDisabled) {
|
||||||
|
this.entityTypesVersionCreateFormGroup.disable({emitEvent: false});
|
||||||
|
} else {
|
||||||
|
this.entityTypesVersionCreateFormGroup.enable({emitEvent: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: {[entityType: string]: EntityTypeVersionCreateConfig} | undefined): void {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.entityTypesVersionCreateFormGroup.setControl('entityTypes',
|
||||||
|
this.prepareEntityTypesFormArray(value), {emitEvent: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
public validate(c: FormControl) {
|
||||||
|
return this.entityTypesVersionCreateFormGroup.valid && this.entityTypesFormGroupArray().length ? null : {
|
||||||
|
entityTypes: {
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepareEntityTypesFormArray(entityTypes: {[entityType: string]: EntityTypeVersionCreateConfig} | undefined): FormArray {
|
||||||
|
const entityTypesControls: Array<AbstractControl> = [];
|
||||||
|
if (entityTypes) {
|
||||||
|
for (const entityType of Object.keys(entityTypes)) {
|
||||||
|
const config = entityTypes[entityType];
|
||||||
|
entityTypesControls.push(this.createEntityTypeControl(entityType as EntityType, config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.fb.array(entityTypesControls);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createEntityTypeControl(entityType: EntityType, config: EntityTypeVersionCreateConfig): AbstractControl {
|
||||||
|
const entityTypeControl = this.fb.group(
|
||||||
|
{
|
||||||
|
entityType: [entityType, [Validators.required]],
|
||||||
|
config: this.fb.group({
|
||||||
|
syncStrategy: [config.syncStrategy === null ? 'default' : config.syncStrategy, []],
|
||||||
|
saveRelations: [config.saveRelations, []],
|
||||||
|
allEntities: [config.allEntities, []],
|
||||||
|
entityIds: [config.entityIds, [Validators.required]]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.updateEntityTypeValidators(entityTypeControl);
|
||||||
|
entityTypeControl.get('config').get('allEntities').valueChanges.subscribe(() => {
|
||||||
|
this.updateEntityTypeValidators(entityTypeControl);
|
||||||
|
});
|
||||||
|
return entityTypeControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEntityTypeValidators(entityTypeControl: AbstractControl): void {
|
||||||
|
const allEntities: boolean = entityTypeControl.get('config').get('allEntities').value;
|
||||||
|
if (allEntities) {
|
||||||
|
entityTypeControl.get('config').get('entityIds').disable({emitEvent: false});
|
||||||
|
} else {
|
||||||
|
entityTypeControl.get('config').get('entityIds').enable({emitEvent: false});
|
||||||
|
}
|
||||||
|
entityTypeControl.get('config').get('entityIds').updateValueAndValidity({emitEvent: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
entityTypesFormGroupArray(): FormGroup[] {
|
||||||
|
return (this.entityTypesVersionCreateFormGroup.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.entityTypesVersionCreateFormGroup.get('entityTypes') as FormArray).removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addEnabled(): boolean {
|
||||||
|
const entityTypesArray = this.entityTypesVersionCreateFormGroup.get('entityTypes') as FormArray;
|
||||||
|
return entityTypesArray.length < exportableEntityTypes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addEntityType() {
|
||||||
|
const entityTypesArray = this.entityTypesVersionCreateFormGroup.get('entityTypes') as FormArray;
|
||||||
|
const config: EntityTypeVersionCreateConfig = {
|
||||||
|
syncStrategy: null,
|
||||||
|
saveRelations: false,
|
||||||
|
allEntities: true,
|
||||||
|
entityIds: []
|
||||||
|
};
|
||||||
|
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.entityTypesVersionCreateFormGroup.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeAll() {
|
||||||
|
const entityTypesArray = this.entityTypesVersionCreateFormGroup.get('entityTypes') as FormArray;
|
||||||
|
entityTypesArray.clear();
|
||||||
|
this.entityTypesVersionCreateFormGroup.updateValueAndValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
entityTypeText(entityTypeControl: AbstractControl): string {
|
||||||
|
const entityType: EntityType = entityTypeControl.get('entityType').value;
|
||||||
|
const config: EntityTypeVersionCreateConfig = entityTypeControl.get('config').value;
|
||||||
|
let count = config?.entityIds?.length;
|
||||||
|
if (!isDefinedAndNotNull(count)) {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
if (entityType) {
|
||||||
|
return this.translate.instant((config?.allEntities ? entityTypeTranslations.get(entityType).typePlural
|
||||||
|
: entityTypeTranslations.get(entityType).list), { count });
|
||||||
|
} else {
|
||||||
|
return 'Undefined';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allowedEntityTypes(entityTypeControl?: AbstractControl): Array<EntityType> {
|
||||||
|
let res = [...exportableEntityTypes];
|
||||||
|
const currentEntityType: EntityType = entityTypeControl?.get('entityType')?.value;
|
||||||
|
const value: [{entityType: string, config: EntityTypeVersionCreateConfig}] =
|
||||||
|
this.entityTypesVersionCreateFormGroup.get('entityTypes').value || [];
|
||||||
|
const usedEntityTypes = value.map(val => val.entityType).filter(val => val);
|
||||||
|
res = res.filter(entityType => !usedEntityTypes.includes(entityType) || entityType === currentEntityType);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateModel() {
|
||||||
|
const value: [{entityType: string, config: EntityTypeVersionCreateConfig}] =
|
||||||
|
this.entityTypesVersionCreateFormGroup.get('entityTypes').value || [];
|
||||||
|
let modelValue: {[entityType: string]: EntityTypeVersionCreateConfig} = null;
|
||||||
|
if (value && value.length) {
|
||||||
|
modelValue = {};
|
||||||
|
value.forEach((val) => {
|
||||||
|
modelValue[val.entityType] = val.config;
|
||||||
|
if ((modelValue[val.entityType].syncStrategy as any) === 'default') {
|
||||||
|
modelValue[val.entityType].syncStrategy = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.modelValue = modelValue;
|
||||||
|
this.propagateChange(this.modelValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<mat-progress-bar color="warn" style="z-index: 10; width: 100%; margin-bottom: -4px;" mode="indeterminate"
|
<mat-progress-bar color="warn" style="z-index: 10; width: 100%; margin-bottom: -4px;" mode="indeterminate"
|
||||||
*ngIf="isLoading$ | async">
|
*ngIf="isLoading$ | async">
|
||||||
</mat-progress-bar>
|
</mat-progress-bar>
|
||||||
<form [formGroup]="exportFormGroup" style="padding-top: 16px;">
|
<form [formGroup]="createVersionFormGroup" style="padding-top: 16px;">
|
||||||
<fieldset [disabled]="isLoading$ | async">
|
<fieldset [disabled]="isLoading$ | async">
|
||||||
<div fxFlex fxLayout="column">
|
<div fxFlex fxLayout="column">
|
||||||
<tb-branch-autocomplete
|
<tb-branch-autocomplete
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<mat-form-field class="mat-block" fxFlex>
|
<mat-form-field class="mat-block" fxFlex>
|
||||||
<mat-label translate>version-control.version-name</mat-label>
|
<mat-label translate>version-control.version-name</mat-label>
|
||||||
<input required matInput formControlName="versionName">
|
<input required matInput formControlName="versionName">
|
||||||
<mat-error *ngIf="exportFormGroup.get('versionName').hasError('required')">
|
<mat-error *ngIf="createVersionFormGroup.get('versionName').hasError('required')">
|
||||||
{{ 'version-control.version-name-required' | translate }}
|
{{ 'version-control.version-name-required' | translate }}
|
||||||
</mat-error>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
@ -54,13 +54,13 @@
|
|||||||
<button mat-raised-button color="primary"
|
<button mat-raised-button color="primary"
|
||||||
type="button"
|
type="button"
|
||||||
(click)="export()"
|
(click)="export()"
|
||||||
[disabled]="(isLoading$ | async) || exportFormGroup.invalid || !exportFormGroup.dirty">
|
[disabled]="(isLoading$ | async) || createVersionFormGroup.invalid || !createVersionFormGroup.dirty">
|
||||||
{{ 'action.create' | translate }}
|
{{ 'action.create' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section *ngIf="resultMessage">
|
<section *ngIf="resultMessage">
|
||||||
<div class="mat-title export-result-message">{{ resultMessage }}</div>
|
<div class="mat-title create-result-message">{{ resultMessage }}</div>
|
||||||
<div fxLayoutAlign="end center" fxLayoutGap="8px">
|
<div fxLayoutAlign="end center" fxLayoutGap="8px">
|
||||||
<button mat-button color="primary"
|
<button mat-button color="primary"
|
||||||
type="button"
|
type="button"
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
.create-result-message {
|
||||||
|
padding: 48px 8px 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -29,11 +29,11 @@ import { EntityId } from '@shared/models/id/entity-id';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entity-version-export',
|
selector: 'tb-entity-version-create',
|
||||||
templateUrl: './entity-version-export.component.html',
|
templateUrl: './entity-version-create.component.html',
|
||||||
styleUrls: ['./entity-version-export.component.scss']
|
styleUrls: ['./entity-version-create.component.scss']
|
||||||
})
|
})
|
||||||
export class EntityVersionExportComponent extends PageComponent implements OnInit {
|
export class EntityVersionCreateComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
branch: string;
|
branch: string;
|
||||||
@ -47,7 +47,7 @@ export class EntityVersionExportComponent extends PageComponent implements OnIni
|
|||||||
@Input()
|
@Input()
|
||||||
onContentUpdated: () => void;
|
onContentUpdated: () => void;
|
||||||
|
|
||||||
exportFormGroup: FormGroup;
|
createVersionFormGroup: FormGroup;
|
||||||
|
|
||||||
resultMessage: string;
|
resultMessage: string;
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ export class EntityVersionExportComponent extends PageComponent implements OnIni
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.exportFormGroup = this.fb.group({
|
this.createVersionFormGroup = this.fb.group({
|
||||||
branch: [this.branch, [Validators.required]],
|
branch: [this.branch, [Validators.required]],
|
||||||
versionName: [null, [Validators.required]],
|
versionName: [null, [Validators.required]],
|
||||||
saveRelations: [false, []]
|
saveRelations: [false, []]
|
||||||
@ -75,10 +75,10 @@ export class EntityVersionExportComponent extends PageComponent implements OnIni
|
|||||||
export(): void {
|
export(): void {
|
||||||
const request: SingleEntityVersionCreateRequest = {
|
const request: SingleEntityVersionCreateRequest = {
|
||||||
entityId: this.entityId,
|
entityId: this.entityId,
|
||||||
branch: this.exportFormGroup.get('branch').value,
|
branch: this.createVersionFormGroup.get('branch').value,
|
||||||
versionName: this.exportFormGroup.get('versionName').value,
|
versionName: this.createVersionFormGroup.get('versionName').value,
|
||||||
config: {
|
config: {
|
||||||
saveRelations: this.exportFormGroup.get('saveRelations').value
|
saveRelations: this.createVersionFormGroup.get('saveRelations').value
|
||||||
},
|
},
|
||||||
type: VersionCreateRequestType.SINGLE_ENTITY
|
type: VersionCreateRequestType.SINGLE_ENTITY
|
||||||
};
|
};
|
||||||
@ -32,12 +32,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<span fxFlex></span>
|
<span fxFlex></span>
|
||||||
<button *ngIf="singleEntityMode" mat-stroked-button color="primary"
|
<button *ngIf="singleEntityMode" mat-stroked-button color="primary"
|
||||||
#exportButton
|
#createVersionButton
|
||||||
[disabled]="(isLoading$ | async)"
|
[disabled]="(isLoading$ | async)"
|
||||||
(click)="toggleVcExport($event, exportButton)">
|
(click)="toggleCreateVersion($event, createVersionButton)">
|
||||||
<mat-icon>update</mat-icon>
|
<mat-icon>update</mat-icon>
|
||||||
{{'version-control.create-version' | translate }}
|
{{'version-control.create-version' | translate }}
|
||||||
</button>
|
</button>
|
||||||
|
<button *ngIf="!singleEntityMode" mat-stroked-button color="primary"
|
||||||
|
#complexCreateVersionButton
|
||||||
|
[disabled]="(isLoading$ | async)"
|
||||||
|
(click)="toggleComplexCreateVersion($event, complexCreateVersionButton)">
|
||||||
|
<mat-icon>update</mat-icon>
|
||||||
|
{{'version-control.create-entities-version' | translate }}
|
||||||
|
</button>
|
||||||
<button mat-icon-button
|
<button mat-icon-button
|
||||||
[disabled]="isLoading$ | async"
|
[disabled]="isLoading$ | async"
|
||||||
(click)="enterFilterMode()"
|
(click)="enterFilterMode()"
|
||||||
|
|||||||
@ -43,11 +43,11 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order';
|
|||||||
import { BranchAutocompleteComponent } from '@shared/components/vc/branch-autocomplete.component';
|
import { BranchAutocompleteComponent } from '@shared/components/vc/branch-autocomplete.component';
|
||||||
import { isNotEmptyStr } from '@core/utils';
|
import { isNotEmptyStr } from '@core/utils';
|
||||||
import { TbPopoverService } from '@shared/components/popover.service';
|
import { TbPopoverService } from '@shared/components/popover.service';
|
||||||
import { EntityVersionExportComponent } from '@home/components/vc/entity-version-export.component';
|
import { EntityVersionCreateComponent } from '@home/components/vc/entity-version-create.component';
|
||||||
import { MatButton } from '@angular/material/button';
|
import { MatButton } from '@angular/material/button';
|
||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
|
||||||
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
|
import { EntityVersionRestoreComponent } from '@home/components/vc/entity-version-restore.component';
|
||||||
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
|
import { EntityVersionDiffComponent } from '@home/components/vc/entity-version-diff.component';
|
||||||
|
import { ComplexVersionCreateComponent } from '@home/components/vc/complex-version-create.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tb-entity-versions-table',
|
selector: 'tb-entity-versions-table',
|
||||||
@ -177,21 +177,21 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleVcExport($event: Event, exportButton: MatButton) {
|
toggleCreateVersion($event: Event, createVersionButton: MatButton) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
const trigger = exportButton._elementRef.nativeElement;
|
const trigger = createVersionButton._elementRef.nativeElement;
|
||||||
if (this.popoverService.hasPopover(trigger)) {
|
if (this.popoverService.hasPopover(trigger)) {
|
||||||
this.popoverService.hidePopover(trigger);
|
this.popoverService.hidePopover(trigger);
|
||||||
} else {
|
} else {
|
||||||
const vcExportPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
const createVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
||||||
this.viewContainerRef, EntityVersionExportComponent, 'left', true, null,
|
this.viewContainerRef, EntityVersionCreateComponent, 'left', true, null,
|
||||||
{
|
{
|
||||||
branch: this.branch,
|
branch: this.branch,
|
||||||
entityId: this.entityId,
|
entityId: this.entityId,
|
||||||
onClose: (result: VersionCreationResult | null, branch: string | null) => {
|
onClose: (result: VersionCreationResult | null, branch: string | null) => {
|
||||||
vcExportPopover.hide();
|
createVersionPopover.hide();
|
||||||
if (result) {
|
if (result) {
|
||||||
if (this.branch !== branch) {
|
if (this.branch !== branch) {
|
||||||
this.branchChanged(branch);
|
this.branchChanged(branch);
|
||||||
@ -201,9 +201,41 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onContentUpdated: () => {
|
onContentUpdated: () => {
|
||||||
vcExportPopover.updatePosition();
|
createVersionPopover.updatePosition();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
vcExportPopover.updatePosition();
|
createVersionPopover.updatePosition();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {}, {}, {}, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleComplexCreateVersion($event: Event, complexCreateVersionButton: MatButton) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopPropagation();
|
||||||
|
}
|
||||||
|
const trigger = complexCreateVersionButton._elementRef.nativeElement;
|
||||||
|
if (this.popoverService.hasPopover(trigger)) {
|
||||||
|
this.popoverService.hidePopover(trigger);
|
||||||
|
} else {
|
||||||
|
const complexCreateVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
||||||
|
this.viewContainerRef, ComplexVersionCreateComponent, 'leftTop', true, null,
|
||||||
|
{
|
||||||
|
branch: this.branch,
|
||||||
|
onClose: (result: VersionCreationResult | null, branch: string | null) => {
|
||||||
|
complexCreateVersionPopover.hide();
|
||||||
|
if (result) {
|
||||||
|
if (this.branch !== branch) {
|
||||||
|
this.branchChanged(branch);
|
||||||
|
} else {
|
||||||
|
this.updateData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onContentUpdated: () => {
|
||||||
|
complexCreateVersionPopover.updatePosition();
|
||||||
|
setTimeout(() => {
|
||||||
|
complexCreateVersionPopover.updatePosition();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, {}, {}, {}, false);
|
}, {}, {}, {}, false);
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
/// limitations under the License.
|
/// limitations under the License.
|
||||||
///
|
///
|
||||||
|
|
||||||
import { AfterViewInit, Component, forwardRef, Input, OnInit } from '@angular/core';
|
import { AfterViewInit, Component, forwardRef, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@app/core/core.state';
|
import { AppState } from '@app/core/core.state';
|
||||||
@ -33,7 +33,7 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|||||||
multi: true
|
multi: true
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, AfterViewInit {
|
export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges {
|
||||||
|
|
||||||
entityTypeFormGroup: FormGroup;
|
entityTypeFormGroup: FormGroup;
|
||||||
|
|
||||||
@ -45,6 +45,9 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
|
|||||||
@Input()
|
@Input()
|
||||||
useAliasEntityTypes: boolean;
|
useAliasEntityTypes: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
filterAllowedEntityTypes = true;
|
||||||
|
|
||||||
private showLabelValue: boolean;
|
private showLabelValue: boolean;
|
||||||
get showLabel(): boolean {
|
get showLabel(): boolean {
|
||||||
return this.showLabelValue;
|
return this.showLabelValue;
|
||||||
@ -87,7 +90,8 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.entityTypes = this.entityService.prepareAllowedEntityTypesList(this.allowedEntityTypes, this.useAliasEntityTypes);
|
this.entityTypes = this.filterAllowedEntityTypes ?
|
||||||
|
this.entityService.prepareAllowedEntityTypesList(this.allowedEntityTypes, this.useAliasEntityTypes) : this.allowedEntityTypes;
|
||||||
this.entityTypeFormGroup.get('entityType').valueChanges.subscribe(
|
this.entityTypeFormGroup.get('entityType').valueChanges.subscribe(
|
||||||
(value) => {
|
(value) => {
|
||||||
let modelValue;
|
let modelValue;
|
||||||
@ -101,6 +105,22 @@ export class EntityTypeSelectComponent implements ControlValueAccessor, OnInit,
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
for (const propName of Object.keys(changes)) {
|
||||||
|
const change = changes[propName];
|
||||||
|
if (!change.firstChange && change.currentValue !== change.previousValue) {
|
||||||
|
if (propName === 'allowedEntityTypes') {
|
||||||
|
this.entityTypes = this.filterAllowedEntityTypes ?
|
||||||
|
this.entityService.prepareAllowedEntityTypesList(this.allowedEntityTypes, this.useAliasEntityTypes) : this.allowedEntityTypes;
|
||||||
|
const currentEntityType: EntityType | AliasEntityType = this.entityTypeFormGroup.get('entityType').value;
|
||||||
|
if (currentEntityType && !this.entityTypes.includes(currentEntityType)) {
|
||||||
|
this.entityTypeFormGroup.get('entityType').patchValue(null, {emitEvent: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,15 @@ import { EntityRelation } from '@shared/models/relation.models';
|
|||||||
import { Device, DeviceCredentials } from '@shared/models/device.models';
|
import { Device, DeviceCredentials } from '@shared/models/device.models';
|
||||||
import { RuleChain, RuleChainMetaData } from '@shared/models/rule-chain.models';
|
import { RuleChain, RuleChainMetaData } from '@shared/models/rule-chain.models';
|
||||||
|
|
||||||
|
export const exportableEntityTypes: Array<EntityType> = [
|
||||||
|
EntityType.ASSET,
|
||||||
|
EntityType.DEVICE,
|
||||||
|
EntityType.DASHBOARD,
|
||||||
|
EntityType.CUSTOMER,
|
||||||
|
EntityType.DEVICE_PROFILE,
|
||||||
|
EntityType.RULE_CHAIN
|
||||||
|
];
|
||||||
|
|
||||||
export interface VersionCreateConfig {
|
export interface VersionCreateConfig {
|
||||||
saveRelations: boolean;
|
saveRelations: boolean;
|
||||||
}
|
}
|
||||||
@ -51,6 +60,43 @@ export interface SingleEntityVersionCreateRequest extends VersionCreateRequest {
|
|||||||
type: VersionCreateRequestType.SINGLE_ENTITY;
|
type: VersionCreateRequestType.SINGLE_ENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SyncStrategy {
|
||||||
|
MERGE = 'MERGE',
|
||||||
|
OVERWRITE = 'OVERWRITE'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const syncStrategyTranslationMap = new Map<SyncStrategy, string>(
|
||||||
|
[
|
||||||
|
[SyncStrategy.MERGE, 'version-control.sync-strategy-merge'],
|
||||||
|
[SyncStrategy.OVERWRITE, 'version-control.sync-strategy-overwrite']
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface EntityTypeVersionCreateConfig extends VersionCreateConfig {
|
||||||
|
syncStrategy: SyncStrategy;
|
||||||
|
entityIds: string[];
|
||||||
|
allEntities: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComplexVersionCreateRequest extends VersionCreateRequest {
|
||||||
|
syncStrategy: SyncStrategy;
|
||||||
|
entityTypes: {[entityType: string]: EntityTypeVersionCreateConfig};
|
||||||
|
type: VersionCreateRequestType.COMPLEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDefaultEntityTypesVersionCreate(): {[entityType: string]: EntityTypeVersionCreateConfig} {
|
||||||
|
const res: {[entityType: string]: EntityTypeVersionCreateConfig} = {};
|
||||||
|
for (const entityType of exportableEntityTypes) {
|
||||||
|
res[entityType] = {
|
||||||
|
syncStrategy: null,
|
||||||
|
saveRelations: false,
|
||||||
|
allEntities: true,
|
||||||
|
entityIds: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
export interface VersionLoadRequest {
|
export interface VersionLoadRequest {
|
||||||
branch: string;
|
branch: string;
|
||||||
versionId: string;
|
versionId: string;
|
||||||
@ -63,6 +109,7 @@ export interface SingleEntityVersionLoadRequest extends VersionLoadRequest {
|
|||||||
type: VersionLoadRequestType.SINGLE_ENTITY;
|
type: VersionLoadRequestType.SINGLE_ENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface BranchInfo {
|
export interface BranchInfo {
|
||||||
name: string;
|
name: string;
|
||||||
default: boolean;
|
default: boolean;
|
||||||
|
|||||||
@ -3137,7 +3137,19 @@
|
|||||||
"previous-difference": "Previous Difference",
|
"previous-difference": "Previous Difference",
|
||||||
"next-difference": "Next Difference",
|
"next-difference": "Next Difference",
|
||||||
"current": "Current",
|
"current": "Current",
|
||||||
"differences": "{ count, plural, 1 {1 difference} other {# differences} }"
|
"differences": "{ count, plural, 1 {1 difference} other {# differences} }",
|
||||||
|
"create-entities-version": "Create entities version",
|
||||||
|
"default-sync-strategy": "Default sync strategy",
|
||||||
|
"sync-strategy-merge": "Merge",
|
||||||
|
"sync-strategy-overwrite": "Overwrite",
|
||||||
|
"entity-types": "Entity types",
|
||||||
|
"sync-strategy": "Sync strategy",
|
||||||
|
"default": "Default",
|
||||||
|
"all-entities": "All entities",
|
||||||
|
"no-entity-types": "No entity types configured",
|
||||||
|
"add-entity-type": "Add entity type",
|
||||||
|
"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."
|
||||||
},
|
},
|
||||||
"widget": {
|
"widget": {
|
||||||
"widget-library": "Widgets Library",
|
"widget-library": "Widgets Library",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user