From d9d2441b3a79219220a121983eff765861b994d3 Mon Sep 17 00:00:00 2001 From: Thomas Hunter Date: Thu, 24 Nov 2022 15:37:01 +0000 Subject: [PATCH] [ACS-3513] [ACS-3515] Create, edit and delete rule set link (#2810) --- projects/aca-folder-rules/assets/i18n/en.json | 21 ++++ .../src/lib/folder-rules.module.ts | 7 +- .../manage-rules.smart-component.html | 27 ++-- .../manage-rules.smart-component.scss | 6 + .../manage-rules.smart-component.ts | 42 +++++++ .../edit-rule-dialog.smart-component.spec.ts | 6 +- .../edit-rule-dialog.smart-component.ts | 3 +- .../rule-list-grouping.ui-component.html | 1 + .../rule-list-grouping.ui-component.spec.ts | 2 - .../rule-list-grouping.ui-component.ts | 2 + .../rule-list-item.ui-component.html | 1 + .../rule-list-item.ui-component.ts | 2 + .../rule-list/rule-list.ui-component.html | 61 +++++---- .../rule-list/rule-list.ui-component.scss | 18 ++- .../rule-list/rule-list.ui-component.spec.ts | 6 +- .../rule-list/rule-list.ui-component.ts | 14 +++ .../rule-set-picker.smart-component.html | 59 +++++++++ .../rule-set-picker.smart-component.scss | 76 ++++++++++++ .../rule-set-picker.smart-component.ts | 116 ++++++++++++++++++ .../lib/services/folder-rule-sets.service.ts | 45 ++++--- 20 files changed, 439 insertions(+), 76 deletions(-) create mode 100644 projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.html create mode 100644 projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.scss create mode 100644 projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.ts diff --git a/projects/aca-folder-rules/assets/i18n/en.json b/projects/aca-folder-rules/assets/i18n/en.json index 9ead4a3eb5..18b93d4031 100644 --- a/projects/aca-folder-rules/assets/i18n/en.json +++ b/projects/aca-folder-rules/assets/i18n/en.json @@ -93,6 +93,7 @@ }, "ACTIONS": { "CREATE_RULE": "Create rule", + "LINK_RULES": "Link rules", "EDIT_RULE": "Edit", "SEE_IN_FOLDER": "See in folder" } @@ -106,6 +107,10 @@ "DELETE_RULE": { "TITLE": "Delete rule", "MESSAGE": "Are you sure you want to delete this rule?" + }, + "DELETE_RULE_SET_LINK": { + "TITLE": "Delete rule set link", + "MESSAGE": "Are you sure you want to delete the link to this rule set?" } }, "RULE_LIST": { @@ -116,6 +121,22 @@ "LOAD_MORE_RULES": "Load more rules", "LOADING_RULES": "Loading rules", "INHERITED_RULES_WILL_BE_RUN_FIRST": "Inherited rules will be run first" + }, + "LINK_RULES_DIALOG": { + "TITLE": "Select a folder to link rules from", + "CANCEL": "Cancel", + "SUBMIT": "Select folder", + "EMPTY_RULES_LIST": { + "TITLE": "No owned rules", + "SUBTITLE": "The selected folder doesn't have any rules of its own." + }, + "LIST_OF_RULES_TO_LINK": "List of rules that will be linked", + "ERRORS": { + "REQUEST_FAILED": "Error while trying to create a link to a rule set" + } + }, + "ERRORS": { + "DELETE_RULE_SET_LINK_FAILED": "Error while trying to delete a link from a rule set" } } } 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 5b15375048..feea68c8dc 100644 --- a/projects/aca-folder-rules/src/lib/folder-rules.module.ts +++ b/projects/aca-folder-rules/src/lib/folder-rules.module.ts @@ -35,7 +35,7 @@ import { RuleCompositeConditionUiComponent } from './rule-details/conditions/rul import { RuleDetailsUiComponent } from './rule-details/rule-details.ui-component'; import { RuleSimpleConditionUiComponent } from './rule-details/conditions/rule-simple-condition.ui-component'; import { GenericErrorModule, PageLayoutModule } from '@alfresco/aca-shared'; -import { BreadcrumbModule, DocumentListModule } from '@alfresco/adf-content-services'; +import { BreadcrumbModule, ContentNodeSelectorModule, DocumentListModule } from '@alfresco/adf-content-services'; import { RuleListItemUiComponent } from './rule-list/rule-list-item/rule-list-item.ui-component'; import { RuleListGroupingUiComponent } from './rule-list/rule-list-grouping/rule-list-grouping.ui-component'; import { RuleTriggersUiComponent } from './rule-details/triggers/rule-triggers.ui-component'; @@ -43,6 +43,7 @@ import { RuleOptionsUiComponent } from './rule-details/options/rule-options.ui-c import { RuleActionListUiComponent } from './rule-details/actions/rule-action-list.ui-component'; import { RuleActionUiComponent } from './rule-details/actions/rule-action.ui-component'; import { RuleListUiComponent } from './rule-list/rule-list/rule-list.ui-component'; +import { RuleSetPickerSmartComponent } from './rule-set-picker/rule-set-picker.smart-component'; const routes: Routes = [ { @@ -61,7 +62,8 @@ const routes: Routes = [ BreadcrumbModule, DocumentListModule, ExtensionsModule, - GenericErrorModule + GenericErrorModule, + ContentNodeSelectorModule ], declarations: [ EditRuleDialogSmartComponent, @@ -73,6 +75,7 @@ const routes: Routes = [ RuleListGroupingUiComponent, RuleListItemUiComponent, RuleListUiComponent, + RuleSetPickerSmartComponent, RuleSimpleConditionUiComponent, RuleTriggersUiComponent, RuleOptionsUiComponent diff --git a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.html b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.html index f4936bd321..9c8607b626 100644 --- a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.html +++ b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.html @@ -26,13 +26,22 @@ class="aca-manage-rules__actions-bar__title__breadcrumb"> - +
+ + + +
@@ -48,7 +57,9 @@ (loadMoreRuleSets)="onLoadMoreRuleSets()" (loadMoreRules)="onLoadMoreRules($event)" (selectRule)="onSelectRule($event)" - (ruleEnabledChanged)="onRuleEnabledToggle($event[0], $event[1])"> + (ruleEnabledChanged)="onRuleEnabledToggle($event[0], $event[1])" + (ruleSetEditLinkClicked)="openLinkRulesDialog($event)" + (ruleSetUnlinkClicked)="onRuleSetUnlinkClicked($event)">
diff --git a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.scss b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.scss index 5f8e1f209a..f50d24ff34 100644 --- a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.scss +++ b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.scss @@ -13,6 +13,12 @@ margin-left: 18px; } } + + &__buttons { + display: flex; + align-items: stretch; + gap: 4px; + } } &__container { diff --git a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.ts b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.ts index f6822e14a8..04abdc58fd 100644 --- a/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.ts +++ b/projects/aca-folder-rules/src/lib/manage-rules/manage-rules.smart-component.ts @@ -39,6 +39,7 @@ import { ActionDefinitionTransformed } from '../model/rule-action.model'; import { ActionsService } from '../services/actions.service'; import { FolderRuleSetsService } from '../services/folder-rule-sets.service'; import { RuleSet } from '../model/rule-set.model'; +import { RuleSetPickerSmartComponent } from '../rule-set-picker/rule-set-picker.smart-component'; @Component({ selector: 'aca-manage-rules', @@ -184,4 +185,45 @@ export class ManageRulesSmartComponent implements OnInit, OnDestroy { canEditRule(ruleSet: RuleSet): boolean { return !ruleSet || FolderRuleSetsService.isOwnedRuleSet(ruleSet, this.nodeId); } + + openLinkRulesDialog(existingRuleSet?: RuleSet) { + this.matDialogService + .open(RuleSetPickerSmartComponent, { + width: '90%', + panelClass: 'aca-rule-set-picker-container', + data: { + nodeId: this.nodeId, + defaultNodeId: this.nodeId, + existingRuleSet + } + }) + .afterClosed() + .subscribe((result) => { + if (result) { + this.folderRuleSetsService.refreshMainRuleSet(); + } + }); + } + + onRuleSetUnlinkClicked(linkedRuleSet: RuleSet) { + this.matDialogService + .open(ConfirmDialogComponent, { + data: { + title: 'ACA_FOLDER_RULES.CONFIRMATION_DIALOG.DELETE_RULE_SET_LINK.TITLE', + message: 'ACA_FOLDER_RULES.CONFIRMATION_DIALOG.DELETE_RULE_SET_LINK.MESSAGE' + }, + minWidth: '346px' + }) + .afterClosed() + .subscribe(async (result) => { + if (result) { + try { + await this.folderRuleSetsService.deleteRuleSetLink(this.nodeId, linkedRuleSet.id); + this.folderRuleSetsService.refreshMainRuleSet(); + } catch (error) { + this.notificationService.showError('ACA_FOLDER_RULES.ERRORS.DELETE_RULE_SET_LINK_FAILED'); + } + } + }); + } } 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 index 28457ca004..16bc574397 100644 --- 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 @@ -39,7 +39,6 @@ import { timer } from 'rxjs'; describe('EditRuleDialogSmartComponent', () => { let fixture: ComponentFixture; - let actionsService: ActionsService; const dialogRef = { close: jasmine.createSpy('close'), @@ -64,9 +63,8 @@ describe('EditRuleDialogSmartComponent', () => { ] }); - actionsService = TestBed.inject(ActionsService); - spyOn(actionsService, 'loadActionDefinitions').and.stub(); - spyOn(actionsService, 'getParameterConstraints').and.stub(); + spyOn(ActionsService.prototype, 'loadActionDefinitions').and.stub(); + spyOn(ActionsService.prototype, 'getParameterConstraints').and.stub(); fixture = TestBed.createComponent(EditRuleDialogSmartComponent); fixture.detectChanges(); 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 index ffe5db6a31..eda6a2adc1 100644 --- 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 @@ -38,7 +38,8 @@ export interface EditRuleDialogOptions { templateUrl: './edit-rule-dialog.smart-component.html', styleUrls: ['./edit-rule-dialog.smart-component.scss'], encapsulation: ViewEncapsulation.None, - host: { class: 'aca-edit-rule-dialog' } + host: { class: 'aca-edit-rule-dialog' }, + providers: [{ provide: ActionsService, useClass: ActionsService }] }) export class EditRuleDialogSmartComponent implements OnInit, OnDestroy { formValid = false; diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.html b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.html index 0f2a6beba8..263750e718 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.html +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.html @@ -6,6 +6,7 @@ tabindex="0" [rule]="item.rule" [isSelected]="isSelected(item.rule)" + [showEnabledToggle]="showEnabledToggles" (click)="onRuleClicked(item.rule)" (enabledChanged)="onEnabledChanged(item.rule, $event)"> diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.spec.ts b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.spec.ts index e3dd30c144..37a839c531 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.spec.ts +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.spec.ts @@ -62,10 +62,8 @@ describe('RuleListGroupingUiComponent', () => { const rule = debugElement.query(By.css('.aca-rule-list-item:first-child')); const name = rule.query(By.css('.aca-rule-list-item__header__name')); const description = rule.query(By.css('.aca-rule-list-item__description')); - const toggleBtn = rule.query(By.css('mat-slide-toggle')); expect(name.nativeElement.textContent).toBe(rulesMock[0].name); - expect(toggleBtn).toBeTruthy(); expect(description.nativeElement.textContent).toBe(rulesMock[0].description); }); }); diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.ts index d5820feb6e..da79035a7e 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.ts +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list-grouping/rule-list-grouping.ui-component.ts @@ -40,6 +40,8 @@ export class RuleListGroupingUiComponent { items: RuleGroupingItem[] = []; @Input() selectedRule: Rule = null; + @Input() + showEnabledToggles = false; @Output() selectRule = new EventEmitter(); diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.html b/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.html index 01fd0064ae..68317598a4 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.html +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.html @@ -3,6 +3,7 @@ {{ rule.name }} diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.ts index 49f7cc679a..c59b278723 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.ts +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list-item/rule-list-item.ui-component.ts @@ -39,6 +39,8 @@ export class RuleListItemUiComponent { @Input() @HostBinding('class.selected') isSelected: boolean; + @Input() + showEnabledToggle = false; @Output() enabledChanged = new EventEmitter(); diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.html b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.html index 0b88f4069e..0bcdb0bf00 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.html +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.html @@ -4,26 +4,22 @@ data-automation-id="rule-list-item" [ngClass]="{ expanded: inheritedRuleSetsExpanded }"> -
+
-
- - - {{ 'ACA_FOLDER_RULES.RULE_LIST.INHERITED_RULES' | translate }} - - info - - - - {{ inheritedRuleSetsExpanded ? 'expand_more' : 'chevron_right' }} + + {{ 'ACA_FOLDER_RULES.RULE_LIST.INHERITED_RULES' | translate }} + + info -
- + + + {{ inheritedRuleSetsExpanded ? 'expand_more' : 'chevron_right' }} +
-
- -
+
+ {{ 'ACA_FOLDER_RULES.RULE_LIST.OWNED_RULES' | translate }} {{ 'ACA_FOLDER_RULES.RULE_LIST.LINKED_RULES' | translate }} + - - {{ mainRuleSetExpanded ? 'expand_more' : 'chevron_right' }} - -
+ + edit + link_off + + + {{ mainRuleSetExpanded ? 'expand_more' : 'chevron_right' }} +
diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.scss b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.scss index 7dee1e7177..dae8faaea1 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.scss +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.scss @@ -14,31 +14,29 @@ &__header { display: flex; flex-direction: row; + gap: 4px; align-items: stretch; cursor: pointer; color: var(--theme-text-color); user-select: none; font-size: 0.9em; + padding: 0.5em 1em; & > * { display: flex; flex-direction: row; align-items: center; - justify-content: space-between; } &__title { - padding: 0.5em 1em; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; flex: 1; - &__text { - display: flex; - flex-direction: row; - align-items: center; - - .mat-icon { - transform: scale(0.8); - } + .mat-icon { + transform: scale(0.8); } } } diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.spec.ts b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.spec.ts index f9fd3c59f6..add479b9c8 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.spec.ts +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.spec.ts @@ -38,8 +38,6 @@ describe('RuleListUiComponent', () => { let component: RuleListUiComponent; let debugElement: DebugElement; - const innerTextWithoutIcon = (element: HTMLDivElement): string => element.innerText.replace(/(expand_more|chevron_right)$/, '').trim(); - beforeEach(() => { TestBed.configureTestingModule({ imports: [CoreTestingModule], @@ -59,7 +57,7 @@ describe('RuleListUiComponent', () => { fixture.detectChanges(); const mainRuleSetTitleElement = debugElement.query(By.css(`[data-automation-id="main-rule-set-title"]`)); - expect(innerTextWithoutIcon(mainRuleSetTitleElement.nativeElement as HTMLDivElement)).toBe('ACA_FOLDER_RULES.RULE_LIST.OWNED_RULES'); + expect((mainRuleSetTitleElement.nativeElement as HTMLDivElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_LIST.OWNED_RULES'); }); it('should show "Rules from linked folder" as a title if the main rule set is linked', () => { @@ -67,6 +65,6 @@ describe('RuleListUiComponent', () => { fixture.detectChanges(); const mainRuleSetTitleElement = debugElement.query(By.css(`[data-automation-id="main-rule-set-title"]`)); - expect(innerTextWithoutIcon(mainRuleSetTitleElement.nativeElement as HTMLDivElement)).toBe('ACA_FOLDER_RULES.RULE_LIST.LINKED_RULES'); + expect((mainRuleSetTitleElement.nativeElement as HTMLDivElement).innerText.trim()).toBe('ACA_FOLDER_RULES.RULE_LIST.LINKED_RULES'); }); }); diff --git a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.ts b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.ts index 2318ac9657..1b96273cf3 100644 --- a/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.ts +++ b/projects/aca-folder-rules/src/lib/rule-list/rule-list/rule-list.ui-component.ts @@ -58,6 +58,10 @@ export class RuleListUiComponent { selectRule = new EventEmitter(); @Output() ruleEnabledChanged = new EventEmitter<[Rule, boolean]>(); + @Output() + ruleSetEditLinkClicked = new EventEmitter(); + @Output() + ruleSetUnlinkClicked = new EventEmitter(); inheritedRuleSetsExpanded = true; mainRuleSetExpanded = true; @@ -118,4 +122,14 @@ export class RuleListUiComponent { onRuleEnabledChanged(event: [Rule, boolean]) { this.ruleEnabledChanged.emit(event); } + + onRuleSetEditLinkClicked(event: Event) { + event.stopPropagation(); + this.ruleSetEditLinkClicked.emit(this.mainRuleSet); + } + + onRuleSetUnlinkClicked(event: Event) { + event.stopPropagation(); + this.ruleSetUnlinkClicked.emit(this.mainRuleSet); + } } diff --git a/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.html b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.html new file mode 100644 index 0000000000..484ffdec5e --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.html @@ -0,0 +1,59 @@ +
+
+ {{ 'ACA_FOLDER_RULES.LINK_RULES_DIALOG.TITLE' | translate }} +
+ +
+ + + + + +
+ + + + + + +
+ {{ 'ACA_FOLDER_RULES.LINK_RULES_DIALOG.LIST_OF_RULES_TO_LINK' | translate }} +
+ + + +
+ + + + + +
+
+
+ + + + + + diff --git a/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.scss b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.scss new file mode 100644 index 0000000000..4a7769af04 --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.scss @@ -0,0 +1,76 @@ +.aca-rule-set-picker-container { + --rule-set-picker-padding: 8px 20px; + + .mat-dialog-container { + padding: 0; + } +} + +.aca-rule-set-picker { + &__header { + display: flex; + align-items: center; + margin: 0; + padding: var(--rule-set-picker-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 { + position: relative; + height: 80vh; + margin: 0; + padding: 0; + display: grid; + grid-template-columns: 2fr minmax(250px, 1fr); + + &__node-selector { + padding: 0 20px; + box-sizing: border-box; + } + + &__rule-list { + padding: 0 20px 0 0; + display: flex; + align-items: stretch; + flex-direction: column; + max-height: 100%; + overflow-y: auto; + overflow-x: hidden; + + &.justify { + align-items: center; + justify-content: center; + } + + &__header { + color: var(--theme-text-color); + font-size: 0.9em; + margin: 8px 0; + } + + .aca-rule-list-item { + cursor: default; + } + } + } + + &__footer { + margin: 0; + padding: var(--rule-set-picker-padding); + box-sizing: border-box; + border-top: 1px solid var(--theme-border-color); + } +} diff --git a/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.ts b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.ts new file mode 100644 index 0000000000..bdc3492bed --- /dev/null +++ b/projects/aca-folder-rules/src/lib/rule-set-picker/rule-set-picker.smart-component.ts @@ -0,0 +1,116 @@ +/*! + * @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, MatDialogRef } from '@angular/material/dialog'; +import { FolderRuleSetsService } from '../services/folder-rule-sets.service'; +import { Node } from '@alfresco/js-api'; +import { RuleSet } from '../model/rule-set.model'; +import { BehaviorSubject, combineLatest, from, of } from 'rxjs'; +import { finalize, map, switchMap } from 'rxjs/operators'; +import { NotificationService } from '@alfresco/adf-core'; + +export interface RuleSetPickerOptions { + nodeId: string; + defaultNodeId: string; + existingRuleSet?: RuleSet; +} + +@Component({ + selector: 'aca-rule-set-picker', + templateUrl: './rule-set-picker.smart-component.html', + styleUrls: ['./rule-set-picker.smart-component.scss'], + encapsulation: ViewEncapsulation.None, + host: { class: 'aca-rule-set-picker' }, + providers: [ + { + provide: FolderRuleSetsService, + useClass: FolderRuleSetsService + } + ] +}) +export class RuleSetPickerSmartComponent { + nodeId = '-root-'; + defaultNodeId = '-root-'; + isBusy = false; + existingRuleSet: RuleSet = null; + + private selectedNodeId = ''; + private folderLoading$ = new BehaviorSubject(true); + + mainRuleSet$ = this.folderRuleSetsService.mainRuleSet$; + rulesLoading$ = combineLatest(this.folderRuleSetsService.isLoading$, this.folderLoading$).pipe( + map(([rulesLoading, folderLoading]) => rulesLoading || folderLoading) + ); + + constructor( + @Inject(MAT_DIALOG_DATA) public data: RuleSetPickerOptions, + private folderRuleSetsService: FolderRuleSetsService, + private dialogRef: MatDialogRef, + private notificationService: NotificationService + ) { + this.nodeId = this.data?.nodeId ?? '-root-'; + this.defaultNodeId = this.data?.defaultNodeId ?? '-root-'; + this.existingRuleSet = this.data?.existingRuleSet ?? null; + } + + hasOwnedRules(ruleSet: RuleSet): boolean { + return ruleSet?.rules.length > 0 && FolderRuleSetsService.isOwnedRuleSet(ruleSet, this.selectedNodeId); + } + + onNodeSelect(nodes: Node[]) { + if (nodes?.length && nodes[0].isFolder && nodes[0].id !== this.selectedNodeId) { + this.selectedNodeId = nodes[0].id; + this.folderRuleSetsService.loadRuleSets(this.selectedNodeId, false); + } + } + + setFolderLoading(isLoading: boolean) { + this.folderLoading$.next(isLoading); + } + + onSubmit() { + this.isBusy = true; + from(this.existingRuleSet ? this.folderRuleSetsService.deleteRuleSetLink(this.nodeId, this.existingRuleSet.id) : of(null)) + .pipe( + switchMap(() => from(this.folderRuleSetsService.createRuleSetLink(this.nodeId, this.selectedNodeId))), + finalize(() => { + this.isBusy = false; + }) + ) + .subscribe( + () => { + this.dialogRef.close(true); + }, + () => { + this.handleError(); + } + ); + } + + private handleError() { + this.notificationService.showError('ACA_FOLDER_RULES.LINK_RULES_DIALOG.ERRORS.REQUEST_FAILED'); + } +} diff --git a/projects/aca-folder-rules/src/lib/services/folder-rule-sets.service.ts b/projects/aca-folder-rules/src/lib/services/folder-rule-sets.service.ts index 5b80349734..d976b4b1c2 100644 --- a/projects/aca-folder-rules/src/lib/services/folder-rule-sets.service.ts +++ b/projects/aca-folder-rules/src/lib/services/folder-rule-sets.service.ts @@ -41,10 +41,10 @@ export class FolderRuleSetsService { public static MAX_RULE_SETS_PER_GET = 100; static isOwnedRuleSet(ruleSet: RuleSet, nodeId: string): boolean { - return ruleSet.owningFolder.id === nodeId; + return ruleSet?.owningFolder?.id === nodeId; } static isLinkedRuleSet(ruleSet: RuleSet, nodeId: string): boolean { - return ruleSet.linkedToBy.indexOf(nodeId) > -1; + return ruleSet?.linkedToBy.indexOf(nodeId) > -1; } static isMainRuleSet(ruleSet: RuleSet, nodeId: string): boolean { return this.isOwnedRuleSet(ruleSet, nodeId) || this.isLinkedRuleSet(ruleSet, nodeId); @@ -72,11 +72,13 @@ export class FolderRuleSetsService { selectedRuleSet$ = this.folderRulesService.selectedRule$.pipe( map((rule: Rule) => { + if (rule === null) { + return null; + } if (this.mainRuleSet?.rules.findIndex((r: Rule) => r.id === rule.id) > -1) { return this.mainRuleSet; - } else { - return this.inheritedRuleSets.find((ruleSet: RuleSet) => ruleSet.rules.findIndex((r: Rule) => r.id === rule.id) > -1) ?? null; } + return this.inheritedRuleSets.find((ruleSet: RuleSet) => ruleSet.rules.findIndex((r: Rule) => r.id === rule.id) > -1) ?? null; }) ); @@ -117,7 +119,7 @@ export class FolderRuleSetsService { ); } - loadRuleSets(nodeId: string) { + loadRuleSets(nodeId: string, loadInheritedRuleSets = true) { this.isLoadingSource.next(true); this.mainRuleSet = null; this.inheritedRuleSets = []; @@ -132,7 +134,7 @@ export class FolderRuleSetsService { this.currentFolder = nodeInfo; this.folderInfoSource.next(this.currentFolder); }), - switchMap(() => combineLatest(this.getMainRuleSet(nodeId), this.getInheritedRuleSets(nodeId))), + switchMap(() => combineLatest(this.getMainRuleSet(nodeId), loadInheritedRuleSets ? this.getInheritedRuleSets(nodeId) : of([]))), finalize(() => this.isLoadingSource.next(false)) ) .subscribe(([mainRuleSet, inheritedRuleSets]) => { @@ -222,14 +224,29 @@ export class FolderRuleSetsService { } this.folderRulesService.selectRule(newRule); } else { - this.getMainRuleSet(this.currentFolder.id).subscribe((mainRuleSet: RuleSet) => { - this.mainRuleSet = mainRuleSet; - this.mainRuleSetSource.next(mainRuleSet); - if (mainRuleSet) { - const ruleToSelect = mainRuleSet.rules.find((rule: Rule) => rule.id === newRule.id); - this.folderRulesService.selectRule(ruleToSelect); - } - }); + this.refreshMainRuleSet(newRule); } } + + refreshMainRuleSet(ruleToSelect: Rule = null) { + this.getMainRuleSet(this.currentFolder.id).subscribe((mainRuleSet: RuleSet) => { + this.mainRuleSet = mainRuleSet; + this.mainRuleSetSource.next(mainRuleSet); + if (mainRuleSet) { + const ruleToSelectInRuleSet = ruleToSelect ? mainRuleSet.rules.find((rule: Rule) => rule.id === ruleToSelect.id) : mainRuleSet.rules[0]; + this.folderRulesService.selectRule(ruleToSelectInRuleSet); + } + }); + } + + async createRuleSetLink(folderIdToCreateLink: string, folderIdToLinkFrom: string): Promise { + const data = { + id: folderIdToLinkFrom + }; + return this.callApi(`/nodes/${folderIdToCreateLink}/rule-set-links`, 'POST', data); + } + + async deleteRuleSetLink(folderIdToDeleteLink: string, ruleSetIdToDelete: string): Promise { + return this.callApi(`/nodes/${folderIdToDeleteLink}/rule-set-links/${ruleSetIdToDelete}`, 'DELETE'); + } }