diff --git a/app/src/app/services/content-management.service.ts b/app/src/app/services/content-management.service.ts index f3d171033..7375ad0e7 100644 --- a/app/src/app/services/content-management.service.ts +++ b/app/src/app/services/content-management.service.ts @@ -74,6 +74,7 @@ import { forkJoin, Observable, of, zip } from 'rxjs'; import { catchError, map, mergeMap, take, tap } from 'rxjs/operators'; import { NodeActionsService } from './node-actions.service'; import { Router } from '@angular/router'; +import { EditRuleDialogSmartComponent } from '@alfresco/aca-folder-rules'; interface RestoredNode { status: number; @@ -1078,4 +1079,13 @@ export class ContentManagementService { .onAction() .subscribe(() => this.undoMoveNodes(moveResponse, initialParentId)); } + + manageRules(node: any) { + if (node && node.entry) { + this.dialogRef.open(EditRuleDialogSmartComponent, { + minWidth: '70%', + panelClass: 'aca-edit-rule-dialog-container' + }); + } + } } diff --git a/app/src/app/store/effects/node.effects.ts b/app/src/app/store/effects/node.effects.ts index 95d095169..c94d98b32 100644 --- a/app/src/app/store/effects/node.effects.ts +++ b/app/src/app/store/effects/node.effects.ts @@ -48,7 +48,8 @@ import { getAppSelection, ManageAspectsAction, NavigateRouteAction, - ExpandInfoDrawerAction + ExpandInfoDrawerAction, + ManageRulesAction } from '@alfresco/aca-shared/store'; import { ContentManagementService } from '../../services/content-management.service'; import { ViewUtilService } from '@alfresco/adf-core'; @@ -420,4 +421,26 @@ export class NodeEffects { } } } + + manageRules$ = createEffect( + () => + this.actions$.pipe( + ofType(NodeActionTypes.ManageRules), + map((action) => { + if (action && action.payload) { + this.contentService.manageRules(action.payload); + } else { + this.store + .select(getAppSelection) + .pipe(take(1)) + .subscribe((selection) => { + if (selection && !selection.isEmpty) { + this.contentService.manageRules(selection.nodes[0]); + } + }); + } + }) + ), + { dispatch: false } + ); } diff --git a/projects/aca-folder-rules/assets/i18n/en.json b/projects/aca-folder-rules/assets/i18n/en.json index bd3a3294c..0df730e3a 100644 --- a/projects/aca-folder-rules/assets/i18n/en.json +++ b/projects/aca-folder-rules/assets/i18n/en.json @@ -5,6 +5,27 @@ "CREATE_RULES_DESC": "[tbd] Creates new rules", "LINK_RULES": "Link to rules set", "LINK_RULES_DESC": "[tbd] Link to existing rules" + }, + "EDIT_RULE_DIALOG": { + "CANCEL": "Cancel", + "CREATE": "Create", + "CREATE_TITLE": "Create a rule", + "UPDATE": "Update", + "UPDATE_TITLE": "Update a rule" + }, + "RULE_DETAILS": { + "LABEL": { + "NAME": "Name", + "DESCRIPTION": "Description" + }, + "PLACEHOLDER": { + "NAME": "Enter rule name", + "DESCRIPTION": "Enter rule description", + "NO_DESCRIPTION": "No description" + }, + "ERROR": { + "REQUIRED": "This field is required" + } } } } diff --git a/projects/aca-folder-rules/src/lib/folder-rules.module.ts b/projects/aca-folder-rules/src/lib/folder-rules.module.ts index dde6be5d5..076e607f0 100644 --- a/projects/aca-folder-rules/src/lib/folder-rules.module.ts +++ b/projects/aca-folder-rules/src/lib/folder-rules.module.ts @@ -23,13 +23,19 @@ * along with Alfresco. If not, see . */ -import { TranslationService } from '@alfresco/adf-core'; +import { CoreModule, TranslationService } from '@alfresco/adf-core'; import { ExtensionService, provideExtensionConfig } from '@alfresco/adf-extensions'; import { NgModule } from '@angular/core'; import * as rules from './folder-rules.rules'; +import { CommonModule } from '@angular/common'; + +import { EditRuleDialogSmartComponent } from './rule-details/edit-rule-dialog.smart-component'; +import { RuleDetailsUiComponent } from './rule-details/rule-details.ui-component'; @NgModule({ - providers: [provideExtensionConfig(['folder-rules.plugin.json'])] + providers: [provideExtensionConfig(['folder-rules.plugin.json'])], + imports: [CommonModule, CoreModule.forChild()], + declarations: [EditRuleDialogSmartComponent, RuleDetailsUiComponent] }) export class AcaFolderRulesModule { constructor(translation: TranslationService, extensions: ExtensionService) { diff --git a/projects/aca-folder-rules/src/lib/model/rule-composite-condition.model.ts b/projects/aca-folder-rules/src/lib/model/rule-composite-condition.model.ts new file mode 100644 index 000000000..612e095de --- /dev/null +++ b/projects/aca-folder-rules/src/lib/model/rule-composite-condition.model.ts @@ -0,0 +1,33 @@ +/*! + * @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 . + */ + +import { RuleSimpleCondition } from './rule-simple-condition.model'; + +export interface RuleCompositeCondition { + inverted: boolean; + booleanMode: 'and' | 'or'; + compositeConditions: RuleCompositeCondition[]; + simpleConditions: RuleSimpleCondition[]; +} diff --git a/projects/aca-folder-rules/src/lib/model/rule-simple-condition.model.ts b/projects/aca-folder-rules/src/lib/model/rule-simple-condition.model.ts new file mode 100644 index 000000000..04784baae --- /dev/null +++ b/projects/aca-folder-rules/src/lib/model/rule-simple-condition.model.ts @@ -0,0 +1,30 @@ +/*! + * @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 . + */ + +export interface RuleSimpleCondition { + field: string; + comparator: string; + parameter: string; +} diff --git a/projects/aca-folder-rules/src/lib/model/rule.model.ts b/projects/aca-folder-rules/src/lib/model/rule.model.ts new file mode 100644 index 000000000..8463cc8f3 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/model/rule.model.ts @@ -0,0 +1,40 @@ +/*! + * @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 . + */ + +import { RuleCompositeCondition } from './rule-composite-condition.model'; + +export interface Rule { + id: string; + name: string; + description: string; + enabled: boolean; + cascade: boolean; + asynchronous: boolean; + errorScript: string; + shared: boolean; + triggers: ('inbound' | 'update' | 'outbound')[]; + conditions: RuleCompositeCondition; + actions: string[]; +} diff --git a/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.html b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.html new file mode 100644 index 000000000..f1200c313 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.html @@ -0,0 +1,17 @@ +
+
+ {{ title | translate }} +
+ +
+ + + + + + + + + diff --git a/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.scss b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.scss new file mode 100644 index 000000000..2c78b0b0e --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.scss @@ -0,0 +1,42 @@ +.aca-edit-rule-dialog-container { + --edit-rule-dialog-padding: 8px 20px; + + .mat-dialog-container { + padding: 0; + } +} + +.aca-edit-rule-dialog { + &__header { + display: flex; + align-items: center; + margin: 0; + padding: var(--edit-rule-dialog-padding); + box-sizing: border-box; + border-bottom: 1px solid var(--theme-border-color); + + &__title { + font-size: 16px; + font-weight: bold; + flex-grow: 1; + } + + &__close { + & mat-icon { + font-size: 18px; + } + } + } + + &__content { + margin: 0; + padding: 0; + } + + &__footer { + margin: 0; + padding: var(--edit-rule-dialog-padding); + box-sizing: border-box; + border-top: 1px solid var(--theme-border-color); + } +} diff --git a/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.spec.ts b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.spec.ts new file mode 100644 index 000000000..84fc7f947 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.spec.ts @@ -0,0 +1,115 @@ +/*! + * @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 . + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { EditRuleDialogOptions, EditRuleDialogSmartComponent } from './edit-rule-dialog.smart-component'; +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'; + +describe('EditRuleDialogComponent', () => { + let fixture: ComponentFixture; + + const dialogRef = { + close: jasmine.createSpy('close'), + open: jasmine.createSpy('open') + }; + + const setupBeforeEach = (dialogOptions: EditRuleDialogOptions = {}) => { + TestBed.configureTestingModule({ + imports: [CoreTestingModule], + declarations: [EditRuleDialogSmartComponent, RuleDetailsUiComponent], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA, useValue: dialogOptions } + ] + }); + + fixture = TestBed.createComponent(EditRuleDialogSmartComponent); + }; + + describe('No dialog options passed / indifferent', () => { + beforeEach(() => { + setupBeforeEach(); + }); + + it('should activate the submit button only when a valid state is received', () => { + fixture.detectChanges(); + const submitButton = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement; + const ruleDetails = fixture.debugElement.query(By.directive(RuleDetailsUiComponent)).componentInstance as RuleDetailsUiComponent; + ruleDetails.formValidationChanged.emit(true); + + fixture.detectChanges(); + expect(submitButton.disabled).toBeFalsy(); + ruleDetails.formValidationChanged.emit(false); + + fixture.detectChanges(); + expect(submitButton.disabled).toBeTruthy(); + }); + + it('should show a "create" label in the title', () => { + fixture.detectChanges(); + const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-title"]')).nativeElement as HTMLDivElement; + + expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE_TITLE'); + }); + + it('should show a "create" label in the submit button', () => { + fixture.detectChanges(); + const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement; + + expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.CREATE'); + }); + }); + + describe('With dialog options passed', () => { + const dialogOptions: EditRuleDialogOptions = { + model: { + id: 'rule-id', + name: 'Rule name', + description: 'This is the description of the rule' + } + }; + + beforeEach(() => { + setupBeforeEach(dialogOptions); + }); + + it('should show an "update" label in the title', () => { + fixture.detectChanges(); + const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-title"]')).nativeElement as HTMLDivElement; + + expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE_TITLE'); + }); + + it('should show a "create" label in the submit button', () => { + fixture.detectChanges(); + const titleElement = fixture.debugElement.query(By.css('[data-automation-id="edit-rule-dialog-submit"]')).nativeElement as HTMLButtonElement; + + expect(titleElement.innerText.trim()).toBe('ACA_FOLDER_RULES.EDIT_RULE_DIALOG.UPDATE'); + }); + }); +}); diff --git a/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.ts b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.ts new file mode 100644 index 000000000..57c33de4d --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/edit-rule-dialog.smart-component.ts @@ -0,0 +1,60 @@ +/*! + * @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 . + */ + +import { Component, Inject, ViewEncapsulation } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Rule } from '../model/rule.model'; + +export interface EditRuleDialogOptions { + model?: Partial; +} + +@Component({ + selector: 'aca-edit-rule-dialog', + templateUrl: './edit-rule-dialog.smart-component.html', + styleUrls: ['./edit-rule-dialog.smart-component.scss'], + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-edit-rule-dialog' } +}) +export class EditRuleDialogSmartComponent { + formValid = false; + model: Partial; + + constructor(@Inject(MAT_DIALOG_DATA) public options: EditRuleDialogOptions) { + this.model = this.options?.model || {}; + } + + get isUpdateMode(): boolean { + return !!this.options?.model?.id; + } + + get title(): string { + return 'ACA_FOLDER_RULES.EDIT_RULE_DIALOG.' + (this.isUpdateMode ? 'UPDATE_TITLE' : 'CREATE_TITLE'); + } + + get submitLabel(): string { + return 'ACA_FOLDER_RULES.EDIT_RULE_DIALOG.' + (this.isUpdateMode ? 'UPDATE' : 'CREATE'); + } +} diff --git a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.html b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.html new file mode 100644 index 000000000..492cacfd8 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.html @@ -0,0 +1,27 @@ +
+
+ +
+ + + {{ getErrorMessage(name) | translate }} + +
+
+ +
+ +
+ + + +
+
+
diff --git a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.scss b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.scss new file mode 100644 index 000000000..ac2d8cccf --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.scss @@ -0,0 +1,44 @@ +.aca-rule-details { + &__form { + padding: 20px; + + &__row { + display: flex; + gap: 8px; + + & > label { + font-weight: bold; + width: 20%; + min-width: 100px; + max-width: 150px; + padding-top: 0.75em; + } + + & > div { + flex-grow: 1; + + mat-form-field { + width: 100%; + font-size: inherit; + + .mat-form-field-infix { + border: none; + } + } + } + } + + hr { + border: none; + border-bottom: 1px solid var(--theme-border-color); + } + + *:disabled { + color: #000000; + } + + textarea { + min-height: 4em; + } + } +} diff --git a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.spec.ts b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.spec.ts new file mode 100644 index 000000000..2368a33a9 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.spec.ts @@ -0,0 +1,87 @@ +/*! + * @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 . + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; +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'; + +describe('RuleDetailsUiComponent', () => { + let fixture: ComponentFixture; + let component: RuleDetailsUiComponent; + + const initialValue: Partial = { + id: 'rule-id', + name: 'Rule name', + description: 'This is the description of the rule' + }; + + const getHtmlElement = (dataAutomationId: string) => + fixture.debugElement.query(By.css(`[data-automation-id="${dataAutomationId}"]`)).nativeElement as T; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [CoreTestingModule], + declarations: [RuleDetailsUiComponent] + }); + + fixture = TestBed.createComponent(RuleDetailsUiComponent); + component = fixture.componentInstance; + }); + + it('should fill the form out with initial values', () => { + component.initialValue = initialValue; + fixture.detectChanges(); + + const nameInput = getHtmlElement('rule-details-name-input'); + const descriptionTextarea = getHtmlElement('rule-details-description-textarea'); + + expect(nameInput.value).toBe(initialValue.name); + expect(descriptionTextarea.value).toBe(initialValue.description); + }); + + it('should be editable if not read-only', () => { + component.readOnly = false; + fixture.detectChanges(); + + const nameInput = getHtmlElement('rule-details-name-input'); + const descriptionTextarea = getHtmlElement('rule-details-description-textarea'); + + expect(nameInput.disabled).toBeFalsy(); + expect(descriptionTextarea.disabled).toBeFalsy(); + }); + + it('should not be editable if read-only', () => { + component.readOnly = true; + fixture.detectChanges(); + + const nameInput = getHtmlElement('rule-details-name-input'); + const descriptionTextarea = getHtmlElement('rule-details-description-textarea'); + + expect(nameInput.disabled).toBeTruthy(); + expect(descriptionTextarea.disabled).toBeTruthy(); + }); +}); diff --git a/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts new file mode 100644 index 000000000..1ba61a9d8 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-details/rule-details.ui-component.ts @@ -0,0 +1,125 @@ +/*! + * @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 . + */ + +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; +import { Rule } from '../model/rule.model'; + +@Component({ + selector: 'aca-rule-details', + templateUrl: './rule-details.ui-component.html', + styleUrls: ['./rule-details.ui-component.scss'], + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-rule-details' } +}) +export class RuleDetailsUiComponent implements OnInit, OnDestroy { + private _readOnly = false; + @Input() + get readOnly(): boolean { + return this._readOnly; + } + set readOnly(value: boolean) { + this._readOnly = value; + if (this.form?.disable) { + if (value) { + this.form.disable(); + } else { + this.form.enable(); + } + } + } + @Input() + initialValue: Partial = {}; + + @Output() + formValidationChanged = new EventEmitter(); + @Output() + formValueChanged = new EventEmitter>(); + + private onDestroy$ = new Subject(); + form: FormGroup; + + get name(): AbstractControl { + return this.form.get('name'); + } + + get description(): AbstractControl { + return this.form.get('description'); + } + + constructor(private formBuilder: FormBuilder) {} + + ngOnInit() { + this.form = this.formBuilder.group({ + name: [this.initialValue.name || '', Validators.required], + description: [this.initialValue.description || ''] + }); + this.readOnly = this._readOnly; + + this.form.statusChanges + .pipe( + map(() => this.form.valid), + distinctUntilChanged(), + takeUntil(this.onDestroy$) + ) + .subscribe((value: boolean) => { + this.formValidationChanged.emit(value); + }); + this.formValidationChanged.emit(this.form.valid); + + this.form.valueChanges.pipe(takeUntil(this.onDestroy$)).subscribe((newFormValue: any) => { + this.formValueChanged.emit(newFormValue); + }); + } + + ngOnDestroy() { + this.onDestroy$.next(); + this.onDestroy$.complete(); + } + + getErrorMessage(control: AbstractControl): string { + if (control.hasError('required')) { + return 'ACA_FOLDER_RULES.RULE_DETAILS.ERROR.REQUIRED'; + } + return ''; + } + + getPlaceholder(fieldName: string): string { + let str = 'ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.'; + switch (fieldName) { + case 'name': + str += 'NAME'; + break; + case 'description': + str += this.readOnly ? 'NO_DESCRIPTION' : 'DESCRIPTION'; + break; + default: + return ''; + } + return str; + } +} diff --git a/projects/aca-folder-rules/src/public-api.ts b/projects/aca-folder-rules/src/public-api.ts index f488315ed..0e6c9b3d6 100644 --- a/projects/aca-folder-rules/src/public-api.ts +++ b/projects/aca-folder-rules/src/public-api.ts @@ -24,3 +24,4 @@ */ export * from './lib/folder-rules.module'; +export { EditRuleDialogSmartComponent } from './lib/rule-details/edit-rule-dialog.smart-component'; diff --git a/projects/aca-shared/store/src/actions/node.actions.ts b/projects/aca-shared/store/src/actions/node.actions.ts index b482d6c63..e17ac7385 100644 --- a/projects/aca-shared/store/src/actions/node.actions.ts +++ b/projects/aca-shared/store/src/actions/node.actions.ts @@ -47,7 +47,8 @@ export enum NodeActionTypes { AddFavorite = 'ADD_FAVORITE', RemoveFavorite = 'REMOVE_FAVORITE', ChangeAspects = 'ASPECT_LIST', - ExpandInfoDrawer = 'EXPAND_INFO_DRAWER' + ExpandInfoDrawer = 'EXPAND_INFO_DRAWER', + ManageRules = 'MANAGE_RULES' } export class SetSelectedNodesAction implements Action { @@ -173,3 +174,9 @@ export class ManageAspectsAction implements Action { constructor(public payload: MinimalNodeEntity) {} } + +export class ManageRulesAction implements Action { + readonly type = NodeActionTypes.ManageRules; + + constructor(public payload: MinimalNodeEntity) {} +}