mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-26 17:24:45 +00:00
[ACS-3257] Create / Update rules dialog condition section (#2585)
* First commit: simple and composite condition UI * Styling, readonly mode, etc... * Unit tests for RuleSimpleConditionUiComponent * Validation for composite condition * Add unit tests for composite conditions * Revert manage rules screen * Reset karma conf singleRun to true * Couple of small changes * Typo
This commit is contained in:
parent
b082aaa011
commit
9a650f5265
@ -21,8 +21,47 @@
|
||||
"NO_DESCRIPTION": "No description"
|
||||
},
|
||||
"ERROR": {
|
||||
"REQUIRED": "This field is required"
|
||||
}
|
||||
"REQUIRED": "This field is required",
|
||||
"RULE_COMPOSITE_CONDITION_INVALID": "One or more condition groups is empty"
|
||||
},
|
||||
"COMPARATORS": {
|
||||
"EQUALS": "(=) Equals",
|
||||
"CONTAINS": "Contains",
|
||||
"STARTS_WITH": "Starts with",
|
||||
"ENDS_WITH": "Ends with",
|
||||
"GREATER_THAN": "(>) Greater than",
|
||||
"LESS_THAN": "(<) Less than",
|
||||
"GREATER_THAN_OR_EQUAL": "(>=) Greater than or equal",
|
||||
"LESS_THAN_OR_EQUAL": "(<=) Less than or equal",
|
||||
"ON": "(=) On",
|
||||
"AFTER": "(>) After",
|
||||
"BEFORE": "(<) Before",
|
||||
"ON_OR_AFTER": "(>=) On or after",
|
||||
"ON_OR_BEFORE": "(<=) On or before",
|
||||
"INSTANCE_OF": "(=) Is"
|
||||
},
|
||||
"FIELDS": {
|
||||
"NAME": "Name",
|
||||
"SIZE": "Size",
|
||||
"MIMETYPE": "Mimetype",
|
||||
"ENCODING": "Encoding",
|
||||
"HAS_CATEGORY": "Has category",
|
||||
"HAS_TAG": "Has tag",
|
||||
"HAS_ASPECT": "Has aspect"
|
||||
},
|
||||
"LOGIC_OPERATORS": {
|
||||
"IF": "If",
|
||||
"NOT_IF": "NOT If",
|
||||
"AND": "And",
|
||||
"OR": "Or"
|
||||
},
|
||||
"ACTIONS": {
|
||||
"ADD_CONDITION": "Add condition",
|
||||
"ADD_GROUP": "Add group",
|
||||
"REMOVE": "Remove"
|
||||
},
|
||||
"NO_CONDITIONS": "No conditions",
|
||||
"NO_CONDITIONS_IN_GROUP": "No conditions in the group"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,9 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { EditRuleDialogSmartComponent } from './rule-details/edit-rule-dialog.smart-component';
|
||||
import { ManageRulesSmartComponent } from './manage-rules/manage-rules.smart-component';
|
||||
import { RuleCompositeConditionUiComponent } from './rule-details/conditions/rule-composite-condition.ui-component';
|
||||
import { RuleDetailsUiComponent } from './rule-details/rule-details.ui-component';
|
||||
import { RuleSimpleConditionUiComponent } from './rule-details/conditions/rule-simple-condition.ui-component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -44,7 +46,13 @@ const routes: Routes = [
|
||||
@NgModule({
|
||||
providers: [provideExtensionConfig(['folder-rules.plugin.json'])],
|
||||
imports: [CommonModule, RouterModule.forChild(routes), CoreModule.forChild()],
|
||||
declarations: [EditRuleDialogSmartComponent, ManageRulesSmartComponent, RuleDetailsUiComponent]
|
||||
declarations: [
|
||||
EditRuleDialogSmartComponent,
|
||||
ManageRulesSmartComponent,
|
||||
RuleCompositeConditionUiComponent,
|
||||
RuleDetailsUiComponent,
|
||||
RuleSimpleConditionUiComponent
|
||||
]
|
||||
})
|
||||
export class AcaFolderRulesModule {
|
||||
constructor(translation: TranslationService, extensions: ExtensionService) {
|
||||
|
68
projects/aca-folder-rules/src/lib/mock/conditions.mock.ts
Normal file
68
projects/aca-folder-rules/src/lib/mock/conditions.mock.ts
Normal file
@ -0,0 +1,68 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RuleCompositeCondition } from '../model/rule-composite-condition.model';
|
||||
import { RuleSimpleCondition } from '../model/rule-simple-condition.model';
|
||||
|
||||
const simpleConditionMock: RuleSimpleCondition = {
|
||||
field: 'cm:name',
|
||||
comparator: 'equals',
|
||||
parameter: ''
|
||||
};
|
||||
|
||||
const emptyCompositeConditionMock: RuleCompositeCondition = {
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
};
|
||||
|
||||
const compositeConditionWithOneConditionMock: RuleCompositeCondition = {
|
||||
...emptyCompositeConditionMock,
|
||||
simpleConditions: [{ ...simpleConditionMock }]
|
||||
};
|
||||
|
||||
export const compositeConditionWithOneGroupMock: RuleCompositeCondition = {
|
||||
...emptyCompositeConditionMock,
|
||||
compositeConditions: [{ ...compositeConditionWithOneConditionMock }]
|
||||
};
|
||||
|
||||
export const compositeConditionWithNestedGroupsMock: RuleCompositeCondition = {
|
||||
...emptyCompositeConditionMock,
|
||||
compositeConditions: [
|
||||
{
|
||||
...emptyCompositeConditionMock,
|
||||
compositeConditions: [{ ...compositeConditionWithOneConditionMock }]
|
||||
},
|
||||
{ ...compositeConditionWithOneConditionMock }
|
||||
]
|
||||
};
|
||||
|
||||
export const compositeConditionWithThreeConditionMock: RuleCompositeCondition = {
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
compositeConditions: [],
|
||||
simpleConditions: [{ ...simpleConditionMock }, { ...simpleConditionMock }, { ...simpleConditionMock }]
|
||||
};
|
@ -0,0 +1,68 @@
|
||||
<form class="aca-rule-composite-condition__form" [formGroup]="form">
|
||||
<div *ngIf="hasNoConditions" class="aca-rule-composite-condition__form__no-conditions" data-automation-id="no-conditions">
|
||||
{{ 'ACA_FOLDER_RULES.RULE_DETAILS.' + (childCondition ? 'NO_CONDITIONS_IN_GROUP' : 'NO_CONDITIONS') | translate }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="aca-rule-composite-condition__form__row"
|
||||
*ngFor="let control of conditionFormControls; let i = index">
|
||||
|
||||
<mat-form-field *ngIf="i === 0">
|
||||
<mat-select
|
||||
[value]="invertedControl.value"
|
||||
[disabled]="readOnly"
|
||||
(selectionChange)="setInverted($event.value)">
|
||||
<mat-option [value]="false">{{ 'ACA_FOLDER_RULES.RULE_DETAILS.LOGIC_OPERATORS.IF' | translate }}</mat-option>
|
||||
<mat-option [value]="true">{{ 'ACA_FOLDER_RULES.RULE_DETAILS.LOGIC_OPERATORS.NOT_IF' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field *ngIf="i > 0">
|
||||
<mat-select
|
||||
[value]="booleanModeControl.value"
|
||||
[disabled]="i > 1 || readOnly"
|
||||
(selectionChange)="setBooleanMode($event.value)">
|
||||
<mat-option value="and">{{ 'ACA_FOLDER_RULES.RULE_DETAILS.LOGIC_OPERATORS.AND' | translate }}</mat-option>
|
||||
<mat-option value="or">{{ 'ACA_FOLDER_RULES.RULE_DETAILS.LOGIC_OPERATORS.OR' | translate }}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<aca-rule-composite-condition
|
||||
*ngIf="!isFormControlSimpleCondition(control)"
|
||||
[secondaryBackground]="!secondaryBackground"
|
||||
[childCondition]="true"
|
||||
[formControl]="control">
|
||||
</aca-rule-composite-condition>
|
||||
|
||||
<aca-rule-simple-condition
|
||||
*ngIf="isFormControlSimpleCondition(control)"
|
||||
[formControl]="control">
|
||||
</aca-rule-simple-condition>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" *ngIf="!readOnly" data-automation-id="condition-actions-button">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu">
|
||||
<button
|
||||
mat-menu-item
|
||||
[title]="'ACA_FOLDER_RULES.RULE_DETAILS.ACTIONS.REMOVE' | translate"
|
||||
(click)="removeCondition(control)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'ACA_FOLDER_RULES.RULE_DETAILS.ACTIONS.REMOVE' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="aca-rule-composite-condition__form__actions" *ngIf="!readOnly" data-automation-id="add-actions">
|
||||
<button mat-button (click)="addSimpleCondition()" data-automation-id="add-condition-button">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>{{ 'ACA_FOLDER_RULES.RULE_DETAILS.ACTIONS.ADD_CONDITION' | translate }}</span>
|
||||
</button>
|
||||
<button mat-button (click)="addCompositeCondition()" data-automation-id="add-group-button">
|
||||
<mat-icon>add</mat-icon>
|
||||
<span>{{ 'ACA_FOLDER_RULES.RULE_DETAILS.ACTIONS.ADD_GROUP' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
@ -0,0 +1,38 @@
|
||||
.aca-rule-composite-condition {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
background-color: hsl(0,0%,100%);
|
||||
|
||||
&.childCompositeCondition {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
&.secondaryBackground {
|
||||
background-color: hsl(0,0%,95%);
|
||||
}
|
||||
|
||||
&__form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
&__no-conditions {
|
||||
color: var(--theme-disabled-text-color);
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
&__row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
& > :nth-child(1) {
|
||||
width: 5em;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
& > :nth-child(2) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleCompositeConditionUiComponent } from './rule-composite-condition.ui-component';
|
||||
import { CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
import {
|
||||
compositeConditionWithNestedGroupsMock,
|
||||
compositeConditionWithOneGroupMock,
|
||||
compositeConditionWithThreeConditionMock
|
||||
} from '../../mock/conditions.mock';
|
||||
import { RuleSimpleConditionUiComponent } from './rule-simple-condition.ui-component';
|
||||
|
||||
describe('RuleCompositeConditionUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleCompositeConditionUiComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule],
|
||||
declarations: [RuleCompositeConditionUiComponent, RuleSimpleConditionUiComponent]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RuleCompositeConditionUiComponent);
|
||||
});
|
||||
|
||||
describe('No conditions', () => {
|
||||
let noConditionsElement: DebugElement;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture.detectChanges();
|
||||
noConditionsElement = fixture.debugElement.query(By.css(`[data-automation-id="no-conditions"]`));
|
||||
});
|
||||
|
||||
it('should default to no conditions', () => {
|
||||
const rowElements = fixture.debugElement.queryAll(By.css(`.aca-rule-composite-condition__form__row`));
|
||||
|
||||
expect(rowElements.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should show a message if there are no conditions', () => {
|
||||
fixture.componentInstance.childCondition = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect((noConditionsElement.nativeElement as HTMLElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS');
|
||||
});
|
||||
|
||||
it('should show a different message if the component is not a root condition group', () => {
|
||||
fixture.componentInstance.childCondition = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect((noConditionsElement.nativeElement as HTMLElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_DETAILS.NO_CONDITIONS_IN_GROUP');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Read only mode', () => {
|
||||
it('should hide the add buttons in read only mode', () => {
|
||||
fixture.componentInstance.setDisabledState(true);
|
||||
fixture.detectChanges();
|
||||
const actionsElement = fixture.debugElement.query(By.css(`[data-automation-id="add-actions"]`));
|
||||
|
||||
expect(actionsElement).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the more actions button on the right side of the condition', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithOneGroupMock);
|
||||
fixture.componentInstance.setDisabledState(true);
|
||||
fixture.detectChanges();
|
||||
const actionsButtonElements = fixture.debugElement.queryAll(By.css(`[data-automation-id="condition-actions-button"]`));
|
||||
|
||||
expect(actionsButtonElements.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have as many simple condition components as defined in the simpleConditions array', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithThreeConditionMock);
|
||||
fixture.detectChanges();
|
||||
const simpleConditionComponents = fixture.debugElement.queryAll(By.css(`.aca-rule-simple-condition`));
|
||||
|
||||
expect(simpleConditionComponents.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should have as many composite condition components as defined in the compositeConditions array, including nested', () => {
|
||||
fixture.componentInstance.writeValue(compositeConditionWithNestedGroupsMock);
|
||||
fixture.detectChanges();
|
||||
const compositeConditionComponents = fixture.debugElement.queryAll(By.css(`.aca-rule-composite-condition`));
|
||||
|
||||
expect(compositeConditionComponents.length).toBe(3);
|
||||
});
|
||||
|
||||
it('should add a simple condition component on click of add condition button', () => {
|
||||
fixture.detectChanges();
|
||||
const predicate = By.css(`.aca-rule-simple-condition`);
|
||||
const simpleConditionComponentsBeforeClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(simpleConditionComponentsBeforeClick.length).toBe(0);
|
||||
|
||||
const addConditionButton = fixture.debugElement.query(By.css(`[data-automation-id="add-condition-button"]`));
|
||||
(addConditionButton.nativeElement as HTMLButtonElement).click();
|
||||
fixture.detectChanges();
|
||||
const simpleConditionComponentsAfterClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(simpleConditionComponentsAfterClick.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should add a composite condition component on click of add group button', () => {
|
||||
fixture.detectChanges();
|
||||
const predicate = By.css(`.aca-rule-composite-condition`);
|
||||
const compositeConditionComponentsBeforeClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(compositeConditionComponentsBeforeClick.length).toBe(0);
|
||||
|
||||
const addGroupButton = fixture.debugElement.query(By.css(`[data-automation-id="add-group-button"]`));
|
||||
(addGroupButton.nativeElement as HTMLButtonElement).click();
|
||||
fixture.detectChanges();
|
||||
const compositeConditionComponentsAfterClick = fixture.debugElement.queryAll(predicate);
|
||||
|
||||
expect(compositeConditionComponentsAfterClick.length).toBe(1);
|
||||
});
|
||||
});
|
@ -0,0 +1,157 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, forwardRef, HostBinding, Input, OnDestroy, ViewEncapsulation } from '@angular/core';
|
||||
import { RuleCompositeCondition } from '../../model/rule-composite-condition.model';
|
||||
import { ControlValueAccessor, FormArray, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { RuleSimpleCondition } from '../../model/rule-simple-condition.model';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-rule-composite-condition',
|
||||
templateUrl: './rule-composite-condition.ui-component.html',
|
||||
styleUrls: ['./rule-composite-condition.ui-component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'aca-rule-composite-condition' },
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
multi: true,
|
||||
useExisting: forwardRef(() => RuleCompositeConditionUiComponent)
|
||||
}
|
||||
]
|
||||
})
|
||||
export class RuleCompositeConditionUiComponent implements ControlValueAccessor, OnDestroy {
|
||||
@HostBinding('class.secondaryBackground')
|
||||
@Input()
|
||||
secondaryBackground = false;
|
||||
@HostBinding('class.childCompositeCondition')
|
||||
@Input()
|
||||
childCondition = false;
|
||||
|
||||
form = new FormGroup({
|
||||
inverted: new FormControl(),
|
||||
booleanMode: new FormControl(),
|
||||
compositeConditions: new FormArray([]),
|
||||
simpleConditions: new FormArray([])
|
||||
});
|
||||
|
||||
private formSubscription = this.form.valueChanges.subscribe((value) => {
|
||||
this.onChange(value);
|
||||
this.onTouch();
|
||||
});
|
||||
|
||||
get invertedControl(): FormControl {
|
||||
return this.form.get('inverted') as FormControl;
|
||||
}
|
||||
get booleanModeControl(): FormControl {
|
||||
return this.form.get('booleanMode') as FormControl;
|
||||
}
|
||||
get compositeConditionsFormArray(): FormArray {
|
||||
return this.form.get('compositeConditions') as FormArray;
|
||||
}
|
||||
get simpleConditionsFormArray(): FormArray {
|
||||
return this.form.get('simpleConditions') as FormArray;
|
||||
}
|
||||
get conditionFormControls(): FormControl[] {
|
||||
return [...(this.compositeConditionsFormArray.controls as FormControl[]), ...(this.simpleConditionsFormArray.controls as FormControl[])];
|
||||
}
|
||||
get hasNoConditions(): boolean {
|
||||
return this.conditionFormControls.length === 0;
|
||||
}
|
||||
|
||||
private _readOnly = false;
|
||||
get readOnly(): boolean {
|
||||
return this._readOnly;
|
||||
}
|
||||
|
||||
onChange: (condition: RuleCompositeCondition) => void = () => undefined;
|
||||
onTouch: () => void = () => undefined;
|
||||
|
||||
writeValue(value: RuleCompositeCondition) {
|
||||
this.form.get('inverted').setValue(value.inverted);
|
||||
this.form.get('booleanMode').setValue(value.booleanMode);
|
||||
this.form.setControl('compositeConditions', new FormArray(value.compositeConditions.map((condition) => new FormControl(condition))));
|
||||
this.form.setControl('simpleConditions', new FormArray(value.simpleConditions.map((condition) => new FormControl(condition))));
|
||||
}
|
||||
|
||||
registerOnChange(fn: () => void) {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void) {
|
||||
this.onTouch = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
if (isDisabled) {
|
||||
this._readOnly = true;
|
||||
this.form.disable();
|
||||
} else {
|
||||
this._readOnly = false;
|
||||
this.form.enable();
|
||||
}
|
||||
}
|
||||
|
||||
setInverted(value: boolean) {
|
||||
this.invertedControl.setValue(value);
|
||||
}
|
||||
|
||||
setBooleanMode(value: 'and' | 'or') {
|
||||
this.booleanModeControl.setValue(value);
|
||||
}
|
||||
|
||||
isFormControlSimpleCondition(control: FormControl): boolean {
|
||||
return control.value.hasOwnProperty('field');
|
||||
}
|
||||
|
||||
removeCondition(control: FormControl) {
|
||||
const formArray = this.isFormControlSimpleCondition(control) ? this.simpleConditionsFormArray : this.compositeConditionsFormArray;
|
||||
const index = (formArray.value as FormControl[]).indexOf(control.value);
|
||||
formArray.removeAt(index);
|
||||
}
|
||||
|
||||
addSimpleCondition() {
|
||||
const newCondition: RuleSimpleCondition = {
|
||||
field: 'cm:name',
|
||||
comparator: 'equals',
|
||||
parameter: ''
|
||||
};
|
||||
this.simpleConditionsFormArray.push(new FormControl(newCondition));
|
||||
}
|
||||
|
||||
addCompositeCondition() {
|
||||
const newCondition: RuleCompositeCondition = {
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
};
|
||||
this.compositeConditionsFormArray.push(new FormControl(newCondition));
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.formSubscription.unsubscribe();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { RuleCompositeCondition } from '../../model/rule-composite-condition.model';
|
||||
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||||
|
||||
const isCompositeConditionValid = (value: RuleCompositeCondition, isRootCondition = true): boolean => {
|
||||
if (value.compositeConditions.length > 0) {
|
||||
return value.compositeConditions.reduce(
|
||||
(arrayValid: boolean, nestedCondition: RuleCompositeCondition) => arrayValid && isCompositeConditionValid(nestedCondition, false),
|
||||
true
|
||||
);
|
||||
}
|
||||
return !!value.simpleConditions.length || isRootCondition;
|
||||
};
|
||||
|
||||
export const ruleCompositeConditionValidator =
|
||||
(): ValidatorFn =>
|
||||
(control: AbstractControl): ValidationErrors | null =>
|
||||
isCompositeConditionValid(control.value) ? null : { ruleCompositeConditionInvalid: true };
|
@ -0,0 +1,95 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface RuleConditionComparator {
|
||||
name: string;
|
||||
labels: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const ruleConditionComparators: RuleConditionComparator[] = [
|
||||
{
|
||||
name: 'equals',
|
||||
labels: {
|
||||
string: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.EQUALS',
|
||||
number: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.EQUALS',
|
||||
date: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.ON',
|
||||
special: ''
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'contains',
|
||||
labels: {
|
||||
string: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.CONTAINS'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'startsWith',
|
||||
labels: {
|
||||
string: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.STARTS_WITH'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'endsWith',
|
||||
labels: {
|
||||
string: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.ENDS_WITH'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'greaterThan',
|
||||
labels: {
|
||||
number: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.GREATER_THAN',
|
||||
date: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.AFTER'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'lessThan',
|
||||
labels: {
|
||||
number: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.LESS_THAN',
|
||||
date: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.BEFORE'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'greaterThanOrEqual',
|
||||
labels: {
|
||||
number: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.GREATER_THAN_OR_EQUAL',
|
||||
date: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.ON_OR_AFTER'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'lessThanOrEqual',
|
||||
labels: {
|
||||
number: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.LESS_THAN_OR_EQUAL',
|
||||
date: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.ON_OR_BEFORE'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'instanceOf',
|
||||
labels: {
|
||||
type: 'ACA_FOLDER_RULES.RULE_DETAILS.COMPARATORS.INSTANCE_OF'
|
||||
}
|
||||
}
|
||||
];
|
@ -0,0 +1,70 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export type RuleConditionFieldType = 'string' | 'number' | 'date' | 'type' | 'special';
|
||||
|
||||
export interface RuleConditionField {
|
||||
name: string;
|
||||
label: string;
|
||||
type: RuleConditionFieldType;
|
||||
}
|
||||
|
||||
export const ruleConditionFields: RuleConditionField[] = [
|
||||
{
|
||||
name: 'cm:name',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.NAME',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.SIZE',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'mimetype',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.MIMETYPE',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'encoding',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.ENCODING',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_CATEGORY',
|
||||
type: 'special'
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_TAG',
|
||||
type: 'special'
|
||||
},
|
||||
{
|
||||
name: 'aspect',
|
||||
label: 'ACA_FOLDER_RULES.RULE_DETAILS.FIELDS.HAS_ASPECT',
|
||||
type: 'special'
|
||||
}
|
||||
];
|
@ -0,0 +1,24 @@
|
||||
<form class="aca-rule-simple-condition__form" [formGroup]="form">
|
||||
<mat-form-field class="aca-rule-simple-condition__form__field-input">
|
||||
<mat-select formControlName="field" data-automation-id="field-select"
|
||||
(selectionChange)="onChangeField()">
|
||||
<mat-option *ngFor="let field of fields" [value]="field.name">
|
||||
{{ field.label | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="aca-rule-simple-condition__form__comparator-input" [class]="{ hidden: isComparatorHidden }" data-automation-id="comparator-form-field">
|
||||
<mat-select formControlName="comparator" data-automation-id="comparator-select">
|
||||
<mat-option
|
||||
*ngFor="let comparator of selectedFieldComparators"
|
||||
[value]="comparator.name">
|
||||
{{ comparator.labels[this.selectedField?.type || 'equals'] | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field class="aca-rule-simple-condition__form__parameter-input">
|
||||
<input matInput type="text" formControlName="parameter" data-automation-id="value-input">
|
||||
</mat-form-field>
|
||||
</form>
|
@ -0,0 +1,18 @@
|
||||
.aca-rule-simple-condition {
|
||||
&__form {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
|
||||
mat-form-field {
|
||||
flex: 2;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
&__comparator-input {
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RuleSimpleConditionUiComponent } from './rule-simple-condition.ui-component';
|
||||
import { CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
describe('RuleSimpleConditionUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleSimpleConditionUiComponent>;
|
||||
|
||||
const getByDataAutomationId = (dataAutomationId: string): DebugElement =>
|
||||
fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`));
|
||||
|
||||
const changeMatSelectValue = (dataAutomationId: string, value: string) => {
|
||||
const matSelect = getByDataAutomationId(dataAutomationId).nativeElement;
|
||||
matSelect.click();
|
||||
fixture.detectChanges();
|
||||
const matOption = fixture.debugElement.query(By.css(`.mat-option[ng-reflect-value="${value}"]`)).nativeElement;
|
||||
matOption.click();
|
||||
fixture.detectChanges();
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule],
|
||||
declarations: [RuleSimpleConditionUiComponent]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RuleSimpleConditionUiComponent);
|
||||
});
|
||||
|
||||
it('should default the field to the name, the comparator to equals and the value empty', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(getByDataAutomationId('field-select').componentInstance.value).toBe('cm:name');
|
||||
expect(getByDataAutomationId('comparator-select').componentInstance.value).toBe('equals');
|
||||
expect(getByDataAutomationId('value-input').nativeElement.value).toBe('');
|
||||
});
|
||||
|
||||
it('should hide the comparator select box if the type of the field is special', () => {
|
||||
fixture.detectChanges();
|
||||
const comparatorFormField = getByDataAutomationId('comparator-form-field').nativeElement;
|
||||
|
||||
expect(fixture.componentInstance.isComparatorHidden).toBeFalsy();
|
||||
expect(getComputedStyle(comparatorFormField).display).not.toBe('none');
|
||||
|
||||
changeMatSelectValue('field-select', 'category');
|
||||
|
||||
expect(fixture.componentInstance.isComparatorHidden).toBeTruthy();
|
||||
expect(getComputedStyle(comparatorFormField).display).toBe('none');
|
||||
});
|
||||
|
||||
it('should set the comparator to equals if the field is set to a type with different comparators', () => {
|
||||
const onChangeFieldSpy = spyOn(fixture.componentInstance, 'onChangeField').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
changeMatSelectValue('comparator-select', 'contains');
|
||||
|
||||
expect(getByDataAutomationId('comparator-select').componentInstance.value).toBe('contains');
|
||||
changeMatSelectValue('field-select', 'mimetype');
|
||||
|
||||
expect(onChangeFieldSpy).toHaveBeenCalledTimes(1);
|
||||
expect(getByDataAutomationId('comparator-select').componentInstance.value).toBe('contains');
|
||||
changeMatSelectValue('field-select', 'size');
|
||||
|
||||
expect(onChangeFieldSpy).toHaveBeenCalledTimes(2);
|
||||
expect(getByDataAutomationId('comparator-select').componentInstance.value).toBe('equals');
|
||||
});
|
||||
});
|
@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, forwardRef, OnDestroy, ViewEncapsulation } from '@angular/core';
|
||||
import { AbstractControl, ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { RuleSimpleCondition } from '../../model/rule-simple-condition.model';
|
||||
import { RuleConditionField, ruleConditionFields } from './rule-condition-fields';
|
||||
import { RuleConditionComparator, ruleConditionComparators } from './rule-condition-comparators';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-rule-simple-condition',
|
||||
templateUrl: './rule-simple-condition.ui-component.html',
|
||||
styleUrls: ['./rule-simple-condition.ui-component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'aca-rule-simple-condition' },
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
multi: true,
|
||||
useExisting: forwardRef(() => RuleSimpleConditionUiComponent)
|
||||
}
|
||||
]
|
||||
})
|
||||
export class RuleSimpleConditionUiComponent implements ControlValueAccessor, OnDestroy {
|
||||
readonly fields = ruleConditionFields;
|
||||
|
||||
form = new FormGroup({
|
||||
field: new FormControl('cm:name'),
|
||||
comparator: new FormControl('equals'),
|
||||
parameter: new FormControl()
|
||||
});
|
||||
|
||||
private formSubscription = this.form.valueChanges.subscribe((value) => {
|
||||
this.onChange(value);
|
||||
this.onTouch();
|
||||
});
|
||||
|
||||
get selectedField(): RuleConditionField {
|
||||
return this.fields.find((field) => field.name === this.form.get('field').value);
|
||||
}
|
||||
get selectedFieldComparators(): RuleConditionComparator[] {
|
||||
return ruleConditionComparators.filter((comparator) => Object.keys(comparator.labels).includes(this.selectedField.type));
|
||||
}
|
||||
get isComparatorHidden(): boolean {
|
||||
return this.selectedField?.type === 'special';
|
||||
}
|
||||
get comparatorControl(): AbstractControl {
|
||||
return this.form.get('comparator');
|
||||
}
|
||||
|
||||
onChange: (condition: RuleSimpleCondition) => void = () => undefined;
|
||||
onTouch: () => void = () => undefined;
|
||||
|
||||
writeValue(value: RuleSimpleCondition) {
|
||||
this.form.setValue(value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: () => void) {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: () => void) {
|
||||
this.onTouch = fn;
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
if (isDisabled) {
|
||||
this.form.disable();
|
||||
} else {
|
||||
this.form.enable();
|
||||
}
|
||||
}
|
||||
|
||||
onChangeField() {
|
||||
if (!this.selectedFieldComparators.find((comparator) => comparator.name === this.comparatorControl.value)) {
|
||||
this.comparatorControl.setValue('equals');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.formSubscription.unsubscribe();
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import { By } from '@angular/platform-browser';
|
||||
import { RuleDetailsUiComponent } from './rule-details.ui-component';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { RuleCompositeConditionUiComponent } from './conditions/rule-composite-condition.ui-component';
|
||||
|
||||
describe('EditRuleDialogComponent', () => {
|
||||
let fixture: ComponentFixture<EditRuleDialogSmartComponent>;
|
||||
@ -41,7 +42,7 @@ describe('EditRuleDialogComponent', () => {
|
||||
const setupBeforeEach = (dialogOptions: EditRuleDialogOptions = {}) => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule],
|
||||
declarations: [EditRuleDialogSmartComponent, RuleDetailsUiComponent],
|
||||
declarations: [EditRuleDialogSmartComponent, RuleCompositeConditionUiComponent, RuleDetailsUiComponent],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: dialogRef },
|
||||
{ provide: MAT_DIALOG_DATA, useValue: dialogOptions }
|
||||
@ -105,7 +106,7 @@ describe('EditRuleDialogComponent', () => {
|
||||
expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE');
|
||||
});
|
||||
|
||||
it('should show a "create" label in the submit button', () => {
|
||||
it('should show an "update" label in the submit button', () => {
|
||||
fixture.detectChanges();
|
||||
const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement;
|
||||
|
||||
|
@ -24,4 +24,9 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<aca-rule-composite-condition formControlName="conditions"></aca-rule-composite-condition>
|
||||
<mat-error>{{ getErrorMessage(conditions) | translate }}</mat-error>
|
||||
</form>
|
||||
|
@ -33,12 +33,17 @@
|
||||
border-bottom: 1px solid var(--theme-border-color);
|
||||
}
|
||||
|
||||
*:disabled {
|
||||
color: #000000;
|
||||
*:disabled, .mat-select-disabled .mat-select-value {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 4em;
|
||||
}
|
||||
|
||||
& > .aca-rule-composite-condition + .mat-error {
|
||||
font-size: 75%;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import { CoreTestingModule } from '@alfresco/adf-core';
|
||||
import { RuleDetailsUiComponent } from './rule-details.ui-component';
|
||||
import { Rule } from '../model/rule.model';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { RuleCompositeConditionUiComponent } from './conditions/rule-composite-condition.ui-component';
|
||||
|
||||
describe('RuleDetailsUiComponent', () => {
|
||||
let fixture: ComponentFixture<RuleDetailsUiComponent>;
|
||||
@ -45,7 +46,7 @@ describe('RuleDetailsUiComponent', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreTestingModule],
|
||||
declarations: [RuleDetailsUiComponent]
|
||||
declarations: [RuleCompositeConditionUiComponent, RuleDetailsUiComponent]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(RuleDetailsUiComponent);
|
||||
|
@ -24,10 +24,11 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Subject } from 'rxjs';
|
||||
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
|
||||
import { Rule } from '../model/rule.model';
|
||||
import { ruleCompositeConditionValidator } from './conditions/rule-composite-condition.validators';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-rule-details',
|
||||
@ -66,17 +67,26 @@ export class RuleDetailsUiComponent implements OnInit, OnDestroy {
|
||||
get name(): AbstractControl {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
get description(): AbstractControl {
|
||||
return this.form.get('description');
|
||||
}
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {}
|
||||
get conditions(): AbstractControl {
|
||||
return this.form.get('conditions');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this.formBuilder.group({
|
||||
name: [this.initialValue.name || '', Validators.required],
|
||||
description: [this.initialValue.description || '']
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl(this.initialValue.name || '', Validators.required),
|
||||
description: new FormControl(this.initialValue.description || ''),
|
||||
conditions: new FormControl(
|
||||
this.initialValue.conditions || {
|
||||
inverted: false,
|
||||
booleanMode: 'and',
|
||||
compositeConditions: [],
|
||||
simpleConditions: []
|
||||
},
|
||||
ruleCompositeConditionValidator()
|
||||
)
|
||||
});
|
||||
this.readOnly = this._readOnly;
|
||||
|
||||
@ -104,6 +114,8 @@ export class RuleDetailsUiComponent implements OnInit, OnDestroy {
|
||||
getErrorMessage(control: AbstractControl): string {
|
||||
if (control.hasError('required')) {
|
||||
return 'ACA_FOLDER_RULES.RULE_DETAILS.ERROR.REQUIRED';
|
||||
} else if (control.hasError('ruleCompositeConditionInvalid')) {
|
||||
return 'ACA_FOLDER_RULES.RULE_DETAILS.ERROR.RULE_COMPOSITE_CONDITION_INVALID';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user