[ACS-3860] Folder rules - Node picker for action parameters of type "d:noderef" (#2800)

* [ACS-3860] - added callback with node selector dialog

* ACS-3860 - implemented node picker for actions

* ACS-3860 - unit tests

* ACS-3860 - linting

* ACS-3860 - i18n

* ACS-3860 - small fix

* ACS-3860 - changed to private method, added typization

* ACS-3860 - removed useless getter and setter

* ACS-3860 - added 'noderef' to cspell.json
This commit is contained in:
Nikita Maliarchuk 2022-11-22 13:30:46 +01:00 committed by GitHub
parent 03ed8e071a
commit 81033450d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 122 additions and 12 deletions

View File

@ -65,7 +65,8 @@
"dateitem",
"versionable",
"erroredSpy",
"errored"
"errored",
"noderef"
],
"dictionaries": ["html", "en-gb", "en_US"]
}

View File

@ -22,7 +22,8 @@
"NAME": "Enter rule name",
"DESCRIPTION": "Enter rule description",
"NO_DESCRIPTION": "No description",
"VALUE": "Value"
"VALUE": "Value",
"CHOOSE_FOLDER": "Choose destination folder"
},
"ERROR": {
"REQUIRED": "This field is required",

View File

@ -86,7 +86,8 @@
[actionDefinitions]="actionDefinitions$ | async"
[readOnly]="true"
[preview]="true"
[value]="selectedRule">
[value]="selectedRule"
[nodeId]="nodeId">
</aca-rule-details>
</div>
</div>

View File

@ -48,7 +48,7 @@ import { RuleSet } from '../model/rule-set.model';
host: { class: 'aca-manage-rules' }
})
export class ManageRulesSmartComponent implements OnInit, OnDestroy {
nodeId: string = null;
nodeId = '';
mainRuleSet$: Observable<RuleSet>;
inheritedRuleSets$: Observable<RuleSet[]>;
@ -115,7 +115,8 @@ export class ManageRulesSmartComponent implements OnInit, OnDestroy {
width: '90%',
panelClass: 'aca-edit-rule-dialog-container',
data: {
model
model,
nodeId: this.nodeId
}
});

View File

@ -57,6 +57,18 @@ export const actionDefListMock = {
multiValued: false,
mandatory: false,
parameterConstraintName: 'ac-aspects'
},
{
name: 'mock-action-parameter-noderef',
type: 'd:noderef',
multiValued: false,
mandatory: false
},
{
name: 'aspect-name',
type: 'd:noderef',
multiValued: false,
mandatory: false
}
],
name: 'mock-action-1-definition',
@ -102,6 +114,24 @@ const actionParam3TransformedMock: ActionParameterDefinitionTransformed = {
parameterConstraintName: 'ac-aspects'
};
const actionParam4TransformedMock: ActionParameterDefinitionTransformed = {
name: 'mock-action-parameter-noderef',
type: 'd:noderef',
multiValued: false,
mandatory: false,
displayLabel: 'mock-action-parameter-noderef',
parameterConstraintName: ''
};
const actionParam5TransformedMock: ActionParameterDefinitionTransformed = {
name: 'aspect-name',
type: 'd:noderef',
multiValued: false,
mandatory: false,
displayLabel: 'aspect-name',
parameterConstraintName: ''
};
const action1TransformedMock: ActionDefinitionTransformed = {
id: 'mock-action-1-definition',
name: 'mock-action-1-definition',
@ -109,7 +139,13 @@ const action1TransformedMock: ActionDefinitionTransformed = {
title: 'Action 1 title',
applicableTypes: [],
trackStatus: false,
parameterDefinitions: [actionParam1TransformedMock, actionParam2TransformedMock, actionParam3TransformedMock]
parameterDefinitions: [
actionParam1TransformedMock,
actionParam2TransformedMock,
actionParam3TransformedMock,
actionParam4TransformedMock,
actionParam5TransformedMock
]
};
const action2TransformedMock: ActionDefinitionTransformed = {

View File

@ -3,7 +3,8 @@
[actionDefinitions]="actionDefinitions"
[parameterConstraints]="parameterConstraints"
[readOnly]="readOnly"
[formControl]="control">
[formControl]="control"
[nodeId]="nodeId">
</aca-rule-action>
<button

View File

@ -51,6 +51,8 @@ export class RuleActionListUiComponent implements ControlValueAccessor, OnDestro
readOnly = false;
@Input()
parameterConstraints: ActionParameterConstraint[] = [];
@Input()
nodeId = '';
formArray = new FormArray([]);
private formArraySubscription: Subscription;

View File

@ -79,10 +79,13 @@ describe('RuleActionUiComponent', () => {
expect(cardView.properties.length).toBe(0);
changeMatSelectValue('rule-action-select', 'mock-action-1-definition');
expect(cardView.properties.length).toBe(3);
expect(cardView.properties.length).toBe(5);
expect(cardView.properties[0]).toBeInstanceOf(CardViewTextItemModel);
expect(cardView.properties[1]).toBeInstanceOf(CardViewBoolItemModel);
expect(cardView.properties[2]).toBeInstanceOf(CardViewSelectItemModel);
expect(cardView.properties[3]).toBeInstanceOf(CardViewTextItemModel);
expect(cardView.properties[4]).toBeInstanceOf(CardViewSelectItemModel);
changeMatSelectValue('rule-action-select', 'mock-action-2-definition');
expect(cardView.properties.length).toBe(0);

View File

@ -35,10 +35,13 @@ import {
CardViewUpdateService,
UpdateNotification
} from '@alfresco/adf-core';
import { ActionParameterDefinition } from '@alfresco/js-api';
import { ActionParameterDefinition, Node } from '@alfresco/js-api';
import { of, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { ActionParameterConstraint, ConstraintValue } from '../../model/action-parameter-constraint.model';
import { ContentNodeSelectorComponent, ContentNodeSelectorComponentData, NodeAction } from '@alfresco/adf-content-services';
import { MatDialog } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'aca-rule-action',
@ -56,6 +59,9 @@ import { ActionParameterConstraint, ConstraintValue } from '../../model/action-p
]
})
export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDestroy {
@Input()
nodeId = '';
private _actionDefinitions: ActionDefinitionTransformed[];
@Input()
get actionDefinitions(): ActionDefinitionTransformed[] {
@ -108,7 +114,7 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDe
onChange: (action: RuleAction) => void = () => undefined;
onTouch: () => void = () => undefined;
constructor(private cardViewUpdateService: CardViewUpdateService) {}
constructor(private cardViewUpdateService: CardViewUpdateService, private dialog: MatDialog, private translate: TranslateService) {}
writeValue(action: RuleAction) {
this.form.setValue({
@ -161,6 +167,7 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDe
setCardViewProperties() {
this.cardViewItems = (this.selectedActionDefinition?.parameterDefinitions ?? []).map((paramDef) => {
this.isFullWidth = false;
const constraintsForDropdownBox = this._parameterConstraints.find((obj) => obj.name === paramDef.name);
const cardViewPropertiesModel = {
label: paramDef.displayLabel + (paramDef.mandatory ? ' *' : ''),
key: paramDef.name,
@ -182,8 +189,19 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDe
...cardViewPropertiesModel,
value: this.parameters[paramDef.name] ?? false
});
case 'd:noderef':
if (!constraintsForDropdownBox && !this.readOnly) {
return new CardViewTextItemModel({
...cardViewPropertiesModel,
icon: 'folder',
default: this.translate.instant('ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.CHOOSE_FOLDER'),
clickable: true,
clickCallBack: this.openSelectorDialog.bind(this),
value: this.parameters[paramDef.name]
});
}
// falls through
default:
const constraintsForDropdownBox = this._parameterConstraints.find((obj) => obj.name === paramDef.name);
if (constraintsForDropdownBox && !this.readOnly) {
this.isFullWidth = true;
return new CardViewSelectItemModel({
@ -200,6 +218,45 @@ export class RuleActionUiComponent implements ControlValueAccessor, OnInit, OnDe
});
}
private openSelectorDialog() {
const data: ContentNodeSelectorComponentData = {
title: this.translate.instant('ACA_FOLDER_RULES.RULE_DETAILS.PLACEHOLDER.CHOOSE_FOLDER'),
actionName: NodeAction.CHOOSE,
currentFolderId: this.nodeId,
select: new Subject<Node[]>()
};
this.dialog.open(ContentNodeSelectorComponent, {
data,
panelClass: 'adf-content-node-selector-dialog',
width: '630px'
});
data.select.subscribe(
(selections: Node[]) => {
if (selections[0].id) {
this.writeValue({
actionDefinitionId: this.selectedActionDefinitionId,
params: {
'destination-folder': selections[0].id
}
});
this.onChange({
actionDefinitionId: this.selectedActionDefinitionId,
params: this.parameters
});
this.onTouch();
}
},
(error) => {
console.error(error);
},
() => {
this.dialog.closeAll();
}
);
}
setDefaultParameters() {
this.parameters = {};
(this.selectedActionDefinition?.parameterDefinitions ?? []).forEach((paramDef: ActionParameterDefinition) => {

View File

@ -20,6 +20,7 @@
[actionDefinitions]="actionDefinitions$ | async"
[parameterConstraints]="parameterConstraints$ | async"
[value]="model"
[nodeId]="nodeId"
(formValueChanged)="formValue = $event"
(formValidationChanged)="onFormValidChange($event)">
</aca-rule-details>

View File

@ -30,6 +30,7 @@ import { ActionsService } from '../services/actions.service';
export interface EditRuleDialogOptions {
model?: Partial<Rule>;
nodeId?: string;
}
@Component({
@ -42,6 +43,7 @@ export interface EditRuleDialogOptions {
export class EditRuleDialogSmartComponent implements OnInit, OnDestroy {
formValid = false;
model: Partial<Rule>;
nodeId = '';
formValue: Partial<Rule>;
@Output() submitted = new EventEmitter<Partial<Rule>>();
actionDefinitions$ = this.actionsService.actionDefinitionsListing$;
@ -51,6 +53,7 @@ export class EditRuleDialogSmartComponent implements OnInit, OnDestroy {
constructor(@Inject(MAT_DIALOG_DATA) public data: EditRuleDialogOptions, private actionsService: ActionsService) {
this.model = this.data?.model || {};
this.nodeId = this.data?.nodeId;
}
get isUpdateMode(): boolean {

View File

@ -47,7 +47,8 @@
formControlName="actions"
[actionDefinitions]="actionDefinitions"
[parameterConstraints]="parameterConstraints"
[readOnly]="readOnly">
[readOnly]="readOnly"
[nodeId]="nodeId">
</aca-rule-action-list>
</div>

View File

@ -97,6 +97,8 @@ export class RuleDetailsUiComponent implements OnInit, OnDestroy {
actionDefinitions: ActionDefinitionTransformed[] = [];
@Input()
parameterConstraints: ActionParameterConstraint[] = [];
@Input()
nodeId = '';
@Output()
formValidationChanged = new EventEmitter<boolean>();