Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
[isLast]="true"
[isFirst]="true"
[nodeType]="types.GROUP"
[eventGroups]="eventGroups"
[popupTemplate]="nodePopup"
[templateMap]="templateMap"
[allColumns]="allColumns"
Expand Down
55 changes: 55 additions & 0 deletions projects/workflows-creator/src/lib/builder/builder.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ export class BuilderComponent<E> implements OnInit, OnChanges {

nodeList: AbstractBaseGroup<E>[] = [];
processId: string;

// Current selected event identifier for action filtering
get currentSelectedEvent(): string | undefined {
// Look through event groups to find the first selected event
for (const eventGroup of this.eventGroups) {
if (eventGroup?.children?.length > 0) {
const firstChild = eventGroup.children[0];
if (firstChild?.node?.type === NodeTypes.EVENT) {
return firstChild.node.getIdentifier();
}
}
}
return undefined;
}
// sonarignore:start
// TODO: Refactor this code to be more flexible
// sonarignore:start
Expand Down Expand Up @@ -225,6 +239,9 @@ export class BuilderComponent<E> implements OnInit, OnChanges {
* @param event - ElementsWithInput<E>
*/
onEventAdded(event: ElementsWithInput<E>) {
// Check if we need to clear existing actions when event changes
this.clearIncompatibleActions(event.node.getIdentifier());

this.eventAdded.emit({
name: event.node.getIdentifier(),
event: event.newNode.node as WorkflowEvent<E>,
Expand All @@ -237,6 +254,44 @@ export class BuilderComponent<E> implements OnInit, OnChanges {
event.node.getIdentifier() === EventTypes.OnAddItemEvent);
}

/**
* Clears actions that are not compatible with the selected event
* @param selectedEvent - The identifier of the selected event
*/
private clearIncompatibleActions(selectedEvent: string) {
if (this.actionGroups[0]?.children?.length > 0) {
// Get list of actions that should remain (compatible with new event)
const compatibleActions = this.nodes.getActions(selectedEvent);
const compatibleActionIds = new Set(
compatibleActions.map(action => action.getIdentifier()),
);

// Filter out incompatible actions
const currentActions = [...this.actionGroups[0].children];
const actionsToRemove: number[] = [];

currentActions.forEach((action, index) => {
const actionId = action.node.getIdentifier();
if (!compatibleActionIds.has(actionId)) {
actionsToRemove.push(index);
}
});

// Remove incompatible actions (reverse order to maintain indexes)
actionsToRemove.reverse().forEach(index => {
this.actionGroups[0].children.splice(index, 1);
});

// Clear state for removed actions
actionsToRemove.forEach(index => {
const removedAction = currentActions[index];
if (removedAction) {
this.updateState(removedAction.node, removedAction.inputs, true);
}
});
}
}

/**
* The function is called when an event is removed from the workflow.
* Hides the else block when it is not needed.
Expand Down
48 changes: 36 additions & 12 deletions projects/workflows-creator/src/lib/builder/group/group.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,7 @@ export class GroupComponent<E> implements OnInit, AfterViewInit {
ngOnInit(): void {
this.events = this.nodes.getEvents();
this.triggerEvents = this.nodes.getEvents(true);
this.actions = this.nodes
.getActions()
.sort((a, b) =>
a.name
.toString()
.localeCompare(b.name.toString(), undefined, {sensitivity: 'base'}),
);
this.actions = [];

this.typeSubjectPlaceholder = this.localizationSvc.getLocalizedString(
LocalizedStringKeys.TypeSubject,
Expand Down Expand Up @@ -323,15 +317,44 @@ export class GroupComponent<E> implements OnInit, AfterViewInit {
*/
openPopup(type: NodeTypes) {
if (type === NodeTypes.ACTION) {
this.nodeList = this.actions;
} else if (type === NodeTypes.EVENT) {
const selectedEvent = this.fetchSelectedEvent();
this.nodeList = this.nodes.getActions(selectedEvent);
return;
}
if (type === NodeTypes.EVENT) {
this.nodeList =
this.eventGroups.length === 1 && !this.group.children.length
this.eventGroups?.length === 1 && !this.group.children.length
? this.triggerEvents
: this.events;
} else {
throw new InvalidEntityError('' + type);
return;
}
throw new InvalidEntityError(String(type));
}

private fetchSelectedEvent() {
let selectedEvent: string | undefined;

// Method 1: find first EVENT in eventGroups
if (this.eventGroups?.length) {
for (const group of this.eventGroups) {
const firstChild = group?.children?.[0];
if (firstChild?.node?.type === NodeTypes.EVENT) {
selectedEvent = firstChild.node.getIdentifier();
break;
}
}
}

// Method 2: fallback - find first EVENT in current group
if (!selectedEvent) {
for (const child of this.group.children ?? []) {
if (child?.node?.type === NodeTypes.EVENT) {
selectedEvent = child.node.getIdentifier();
break;
}
}
}
return selectedEvent;
}

/**
Expand Down Expand Up @@ -362,6 +385,7 @@ export class GroupComponent<E> implements OnInit, AfterViewInit {
if (newNode.node.getIdentifier() === 'OnIntervalEvent') {
newNode.node.state.change('valueInputType', 'number');
}
this.actions = this.nodes.getActions(); // Get all actions initially
this.group.children.push(newNode as EventWithInput<E>);
this.eventAdded.emit({
node: node,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {WorkflowNode} from '../../types/base.types';
import {AbstractBaseGroup} from '../nodes';

export abstract class NodeService<E> {
abstract getActions(): WorkflowNode<E>[];
abstract getActions(selectedEvent?: string): WorkflowNode<E>[];
abstract getEvents(trigger?: boolean): WorkflowNode<E>[];
abstract getGroups(
trigger?: boolean,
Expand Down
38 changes: 28 additions & 10 deletions projects/workflows-creator/src/lib/services/bpmn/node.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,36 @@ export class BpmnNodesService<E> extends NodeService<E> {
* > Get all the nodes that are of type `ACTION`
*
* The function is a bit more complicated than that, but that's the gist of it
* @param selectedEvent - Optional event identifier to filter actions by eventBinded property
* @returns An array of action nodes.
*/
getActions() {
return this.nodes
.map(
Node =>
new Node(
this.localizationSvc.getLocalizedStringMap(),
this.utils.uuid(),
),
)
.filter(n => n.type === NodeTypes.ACTION);
getActions(selectedEvent?: string) {
const localizedStrings = this.localizationSvc.getLocalizedStringMap();

const actions = this.nodes
.map(Node => new Node(localizedStrings, this.utils.uuid()))
.filter(n => n.type === NodeTypes.ACTION)
.sort((a, b) =>
a.name.toString().localeCompare(b.name.toString(), undefined, {
sensitivity: 'base',
}),
);

return actions.filter(action => {
const a = action as WorkflowAction<E> & {eventBinded?: string[]};
const events = a.eventBinded;

if (!Array.isArray(events)) {
// unbound actions always allowed
return true;
}

if (!selectedEvent) {
// no selectedEvent → return only unbound actions
return false;
}
return events.includes(selectedEvent);
});
}

/**
Expand Down
Loading