From ba583b0ee0843004160835ff3a9b79e28628b731 Mon Sep 17 00:00:00 2001 From: Nilesh Kumar Date: Tue, 25 Apr 2023 13:54:10 +0530 Subject: [PATCH 01/19] fix(core): fix status column not being selected when priority column is already selected GH-8 --- .../src/lib/builder/group/group.component.ts | 44 ++++++++----------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index b9e5cdb..e8d71bb 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -470,32 +470,26 @@ export class GroupComponent implements OnInit, AfterViewInit { } } if (select && isSelectInput(input)) { - if ( + element.node.state.change( + `${input.inputKey}Name`, + (value as AllowedValuesMap)[input.listNameField], + ); + value = element.node.state.get('columnName') === 'Priority' && - input.inputKey !== 'condition' - ) { - element.node.state.change( - `${input.inputKey}Name`, - value as AllowedValuesMap, - ); - this.itemChanged.emit({ - field: input.getIdentifier(), - value: value as AllowedValuesMap, - element: element, - }); - value = value as AllowedValuesMap; - } else { - element.node.state.change( - `${input.inputKey}Name`, - (value as AllowedValuesMap)[input.listNameField], - ); - this.itemChanged.emit({ - field: input.getIdentifier(), - value: (value as AllowedValuesMap)[input.listValueField], - element: element, - }); - value = (value as AllowedValuesMap)[input.listValueField]; - } + input.inputKey === 'value' + ? value + : (value as AllowedValuesMap)[input.listValueField]; + element.node.state.change(input.inputKey, value); + this.handleSubsequentInputs(element, input); + this.itemChanged.emit({ + field: input.getIdentifier(), + value: + element.node.state.get('columnName') === 'Priority' && + input.inputKey === 'value' + ? (value as AllowedValuesMap)[input.listValueField] + : value, + element: element, + }); } element.node.state.change(input.inputKey, value); this.handleSubsequentInputs(element, input); From b22334b0854b719c0f34787a3d024d5fee7de989 Mon Sep 17 00:00:00 2001 From: Nilesh Kumar Date: Wed, 3 May 2023 20:22:34 +0530 Subject: [PATCH 02/19] fix(styles): fix UI discrepency when value width is too large --- .../workflows-creator/src/lib/builder/builder.component.scss | 2 +- .../src/lib/builder/group/group.component.scss | 2 +- .../workflows-creator/src/lib/builder/node/node.component.scss | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.scss b/projects/workflows-creator/src/lib/builder/builder.component.scss index b5e1b4d..495d2d9 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.scss +++ b/projects/workflows-creator/src/lib/builder/builder.component.scss @@ -25,7 +25,7 @@ } } .container { - min-width: 46%; + min-width: 52%; max-width: max-content; color: rgb(50, 51, 56); margin: auto; diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.scss b/projects/workflows-creator/src/lib/builder/group/group.component.scss index 42f2acc..f113dfb 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.scss +++ b/projects/workflows-creator/src/lib/builder/group/group.component.scss @@ -71,7 +71,7 @@ .value-text { display: inline-block; overflow: hidden; - max-width: 45%; + max-width: 15rem; text-decoration: inherit; text-overflow: ellipsis; vertical-align: top; diff --git a/projects/workflows-creator/src/lib/builder/node/node.component.scss b/projects/workflows-creator/src/lib/builder/node/node.component.scss index 4d0acaf..e5435d5 100644 --- a/projects/workflows-creator/src/lib/builder/node/node.component.scss +++ b/projects/workflows-creator/src/lib/builder/node/node.component.scss @@ -6,6 +6,7 @@ position: relative; .workflow-content { flex-grow: 1; + height: 3rem; } .action-icons { cursor: pointer; From d5beb730e6b987d77eab0b57934a39126b80882d Mon Sep 17 00:00:00 2001 From: Nilesh Kumar Date: Wed, 3 May 2023 20:25:28 +0530 Subject: [PATCH 03/19] feat(core): add validation and fix icon properties --- .../src/lib/builder/builder.component.html | 3 +- .../src/lib/builder/builder.component.ts | 105 ++++++++++++++---- .../src/lib/builder/group/group.component.ts | 16 ++- projects/workflows-creator/src/lib/enum.ts | 5 + .../src/lib/services/bpmn/builder.service.ts | 5 +- .../tasks/change-column-value.task.ts | 23 +++- .../strategies/link/gateway-link.strategy.ts | 17 ++- 7 files changed, 128 insertions(+), 46 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.html b/projects/workflows-creator/src/lib/builder/builder.component.html index 4fc1553..c580a97 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.html +++ b/projects/workflows-creator/src/lib/builder/builder.component.html @@ -11,7 +11,7 @@ (add)="openPopup(types.GROUP)" (remove)="onGroupRemove(i)" (eventAdded)="onEventAdded($event)" - (eventRemoved)="onEventRemoved()" + (nodeRemoved)="onNodeRemoved()" (actionAdded)="onActionAdded($event)" (itemChanged)="onItemChanged($event)" > @@ -29,6 +29,7 @@ [templateMap]="templateMap" [allColumns]="allColumns" (eventAdded)="onEventAdded($event)" + (nodeRemoved)="onNodeRemoved()" (actionAdded)="onActionAdded($event)" (itemChanged)="onItemChanged($event)" > diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index d346069..0fb2a77 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -20,7 +20,14 @@ import { } from '../classes'; import {AbstractBaseGroup} from '../classes/nodes'; import {BuilderService, ElementService, NodeService} from '../classes/services'; -import {EventTypes, LocalizedStringKeys, NodeTypes, ValueTypes} from '../enum'; +import { + ActionTypes, + EventTypes, + LocalizedStringKeys, + NodeTypes, + NotificationRecipientTypesEnum, + ValueTypes, +} from '../enum'; import {InvalidEntityError} from '../errors/base.error'; import { ActionAddition, @@ -78,7 +85,7 @@ export class BuilderComponent implements OnInit, OnChanges { stateChange = new EventEmitter>(); @Output() - diagramChange = new EventEmitter(); + diagramChange = new EventEmitter(); @Output() eventAdded = new EventEmitter>(); @@ -217,7 +224,7 @@ export class BuilderComponent implements OnInit, OnChanges { this.updateDiagram(); this.updateState(event.node, event.newNode.inputs); this.elseBlockHidden = - !this.eventGroups[0]?.children?.length && + this.eventGroups[0]?.children?.length === 1 && (event.node.getIdentifier() === EventTypes.OnIntervalEvent || event.node.getIdentifier() === EventTypes.OnAddItemEvent); } @@ -226,16 +233,9 @@ export class BuilderComponent implements OnInit, OnChanges { * The function is called when an event is removed from the workflow. * Hides the else block when it is not needed. */ - onEventRemoved() { - const events = this.eventGroups[0].children; - - this.elseBlockHidden = - events.length === 1 && - (events[0].node.getIdentifier() === EventTypes.OnIntervalEvent || - events[0].node.getIdentifier() === EventTypes.OnAddItemEvent || - (events[0].node.getIdentifier() === EventTypes.OnChangeEvent && - (events[0].node.state.get('value') === ValueTypes.AnyValue || - events[0].node.state.get('valueType') === ValueTypes.AnyValue))); + onNodeRemoved() { + this.updateDiagram(); + if (this.eventGroups[0]?.children?.length) this.hideElseBlockIfRequired(); } /** @@ -264,19 +264,32 @@ export class BuilderComponent implements OnInit, OnChanges { item: item.element.node, }); this.updateState(item.element.node, item.element.inputs); - // TODO: to be refactored - // to hide else block when anything is selected in ValueInput or ValueTypeInput - this.elseBlockHidden = - this.eventGroups[0].children?.length === 1 && - this.eventGroups[0].children[0].node.getIdentifier() === - EventTypes.OnChangeEvent && - (this.eventGroups[0].children[0].node.state.get('value') === - ValueTypes.AnyValue || - this.eventGroups[0].children[0].node.state.get('valueType') === - ValueTypes.AnyValue); + this.hideElseBlockIfRequired(); this.updateDiagram(); } + /** + * This function checks if the else block should be hidden based on the type and number of events in + * the event group. + */ + hideElseBlockIfRequired() { + const events = this.eventGroups[0].children; + let value = events[0].node.state.get('value'); + if (typeof value === 'object') { + value = value.value; + } + if (events.length !== 1) { + this.elseBlockHidden = false; + } else { + this.elseBlockHidden = + events[0].node.getIdentifier() === EventTypes.OnIntervalEvent || + events[0].node.getIdentifier() === EventTypes.OnAddItemEvent || + (events[0].node.getIdentifier() === EventTypes.OnChangeEvent && + (value === ValueTypes.AnyValue || + events[0].node.state.get('valueType') === ValueTypes.AnyValue)); + } + } + /** * "If the type is a group, then get the groups, otherwise throw an error." * @@ -429,8 +442,52 @@ export class BuilderComponent implements OnInit, OnChanges { * It builds a new diagram, emits the new diagram, and then tells Angular to update the view */ async updateDiagram() { + const nodes = [ + ...this.eventGroups[0].children, + ...this.actionGroups[0].children, + ...this.elseActionGroups[0].children, + ]; + let isValid = + !!this.eventGroups[0].children.length && + (!!this.actionGroups[0].children.length || + !!this.elseActionGroups[0].children.length); + if (isValid) { + for (const node of nodes) { + switch (node.node.getIdentifier()) { + case EventTypes.OnChangeEvent: + case EventTypes.OnValueEvent: + case ActionTypes.ChangeColumnValueAction: + const columnExists = !!node.node.state.get('column'); + const valueExists = !!node.node.state.get('value'); + const valueTypeIsAnyValue = + node.node.state.get('valueType') === ValueTypes.AnyValue; + isValid = columnExists && (valueExists || valueTypeIsAnyValue); + break; + case EventTypes.OnIntervalEvent: + const intervalExists = !!node.node.state.get('interval'); + const intervalValueExists = !!node.node.state.get('value'); + isValid = intervalValueExists && intervalExists; + break; + case ActionTypes.SendEmailAction: + const email = !!node.node.state.get('email'); + const emailTo = !!node.node.state.get('emailTo'); + const specificRecipientsRequired = [ + NotificationRecipientTypesEnum.NotifySpecificColumn, + NotificationRecipientTypesEnum.NotifySpecificPeople, + ].includes(node.node.state.get('emailTo')); + const recipients = !!node.node.state.get('specificRecepient'); + isValid = specificRecipientsRequired + ? email && emailTo && recipients + : email && emailTo; + break; + } + if (!isValid) { + break; // exit the loop since we found an invalid input + } + } + } this.diagram = await this.build(); - this.diagramChange.emit(this.diagram); + this.diagramChange.emit({diagram: this.diagram, isValid: isValid}); this.cdr.detectChanges(); } diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index e8d71bb..c41bcd1 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -86,7 +86,7 @@ export class GroupComponent implements OnInit, AfterViewInit { eventAdded = new EventEmitter(); @Output() - eventRemoved = new EventEmitter(); + nodeRemoved = new EventEmitter(); @Output() actionAdded = new EventEmitter(); @@ -322,20 +322,20 @@ export class GroupComponent implements OnInit, AfterViewInit { inputs: this.nodes.mapInputs(node), }; if (node.type === NodeTypes.EVENT) { - this.eventAdded.emit({ - node: node, - newNode: newNode, - }); if (newNode.node.getIdentifier() === 'OnIntervalEvent') { newNode.node.state.change('valueInputType', 'number'); } this.group.children.push(newNode as EventWithInput); + this.eventAdded.emit({ + node: node, + newNode: newNode, + }); } else if (node.type === NodeTypes.ACTION) { + this.group.children.push(newNode as ActionWithInput); this.actionAdded.emit({ node: node, newNode: newNode, }); - this.group.children.push(newNode as ActionWithInput); } else { throw new InvalidEntityError('Node'); } @@ -347,7 +347,7 @@ export class GroupComponent implements OnInit, AfterViewInit { */ onNodeRemove(index: number) { this.group.children.splice(index, 1); - this.eventRemoved.emit(); + this.nodeRemoved.emit(); } /** @@ -475,7 +475,6 @@ export class GroupComponent implements OnInit, AfterViewInit { (value as AllowedValuesMap)[input.listNameField], ); value = - element.node.state.get('columnName') === 'Priority' && input.inputKey === 'value' ? value : (value as AllowedValuesMap)[input.listValueField]; @@ -484,7 +483,6 @@ export class GroupComponent implements OnInit, AfterViewInit { this.itemChanged.emit({ field: input.getIdentifier(), value: - element.node.state.get('columnName') === 'Priority' && input.inputKey === 'value' ? (value as AllowedValuesMap)[input.listValueField] : value, diff --git a/projects/workflows-creator/src/lib/enum.ts b/projects/workflows-creator/src/lib/enum.ts index 9914cfb..189ef9a 100644 --- a/projects/workflows-creator/src/lib/enum.ts +++ b/projects/workflows-creator/src/lib/enum.ts @@ -79,6 +79,11 @@ export enum EventTypes { OnValueEvent = 'OnValueEvent', } +export enum ActionTypes { + ChangeColumnValueAction = 'ChangeColumnValueAction', + SendEmailAction = 'SendEmailAction', +} + export enum StartElementTypes { BasicStartElement = 'StartElement', StartOnIntervalElement = 'StartOnIntervalElement', diff --git a/projects/workflows-creator/src/lib/services/bpmn/builder.service.ts b/projects/workflows-creator/src/lib/services/bpmn/builder.service.ts index 3b9f009..388da48 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/builder.service.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/builder.service.ts @@ -347,7 +347,10 @@ export class BpmnBuilderService extends BuilderService< const [id, key] = property['name'].split('_'); if (state[id]) { try { - state[id][key] = JSON.parse(property['value']); + state[id][key] = + typeof JSON.parse(property['value']) === 'object' + ? JSON.parse(property['value']) + : property['value']; } catch (error) { state[id][key] = property['value']; } diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts index ce89120..9d077fd 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts @@ -8,6 +8,7 @@ import {CREATE_TASK_STRATEGY} from '../../strategies/create'; import {LINK_BASIC_STRATEGY} from '../../strategies/link'; import {ServiceTaskElement} from './service-task.task'; import {ENV_TOKEN} from '../../../../token'; +import {InputTypes} from '../../../../enum'; @Injectable() export class ChangeColumnValue extends ServiceTaskElement { @@ -41,12 +42,24 @@ export class ChangeColumnValue extends ServiceTaskElement { }, changedValue: { formatter: (state: State) => { - if (typeof state.get('value') === 'object') { - return `'${JSON.stringify(state.get('value'))}'`; + switch (state.get('valueInputType')) { + case InputTypes.People: + return `'${JSON.stringify(state.get('value'))}'`; + case InputTypes.List: + if (!state.get('value')) return ''; + return `'${JSON.stringify({ + displayValue: state.get('value').text?.split('"').join(''), + value: state.get('value').value, + iconClass: state.get('value').iconClass, + color: state.get('value').color, + bgColor: state.get('value').bgColor, + })}'`; + default: + return `'{"displayValue": "${ + state.get('valueName')?.split('"').join('') ?? + state.get('value') + }", "value": "${state.get('value')}"}'`; } - return `'{"displayValue": "${ - state.get('valueName') ?? state.get('value') - }", "value": "${state.get('value')}"}'`; }, }, }, diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index 5021d09..276804a 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -369,12 +369,17 @@ export class GatewayLinkStrategy implements LinkStrategy { private getCondition(node: BpmnStatementNode) { let value = node.workflowNode.state.get('value'); const valueType = node.workflowNode.state.get('valueInputType'); - if (valueType === InputTypes.Text || valueType === InputTypes.List) { - value = `'${value}'`; - } - if (value && valueType === InputTypes.People) { - return `'${value.ids}'`; - } + if (value) + switch (valueType) { + case InputTypes.Text: + value = `'${value}'`; + break; + case InputTypes.List: + value = `'${value.value}'`; + break; + case InputTypes.People: + return `'${value.ids}'`; + } const condition = node.workflowNode.state.get('condition'); const pair = this.conditions.find(item => item.condition === condition); if (!pair) { From 1b517c4c92c99a13854c3b9444236d0b726373d1 Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Tue, 23 May 2023 15:47:38 +0530 Subject: [PATCH 04/19] fix(core): incorrect condition for is past today GH-9 --- .../workflows-creator/src/lib/builder/builder.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index 0fb2a77..f727ad5 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -22,6 +22,7 @@ import {AbstractBaseGroup} from '../classes/nodes'; import {BuilderService, ElementService, NodeService} from '../classes/services'; import { ActionTypes, + ConditionTypes, EventTypes, LocalizedStringKeys, NodeTypes, @@ -458,7 +459,10 @@ export class BuilderComponent implements OnInit, OnChanges { case EventTypes.OnValueEvent: case ActionTypes.ChangeColumnValueAction: const columnExists = !!node.node.state.get('column'); - const valueExists = !!node.node.state.get('value'); + const valueExists = + node.node.state.get('condition') === ConditionTypes.PastToday + ? true + : !!node.node.state.get('value'); const valueTypeIsAnyValue = node.node.state.get('valueType') === ValueTypes.AnyValue; isValid = columnExists && (valueExists || valueTypeIsAnyValue); From 5851aabc6e5e768662bbdc0dd082d78b1b11e99b Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Fri, 9 Jun 2023 14:25:41 +0530 Subject: [PATCH 05/19] feat(core): changes condition script for passed by and coming in clauses GH-9 --- .../services/bpmn/strategies/link/gateway-link.strategy.ts | 6 +++++- .../bpmn/strategies/link/or-gateway-link.strategy.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index 276804a..5c1b551 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -322,9 +322,13 @@ export class GatewayLinkStrategy implements LinkStrategy { var taskValuePair = readObj[key]; if(taskValuePair && taskValuePair.value){ var readDateValue = new Date(taskValuePair.value); + var today = new Date(); + readDateValue.setHours(0,0,0,0); + today.setHours(0,0,0,0); + readDateValue.setDate(readDateValue.getDate()${condition}); if(${ isElse ? '!' : '' - }(readDateValue > new Date() && readDateValue.setDate(readDateValue.getDate()${condition}) < new Date())){ + }(readDateValue.valueOf() === today.valueOf())){ ids.push(taskValuePair.id); } } diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts index 9b4c948..f20ddfc 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts @@ -161,9 +161,13 @@ export class OrGatewayLinkStrategy implements LinkStrategy { var taskValuePair = readObj[key]; if(taskValuePair && taskValuePair.value){ var readDateValue = new Date(taskValuePair.value); + var today = new Date(); + readDateValue.setHours(0,0,0,0); + today.setHours(0,0,0,0); + readDateValue.setDate(readDateValue.getDate()${condition}); if(${ isElse ? '!' : '' - }(readDateValue > new Date() && readDateValue.setDate(readDateValue.getDate()${condition}) < new Date())){ + }(readDateValue.valueOf() === today.valueOf())){ ids.push(taskValuePair.id); } } From 050056868bf7b17911736cc4e63fa5f5b3c1d2e4 Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Thu, 15 Jun 2023 14:12:51 +0530 Subject: [PATCH 06/19] fix(core): incorrect addition of read block and gateway when change trigger has anyValue GH-9 --- .../src/lib/builder/builder.component.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index f727ad5..54ab80d 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -25,6 +25,7 @@ import { ConditionTypes, EventTypes, LocalizedStringKeys, + NUMBER, NodeTypes, NotificationRecipientTypesEnum, ValueTypes, @@ -46,6 +47,11 @@ import { WorkflowNode, } from '../types'; import {LocalizationProviderService} from '../services/localization-provider.service'; +import { + ReadColumnValue, + TriggerWhenColumnChanges, +} from '../services/bpmn/elements/tasks'; +import {GatewayElement} from '../services/bpmn/elements/gateways'; @Component({ selector: 'workflow-builder', @@ -360,6 +366,30 @@ export class BuilderComponent implements OnInit, OnChanges { value: AllowedValues | AllowedValuesMap, select = false, ) { + if ( + (input.getIdentifier() === 'ValueTypeInput' || + input.getIdentifier() === 'ValueInput') && + element.node.getIdentifier() === 'OnChangeEvent' + ) { + if ( + ((value as AllowedValuesMap)?.value as AllowedValuesMap)?.value === + ValueTypes.AnyValue + ) { + /** + * Remove node on changes event + */ + element.node.elements.splice(-NUMBER.TWO, NUMBER.TWO); + // element.inputs[1].prefix = ''; + //this.enableActionIcon = false; + } else { + element.node.elements = [ + TriggerWhenColumnChanges.identifier, + ReadColumnValue.identifier, + GatewayElement.identifier, + ]; + } + } + if (select && isSelectInput(input)) { element.node.state.change( `${input.inputKey}Name`, From 422ffd6e296c448e66d7e668d683c763765d506e Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Fri, 30 Jun 2023 14:46:18 +0530 Subject: [PATCH 07/19] fix(core): insert column var at caret position GH-9 --- .../lib/builder/group/group.component.html | 9 ++++--- .../src/lib/builder/group/group.component.ts | 26 +++++++++++++++++-- .../src/lib/types/base.types.ts | 1 + 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.html b/projects/workflows-creator/src/lib/builder/group/group.component.html index 46758f9..3c24b04 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.html +++ b/projects/workflows-creator/src/lib/builder/group/group.component.html @@ -144,7 +144,8 @@ emailInput: emailInput, appendEmailBody: appendEmailBody, setFocusKey: setFocusKey, - hide: hidePopper() + hide: hidePopper(), + setFocusOutPos: setFocusOutPos } " > @@ -284,6 +285,7 @@ let-appendEmailBody="appendEmailBody" let-setFocusKey="setFocusKey" let-hide="hide" + let-setFocusOutPos="setFocusOutPos" > diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index c41bcd1..86ab847 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -103,6 +103,7 @@ export class GroupComponent implements OnInit, AfterViewInit { subject: '', body: '', focusKey: '', + caretPos: 0, }; dropdownSettings: IDropdownSettings = { singleSelection: false, @@ -134,6 +135,9 @@ export class GroupComponent implements OnInit, AfterViewInit { typeSubjectPlaceholder = ''; typeEmailPlaceholder = ''; + doThisLbl = ''; + whenThisHappensLbl = ''; + setLbl = ''; localizedStringKeys = LocalizedStringKeys; @@ -261,11 +265,21 @@ export class GroupComponent implements OnInit, AfterViewInit { */ appendEmailBody(item: Select, emailInput: EmailInput) { if (emailInput.focusKey === 'subject') { - emailInput.subject += ` ${item.value}`; + emailInput.subject = [ + emailInput.subject.slice(0, emailInput.caretPos), + `${item.value}`, + emailInput.subject.slice(emailInput.caretPos), + ].join(''); } if (emailInput.focusKey === 'body') { - emailInput.body += ` ${item.value}`; + emailInput.body = [ + emailInput.body.slice(0, emailInput.caretPos), + `${item.value}`, + emailInput.body.slice(emailInput.caretPos), + ].join(''); } + + emailInput.caretPos += `${item.value}`.length; } /** @@ -278,6 +292,14 @@ export class GroupComponent implements OnInit, AfterViewInit { emailInput.focusKey = key; } + /** + * @emailInput this is the object that contains the email input + * @caretPosition pos caret position + */ + setFocusOutPos(emailInput: EmailInput, caretPosition: number) { + emailInput.caretPos = caretPosition; + } + /** * If the type is an action, set the node list to the actions, otherwise if the type is an event, set * the node list to the trigger events if there is only one event group and no children, otherwise diff --git a/projects/workflows-creator/src/lib/types/base.types.ts b/projects/workflows-creator/src/lib/types/base.types.ts index 91916cf..d38576f 100644 --- a/projects/workflows-creator/src/lib/types/base.types.ts +++ b/projects/workflows-creator/src/lib/types/base.types.ts @@ -172,6 +172,7 @@ export type EmailInput = { subject: string; body: string; focusKey: string; + caretPos: number; }; /** From 315d7a5adb099b4f735dfacb4ea505b5b3784fe3 Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Thu, 6 Jul 2023 17:01:07 +0530 Subject: [PATCH 08/19] feat(core): setting output var in send email service task GH-9 --- .../src/lib/services/bpmn/elements/tasks/send-email.task.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/send-email.task.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/send-email.task.ts index fb309e8..f52ef29 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/send-email.task.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/send-email.task.ts @@ -54,7 +54,8 @@ export class SendEmail extends ServiceTaskElement { }, }, }; - outputs: string; + + outputs = 'outputVariable'; static identifier = 'SendEmail'; getIdentifier(): string { From 5336a42eadfd9a1d7e13c0698a730a1594e42512 Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Fri, 14 Jul 2023 17:03:21 +0530 Subject: [PATCH 09/19] fix(core): escape double quotes in email body and subject GH-9 --- .../src/lib/builder/group/group.component.ts | 7 +++++++ .../src/lib/classes/nodes/abstract-prompt.class.ts | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index 86ab847..a5464cc 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -225,6 +225,13 @@ export class GroupComponent implements OnInit, AfterViewInit { if (allowedInputs.includes(input.getIdentifier())) { const value = input.getModelValue(nodeWithInput.node.state); if (nodeWithInput.node.state.get('email')) { + (value as AllowedValuesMap).body = ( + (value as AllowedValuesMap).body as string + ).replace(/\\"/g, '"'); + (value as AllowedValuesMap).subject = ( + (value as AllowedValuesMap).subject as string + ).replace(/\\"/g, '"'); + this.emailInput = value; } else { switch (nodeWithInput.node.state.get('valueInputType')) { diff --git a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts index 67afaec..a4c73e0 100644 --- a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts +++ b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts @@ -94,6 +94,12 @@ export abstract class WorkflowPrompt { const dateTime = `${this.onDateSelect(date)} ${hours}:${min}`; return moment(dateTime.toString(), 'DD-MM-YYYY hh:mm').format(); case InputTypes.Email: + (value as AllowedValuesMap).body = ( + (value as AllowedValuesMap).body as string + ).replace(/"/g, '\\"'); + (value as AllowedValuesMap).subject = ( + (value as AllowedValuesMap).subject as string + ).replace(/"/g, '\\"'); (value as AllowedValuesMap).displayValue = 'email'; return value; case InputTypes.Number: From 27880b475145fbc7679dd6da9035747710b5c72b Mon Sep 17 00:00:00 2001 From: Maninder Pal Singh Date: Tue, 18 Jul 2023 19:06:36 +0530 Subject: [PATCH 10/19] fix(core): message and subject getting copied to fresh email popup GH-9 --- .../src/lib/builder/group/group.component.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index a5464cc..776c70b 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -400,11 +400,21 @@ export class GroupComponent implements OnInit, AfterViewInit { input.setValue(element.node.state, value), input.typeFunction(element.node.state) === InputTypes.List, ); + this.clearValues(); } popper.hide(); }; } + private clearValues() { + this.emailInput = { + subject: '', + body: '', + focusKey: '', + caretPos: 0, + }; + } + /** * It hides the previous popper and shows the current popper. * @param {MouseEvent} event - MouseEvent - The event that triggered the popper to show. From b8d28784e05e6ceae1a6d34d5cf8fd7e6a0ce2e4 Mon Sep 17 00:00:00 2001 From: Nilesh Kumar <97959767+nileshkumar-sf@users.noreply.github.com> Date: Thu, 8 Feb 2024 19:50:45 +0530 Subject: [PATCH 11/19] feat(core): add custom date option handling in events (#43) --- .../src/lib/builder/builder.component.ts | 9 ++++--- .../strategies/link/gateway-link.strategy.ts | 25 ++++++++++++++++--- .../services/statement/inputs/value.input.ts | 1 + .../statement/inputs/valuetype.input.ts | 1 + 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index 54ab80d..95f9fb1 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -493,9 +493,12 @@ export class BuilderComponent implements OnInit, OnChanges { node.node.state.get('condition') === ConditionTypes.PastToday ? true : !!node.node.state.get('value'); - const valueTypeIsAnyValue = - node.node.state.get('valueType') === ValueTypes.AnyValue; - isValid = columnExists && (valueExists || valueTypeIsAnyValue); + const valueTypeIsSufficient = [ + ValueTypes.AnyValue, + ValueTypes.Today, + ValueTypes.PastToday, + ].includes(node.node.state.get('valueType')); + isValid = columnExists && (valueExists || valueTypeIsSufficient); break; case EventTypes.OnIntervalEvent: const intervalExists = !!node.node.state.get('interval'); diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index 5c1b551..5d79f97 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -224,10 +224,11 @@ export class GatewayLinkStrategy implements LinkStrategy { ) { const column: string = node.workflowNode.state.get('columnName'); const conditionType = node.workflowNode.state.get('condition'); - const value = node.workflowNode.state.get('value'); + const valueType = node.workflowNode.state.get('valueType'); + const valueInputType = node.workflowNode.state.get('valueInputType'); - if (!conditionType && value) { - switch (value) { + if (!conditionType && valueType && valueInputType === InputTypes.Date) { + switch (valueType) { case ValueTypes.PastToday: return ` for(var key in readObj){ @@ -252,6 +253,22 @@ export class GatewayLinkStrategy implements LinkStrategy { } } `; + case ValueTypes.Custom: + return ` + for (var key in readObj) { + var taskValuePair = readObj[key]; + if (taskValuePair && taskValuePair.value) { + var readDateValue = taskValuePair.value.split('T')[0]; + var customDate = "${condition}"; + + if (${ + isElse ? '!' : '' + }(readDateValue === customDate)) { + ids.push(taskValuePair.id); + } + } + } + `; } } @@ -383,6 +400,8 @@ export class GatewayLinkStrategy implements LinkStrategy { break; case InputTypes.People: return `'${value.ids}'`; + case InputTypes.Date: + return `${value.split('T')[0]}`; } const condition = node.workflowNode.state.get('condition'); const pair = this.conditions.find(item => item.condition === condition); diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts index 293db18..83af419 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts @@ -32,6 +32,7 @@ export class ValueInput extends WorkflowListPrompt { InputTypes.Number, InputTypes.People, InputTypes.Percentage, + InputTypes.Date, ].includes(node.state.get('valueInputType')) && node.state.get('valueType') !== ValueTypes.Custom) ); diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts index 58ad5fc..ac19a9b 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts @@ -20,6 +20,7 @@ export class ValueTypeInput extends WorkflowListPrompt { InputTypes.Number, InputTypes.People, InputTypes.Percentage, + InputTypes.Date, ].includes(node.state.get('valueInputType')); }; From 090187cd4b8cecc3d1341114d676c12aa2ac2b4d Mon Sep 17 00:00:00 2001 From: abhinavverma-sf <85155309+abhinavverma-sf@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:43:10 +0530 Subject: [PATCH 12/19] fix(core): camunda update changes and valueType anyValue fix (#85) * fix(core): fix valuetype any change fix valuetype any change GH-9-valueAny * fix(core): saurabh sinha json changes saurabh sinha json changes GH-9-valueAny --------- Co-authored-by: Abhinav Verma --- .../src/lib/builder/builder.component.ts | 2 +- projects/workflows-creator/src/lib/const.ts | 10 ++-- .../bpmn/elements/gateways/gateway.element.ts | 4 +- .../bpmn/elements/process/process.element.ts | 3 +- .../strategies/create/task-create.strategy.ts | 53 ++++++++++++------- .../strategies/link/gateway-link.strategy.ts | 28 ++++++++-- .../link/or-gateway-link.strategy.ts | 7 +-- 7 files changed, 71 insertions(+), 36 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index 95f9fb1..fd2dec2 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -373,7 +373,7 @@ export class BuilderComponent implements OnInit, OnChanges { ) { if ( ((value as AllowedValuesMap)?.value as AllowedValuesMap)?.value === - ValueTypes.AnyValue + ValueTypes.AnyValue || ((value as AllowedValuesMap)?.value === ValueTypes.AnyValue) ) { /** * Remove node on changes event diff --git a/projects/workflows-creator/src/lib/const.ts b/projects/workflows-creator/src/lib/const.ts index 65c943d..4050e0f 100644 --- a/projects/workflows-creator/src/lib/const.ts +++ b/projects/workflows-creator/src/lib/const.ts @@ -14,14 +14,14 @@ xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1aj5pzu" targetNamespace="http://bpmn.io/schema/bpmn" -exporter="Camunda Modeler" exporterVersion="4.12.0" +exporter="Camunda Modeler" exporterVersion="5.21.0" modeler:executionPlatform="Camunda Platform" -modeler:executionPlatformVersion="7.15.0"> +modeler:executionPlatformVersion="7.21.0"> `; -export const JSON_SCRIPT_START = `var json = S(\"{}\");\n`; -export const JSON_SCRIPT_END = `\n json`; +export const JSON_SCRIPT_START = `var json = {};\n`; +export const JSON_SCRIPT_END = `\n JSON.stringify(json)`; export const BASE_XML = new InjectionToken('diagram.bpmn.base'); export const MODDLE = new InjectionToken( @@ -48,4 +48,4 @@ export const typeTuppleList: Array = [ {condition: ConditionTypes.LessThan, operator: '<', value: true}, {condition: ConditionTypes.ComingIn, operator: '-', value: true}, {condition: ConditionTypes.PastBy, operator: '+', value: true}, -]; +]; \ No newline at end of file diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts index 6c178e5..9840a38 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts @@ -21,7 +21,7 @@ export class GatewayElement extends BpmnElement { ) { super(); } - tag = 'bpmn:ExclusiveGateway'; + tag = 'bpmn:InclusiveGateway'; name = 'gateway'; properties = {}; statement: string | undefined; @@ -40,4 +40,4 @@ export class GatewayElement extends BpmnElement { getIdentifier(): string { return GatewayElement.identifier; } -} +} \ No newline at end of file diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts index 059f7ba..9aec485 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts @@ -30,9 +30,10 @@ export class ProcessElement extends BpmnElement { static identifier = 'ProcessElement'; attributes = { isExecutable: true, + historyTimeToLive: 'P3650D', }; getIdentifier(): string { return ProcessElement.identifier; } -} +} \ No newline at end of file diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts index 72562df..aef6847 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts @@ -142,38 +142,53 @@ export class CreateTaskStrategy implements CreateStrategy { let read = ''; if (froms.length > 0) { if (prevIds.length) { - read = `var readObj = ${prevIds - .map(id => `JSON.parse(execution.getVariable('${id}'))`) - .join(' || ')} || {};`; + read = `${prevIds + .map( + (id, index) => + `var readObj${index} = JSON.parse(execution.getVariable('${id}')) || {};`, + ) + .join('\n')} + `; } } - const getVariables = froms - .map( - p => - `var ${(p as FromParam).from}Local = readObj.${ - (p as FromParam).from - };`, - ) - .join('\n'); + const getVariables = froms.map( + p => + ` + var ${(p as FromParam).from}Local; + ${prevIds + .map( + (_: any, index: number) => ` + if(readObj${index}.${ + (p as FromParam).from + } && readObj${index}.${(froms[0] as FromParam).from}.length){ + ${(froms[0] as FromParam).from}Local = readObj${index}.${ + (froms[0] as FromParam).from + }; + } + `, + ) + .join('\n')} + `, + ); const setVariabels = Object.keys(params).reduce( (p: string, key: string) => { const tmp = params[key]; if (isFormattedParam(tmp)) { - return `${p}\njson.prop("${key}", ${tmp.formatter(state)});`; + return `${p}\njson["${key}"] = ${tmp.formatter(state)};`; } else if (isFromParam(tmp)) { - return `${p}\njson.prop("${key}", ${tmp.from}Local);`; + return `${p}\njson["${key}"] = ${tmp.from}Local;`; } else if (isStateParam(tmp)) { if ( tmp.state === 'recipients' && Array.isArray(state.get(tmp.state)) ) { const metaValue = this.transposeArrayToString(state.get(tmp.state)); - return `${p}\njson.prop("${key}", [${metaValue ?? ''}]);`; + return `${p}\njson["${key}"] = [${metaValue ?? ''}];`; } - return `${p}\njson.prop("${key}", "${state.get(tmp.state) ?? ''}");`; + return `${p}\njson["${key}"] = "${state.get(tmp.state) ?? ''}";`; } else { - return `${p}\njson.prop("${key}", "${tmp.value}");`; + return `${p}\njson["${key}"] = "${tmp.value}";`; } }, '', @@ -181,9 +196,9 @@ export class CreateTaskStrategy implements CreateStrategy { return [ read, getVariables, - `var json = S("{}");`, + `var json = {};`, setVariabels, - 'json', + 'JSON.stringify(json)', ].join('\n'); } @@ -207,4 +222,4 @@ export class CreateTaskStrategy implements CreateStrategy { return [node.prev[0].element.id]; } } -} +} \ No newline at end of file diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index 5d79f97..32342b8 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -193,12 +193,13 @@ export class GatewayLinkStrategy implements LinkStrategy { ) { const lastNodeWithOutput = this.getLastNodeWithOutput(node); const read = `var readObj = JSON.parse(execution.getVariable('${lastNodeWithOutput.element.id}'));`; - const declarations = `var ids = [];var json = S("{}");`; + const declarations = `var ids = [];var json = {};`; const column = node.workflowNode.state.get('columnName'); const condition = this.getCondition(node); const loop = this.createLoopScript(node, condition, isElse); const setters = ` - json.prop("taskIds", ids); + json["taskIds"] = ids; + json = JSON.stringify(json); execution.setVariable('${flowId}',json); if(ids.length > 0){true;}else {false;} `; @@ -227,6 +228,25 @@ export class GatewayLinkStrategy implements LinkStrategy { const valueType = node.workflowNode.state.get('valueType'); const valueInputType = node.workflowNode.state.get('valueInputType'); + if ( + valueInputType === InputTypes.Date && + (valueType === ValueTypes.Custom || + conditionType === ConditionTypes.Equal) + ) { + return ` + for (var key in readObj) { + var taskValuePair = readObj[key]; + if (taskValuePair && (taskValuePair.value || taskValuePair.value==='')) { + var readDateValue = taskValuePair.value.split('T')[0]; + var customDate = "${condition}"; + + if (${isElse ? '!' : ''}(readDateValue === customDate)) { + ids.push(taskValuePair.id); + } + } + } + `; + } if (!conditionType && valueType && valueInputType === InputTypes.Date) { switch (valueType) { case ValueTypes.PastToday: @@ -261,9 +281,7 @@ export class GatewayLinkStrategy implements LinkStrategy { var readDateValue = taskValuePair.value.split('T')[0]; var customDate = "${condition}"; - if (${ - isElse ? '!' : '' - }(readDateValue === customDate)) { + if (${isElse ? '!' : ''}(readDateValue === customDate)) { ids.push(taskValuePair.id); } } diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts index f20ddfc..dd81fd3 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts @@ -112,12 +112,13 @@ export class OrGatewayLinkStrategy implements LinkStrategy { ) { const lastNodeWithOutput = this.getLastNodeWithOutput(node); const read = `var readObj = JSON.parse(execution.getVariable('${lastNodeWithOutput.element.id}'));`; - const declarations = `var ids = [];var json = S("{}");`; + const declarations = `var ids = [];var json = {};`; const column = node.workflowNode.state.get('columnName'); const condition = this.getCondition(node); const loop = this.createLoopScript(node, condition, isElse); const setters = ` - json.prop("taskIds", ids); + json["taskIds"] = ids; + json.stringify(json); execution.setVariable('${flowId}',json); if(ids.length > 0){true;}else {false;} `; @@ -229,4 +230,4 @@ export class OrGatewayLinkStrategy implements LinkStrategy { return `${pair.operator}`; } } -} +} \ No newline at end of file From 242eaeb3329bc952bb5abe8117d98f89c4af1a4a Mon Sep 17 00:00:00 2001 From: VipulSha99 <107537420+VipulSha99@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:13:19 +0530 Subject: [PATCH 13/19] feat(core): add criteriaInput and optionlist for add a condition (#86) --- .../src/lib/builder/group/group.component.ts | 4 +++- .../classes/nodes/abstract-prompt.class.ts | 3 +++ projects/workflows-creator/src/lib/enum.ts | 2 ++ .../tasks/change-column-value.task.ts | 1 + .../bpmn/elements/tasks/read-column.task.ts | 3 +++ .../strategies/link/gateway-link.strategy.ts | 23 +++++++++++++++++++ .../statement/events/onvalue.event.ts | 4 ++-- .../statement/inputs/criteria.input.ts | 20 ++++++++++++++++ .../lib/services/statement/inputs/index.ts | 1 + .../services/statement/inputs/value.input.ts | 2 +- .../src/lib/workflow-builder.module.ts | 2 ++ 11 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index 776c70b..104c5be 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -212,6 +212,8 @@ export class GroupComponent implements OnInit, AfterViewInit { this.templateMap?.[InputTypes.Interval] || this.listTemplate, [InputTypes.Email]: this.templateMap?.[InputTypes.Email] || this.emailTemplate, + [InputTypes.OptionList]: + this.templateMap?.[InputTypes.OptionList] || this.listTemplate, }; } @@ -398,7 +400,7 @@ export class GroupComponent implements OnInit, AfterViewInit { element, input, input.setValue(element.node.state, value), - input.typeFunction(element.node.state) === InputTypes.List, + input.typeFunction(element.node.state) === InputTypes.List || input.typeFunction(element.node.state) === InputTypes.OptionList, ); this.clearValues(); } diff --git a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts index a4c73e0..ad135b9 100644 --- a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts +++ b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts @@ -54,6 +54,7 @@ export abstract class WorkflowPrompt { value: AllowedValues | AllowedValuesMap, ) { switch (this.typeFunction(state)) { + case InputTypes.OptionList: case InputTypes.List: return value; case InputTypes.People: { @@ -146,6 +147,7 @@ export abstract class WorkflowPrompt { */ getValueName(state: State) { switch (this.typeFunction(state)) { + case InputTypes.OptionList: case InputTypes.List: if (typeof state.get(`${this.inputKey}Name`) === 'object') { return state.get(`${this.inputKey}Name`)?.displayValue; @@ -184,6 +186,7 @@ export abstract class WorkflowPrompt { */ setValueName(state: State) { switch (this.typeFunction(state)) { + case InputTypes.OptionList: case InputTypes.List: if ( typeof state.get(this.inputKey) === 'object' && diff --git a/projects/workflows-creator/src/lib/enum.ts b/projects/workflows-creator/src/lib/enum.ts index 189ef9a..b44c535 100644 --- a/projects/workflows-creator/src/lib/enum.ts +++ b/projects/workflows-creator/src/lib/enum.ts @@ -20,6 +20,8 @@ export enum InputTypes { People = 'people', Percentage = 'percentage', Text = 'text', + OptionList = "optionList", + Item = 'Item' } /* Defining the types of conditions that can be used in the application. */ diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts index 9d077fd..26d9262 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/change-column-value.task.ts @@ -45,6 +45,7 @@ export class ChangeColumnValue extends ServiceTaskElement { switch (state.get('valueInputType')) { case InputTypes.People: return `'${JSON.stringify(state.get('value'))}'`; + case InputTypes.OptionList: case InputTypes.List: if (!state.get('value')) return ''; return `'${JSON.stringify({ diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/read-column.task.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/read-column.task.ts index 5d7d7fd..64c116c 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/read-column.task.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/tasks/read-column.task.ts @@ -32,6 +32,9 @@ export class ReadColumnValue extends ServiceTaskElement { taskIds: { from: 'taskIds', }, + metaData: { + state: 'metaData', + }, groupColumnId: { state: 'column', }, diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index 32342b8..d734dee 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -337,6 +337,28 @@ export class GatewayLinkStrategy implements LinkStrategy { } }`; } + if (column === InputTypes.Item) { + return `var selectedVals = ${condition}; + var selCol = selectedVals.split(','); + for(var key in readObj){ + var taskValuePair = readObj[key]; + if(taskValuePair && taskValuePair.value && taskValuePair.value.length){ + var hasItem = false; + var usCol = taskValuePair.value; + + for(var selKey in selCol){ + for(var myKey in usCol){ + if(usCol[myKey].value == selCol[selKey] && !hasItem){ + hasItem = true; + } + } + } + if(${conditionExpression}(hasItem)){ + ids.push(taskValuePair.id); + } + } + }`; + } switch (conditionType) { case ConditionTypes.PastToday: return ` @@ -413,6 +435,7 @@ export class GatewayLinkStrategy implements LinkStrategy { case InputTypes.Text: value = `'${value}'`; break; + case InputTypes.OptionList: case InputTypes.List: value = `'${value.value}'`; break; diff --git a/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts b/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts index a8c4c41..a8458dd 100644 --- a/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts +++ b/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts @@ -3,8 +3,8 @@ import {RecordOfAnyType} from '../../../types'; import {BpmnEvent} from '../../../types/bpmn.types'; import {GatewayElement} from '../../bpmn/elements/gateways/gateway.element'; import {ReadColumnValue} from '../../bpmn/elements/tasks/read-column.task'; -import {ColumnInput} from '../inputs/column.input'; import {ConditionInput} from '../inputs/condition.input'; +import { CriteriaInput } from '../inputs/criteria.input'; import {ValueInput} from '../inputs/value.input'; export class OnValueEvent extends BpmnEvent { @@ -16,7 +16,7 @@ export class OnValueEvent extends BpmnEvent { statement = 'check if '; properties = {}; prompts = [ - ColumnInput.identifier, + CriteriaInput.identifier, ConditionInput.identifier, ValueInput.identifier, ]; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts new file mode 100644 index 0000000..8817e01 --- /dev/null +++ b/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts @@ -0,0 +1,20 @@ +import {State, WorkflowPrompt} from '../../../classes'; +import {InputTypes} from '../../../enum'; +import {RecordOfAnyType} from '../../../types'; + +export class CriteriaInput extends WorkflowPrompt { + prefix = ''; + suffix = ''; + typeFunction = () => InputTypes.OptionList; + inputKey = 'column'; + listNameField = 'text'; + listValueField = 'value'; + placeholder = 'Criteria'; + options = (state: State) => + state.get('columns'); + static identifier = 'CriteriaInput'; + + getIdentifier(): string { + return CriteriaInput.identifier; + } +} diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/index.ts b/projects/workflows-creator/src/lib/services/statement/inputs/index.ts index ea94d81..3fdeb2c 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/index.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/index.ts @@ -7,3 +7,4 @@ export * from './value.input'; export * from './interval.input'; export * from './triggercolumn.input'; export * from './valuetype.input'; +export * from './criteria.input'; \ No newline at end of file diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts index 83af419..b1cb912 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts @@ -9,7 +9,7 @@ import { import {BpmnNode, RecordOfAnyType} from '../../../types'; export class ValueInput extends WorkflowListPrompt { - prefix: string | {state: string} = ''; + prefix: string | {state: string} = {state: 'valuePrefix'}; suffix: string | {state: string} = {state: 'valueSuffix'}; inputKey = 'value'; listNameField = 'text'; diff --git a/projects/workflows-creator/src/lib/workflow-builder.module.ts b/projects/workflows-creator/src/lib/workflow-builder.module.ts index 2501d7d..fe0b382 100644 --- a/projects/workflows-creator/src/lib/workflow-builder.module.ts +++ b/projects/workflows-creator/src/lib/workflow-builder.module.ts @@ -89,6 +89,7 @@ import {TriggerColumnInput} from './services/statement/inputs/triggercolumn.inpu import {ValueTypeInput} from './services/statement/inputs/valuetype.input'; import {TooltipRenderComponent} from './builder/tooltip-render/tooltip-render.component'; import {LocalizationPipe} from './pipes/localization.pipe'; +import { CriteriaInput } from './services'; @NgModule({ declarations: [ BuilderComponent, @@ -143,6 +144,7 @@ import {LocalizationPipe} from './pipes/localization.pipe'; {provide: BPMN_ELEMENTS, useClass: ChangeColumnValue, multi: true}, {provide: BPMN_ELEMENTS, useClass: ProcessPropertiesElement, multi: true}, {provide: BPMN_INPUTS, useClass: ColumnInput, multi: true}, + {provide: BPMN_INPUTS, useClass: CriteriaInput, multi: true}, {provide: BPMN_INPUTS, useClass: TriggerColumnInput, multi: true}, {provide: BPMN_INPUTS, useClass: IntervalInput, multi: true}, {provide: BPMN_INPUTS, useClass: ConditionInput, multi: true}, From 2a7d458459bcff2f474236110631f292f4a17972 Mon Sep 17 00:00:00 2001 From: VipulSha99 <107537420+VipulSha99@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:49:52 +0530 Subject: [PATCH 14/19] feat(core): add timeinterval for the interval trigger in workflow (#88) * feat(core): add timeinterval for the interval trigger in workflow * refactor(core): add changes --- .../src/lib/builder/builder.component.ts | 3 +- .../src/lib/builder/group/group.component.ts | 11 +++- .../classes/nodes/abstract-prompt.class.ts | 6 ++ projects/workflows-creator/src/lib/const.ts | 2 +- projects/workflows-creator/src/lib/enum.ts | 16 ++++- .../bpmn/elements/gateways/gateway.element.ts | 2 +- .../bpmn/elements/process/process.element.ts | 2 +- .../create/basic-interval-create.strategy.ts | 63 +++++++++++++++++-- .../strategies/create/task-create.strategy.ts | 2 +- .../strategies/link/gateway-link.strategy.ts | 1 + .../link/or-gateway-link.strategy.ts | 2 +- .../statement/events/oninterval.event.ts | 10 ++- .../statement/events/onvalue.event.ts | 2 +- .../lib/services/statement/inputs/index.ts | 5 +- .../statement/inputs/interval.input.ts | 4 +- .../statement/inputs/stepper.input.ts | 21 +++++++ .../statement/inputs/timeinterval.input.ts | 30 +++++++++ .../statement/inputs/tointerval.input.ts | 30 +++++++++ .../src/lib/workflow-builder.module.ts | 10 ++- 19 files changed, 201 insertions(+), 21 deletions(-) create mode 100644 projects/workflows-creator/src/lib/services/statement/inputs/stepper.input.ts create mode 100644 projects/workflows-creator/src/lib/services/statement/inputs/timeinterval.input.ts create mode 100644 projects/workflows-creator/src/lib/services/statement/inputs/tointerval.input.ts diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index fd2dec2..d779b16 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -373,7 +373,8 @@ export class BuilderComponent implements OnInit, OnChanges { ) { if ( ((value as AllowedValuesMap)?.value as AllowedValuesMap)?.value === - ValueTypes.AnyValue || ((value as AllowedValuesMap)?.value === ValueTypes.AnyValue) + ValueTypes.AnyValue || + (value as AllowedValuesMap)?.value === ValueTypes.AnyValue ) { /** * Remove node on changes event diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index 104c5be..a091558 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -213,7 +213,13 @@ export class GroupComponent implements OnInit, AfterViewInit { [InputTypes.Email]: this.templateMap?.[InputTypes.Email] || this.emailTemplate, [InputTypes.OptionList]: - this.templateMap?.[InputTypes.OptionList] || this.listTemplate, + this.templateMap?.[InputTypes.OptionList] || this.listTemplate, + [InputTypes.Stepper]: + this.templateMap?.[InputTypes.Stepper] || this.listTemplate, + [InputTypes.IntervalDate]: + this.templateMap?.[InputTypes.IntervalDate] || this.listTemplate, + [InputTypes.IntervalTime]: + this.templateMap?.[InputTypes.IntervalTime] || this.listTemplate, }; } @@ -400,7 +406,8 @@ export class GroupComponent implements OnInit, AfterViewInit { element, input, input.setValue(element.node.state, value), - input.typeFunction(element.node.state) === InputTypes.List || input.typeFunction(element.node.state) === InputTypes.OptionList, + input.typeFunction(element.node.state) === InputTypes.List || + input.typeFunction(element.node.state) === InputTypes.OptionList, ); this.clearValues(); } diff --git a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts index ad135b9..30dda6e 100644 --- a/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts +++ b/projects/workflows-creator/src/lib/classes/nodes/abstract-prompt.class.ts @@ -107,6 +107,7 @@ export abstract class WorkflowPrompt { case InputTypes.Text: case InputTypes.Boolean: case InputTypes.Percentage: + case InputTypes.Stepper: default: if (value) { return (value as HTMLInputElement).value; @@ -169,10 +170,14 @@ export abstract class WorkflowPrompt { .utc(state.get(this.inputKey), 'YYYY-MM-DD hh:mm') .format('MMM DD, YYYY hh:mm A') : ''; + case InputTypes.IntervalDate: + case InputTypes.IntervalTime: + return state.get(this.inputKey)?.value; case InputTypes.Number: case InputTypes.Text: case InputTypes.Boolean: case InputTypes.Percentage: + case InputTypes.Stepper: default: return state.get(this.inputKey); } @@ -209,6 +214,7 @@ export abstract class WorkflowPrompt { case InputTypes.Text: case InputTypes.Boolean: case InputTypes.Percentage: + case InputTypes.Stepper: default: return state.get(this.inputKey); } diff --git a/projects/workflows-creator/src/lib/const.ts b/projects/workflows-creator/src/lib/const.ts index 4050e0f..092f4ce 100644 --- a/projects/workflows-creator/src/lib/const.ts +++ b/projects/workflows-creator/src/lib/const.ts @@ -48,4 +48,4 @@ export const typeTuppleList: Array = [ {condition: ConditionTypes.LessThan, operator: '<', value: true}, {condition: ConditionTypes.ComingIn, operator: '-', value: true}, {condition: ConditionTypes.PastBy, operator: '+', value: true}, -]; \ No newline at end of file +]; diff --git a/projects/workflows-creator/src/lib/enum.ts b/projects/workflows-creator/src/lib/enum.ts index b44c535..0e9d3da 100644 --- a/projects/workflows-creator/src/lib/enum.ts +++ b/projects/workflows-creator/src/lib/enum.ts @@ -20,8 +20,11 @@ export enum InputTypes { People = 'people', Percentage = 'percentage', Text = 'text', - OptionList = "optionList", - Item = 'Item' + OptionList = 'optionList', + Item = 'Item', + Stepper = 'Stepper', + IntervalDate = 'IntervalDate', + IntervalTime = 'IntervalTime', } /* Defining the types of conditions that can be used in the application. */ @@ -108,3 +111,12 @@ export enum LocalizedStringKeys { SelectColumnTooltip = 'selectColumnTooltip', SetLbl = 'setLbl', } + +export enum IntervalType { + Day = 'day', + Days = 'days', + Weeks = 'weeks', + Months = 'months', + Week = 'week', + Month = 'month', +} diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts index 9840a38..74b653f 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/gateways/gateway.element.ts @@ -40,4 +40,4 @@ export class GatewayElement extends BpmnElement { getIdentifier(): string { return GatewayElement.identifier; } -} \ No newline at end of file +} diff --git a/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts b/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts index 9aec485..0c30ab4 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/elements/process/process.element.ts @@ -36,4 +36,4 @@ export class ProcessElement extends BpmnElement { getIdentifier(): string { return ProcessElement.identifier; } -} \ No newline at end of file +} diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/basic-interval-create.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/basic-interval-create.strategy.ts index 8813cf2..61da4f7 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/basic-interval-create.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/basic-interval-create.strategy.ts @@ -7,7 +7,17 @@ import { ModdleElement, RecordOfAnyType, } from '../../../../types'; -import {WorkflowElement} from '../../../../classes'; +import {State, WorkflowElement} from '../../../../classes'; + +enum WeekDaysEnum { + sunday = 1, + monday = 2, + tuesday = 3, + wednesday = 4, + thursday = 5, + friday = 6, + saturday = 7, +} @Injectable() export class CreateBasicIntervalStrategy @@ -38,9 +48,7 @@ export class CreateBasicIntervalStrategy const state = workflowNode.state; const timeCycle = this.moddle.create('bpmn:FormalExpression', { 'xsi:type': 'bpmn:tFormalExpression', - body: `R/P${state.get('timescale')}${state.get('value')}${state.get( - 'interval', - )}`, + body: this.intervalBodyPrepare(state), }); timerEventDefinition['timeCycle'] = timeCycle; @@ -53,6 +61,53 @@ export class CreateBasicIntervalStrategy }); } + private intervalBodyPrepare(state: State) { + if ( + state.get('interval') === 'M' && + state.get('toInterval') && + state.get('TimeInterval') + ) { + const val = + state.get('value') == 1 + ? '*' + : `${state.get('toInterval').month}/${state.get('value')}`; + const timeZoneDate = new Date(); + timeZoneDate.setHours(state.get('TimeInterval').hour); + timeZoneDate.setMinutes(state.get('TimeInterval').min); + return `0 timeZoneDate(${timeZoneDate})timeZoneDateEnd ${ + state.get('toInterval').date + } ${val} ?`; + } else if ( + state.get('interval') === 'W' && + state.get('toInterval') && + state.get('TimeInterval') + ) { + const val = state.get('value') == 1 ? '' : `/${state.get('value')}`; + let weekDays = state + .get('toInterval') + ?.ids?.map( + (day: string) => WeekDaysEnum[day as keyof typeof WeekDaysEnum], + ) + .join(','); + const timeZoneDate = new Date(); + timeZoneDate.setHours(state.get('TimeInterval').hour); + timeZoneDate.setMinutes(state.get('TimeInterval').min); + return `0 timeZoneDate(${timeZoneDate})timeZoneDateEnd ? * ${weekDays}${val}`; + } else if (state.get('interval') === 'D' && state.get('TimeInterval')) { + const today = new Date(); + today.setHours(state.get('TimeInterval').hour); + today.setMinutes(state.get('TimeInterval').min); + let isoString = ''; + if (today.getTime() < new Date().getTime()) { + today.setDate(today.getDate() + 1); + } + isoString = today.toISOString(); + return `R/${isoString}/P${state.get('value')}${state.get('interval')}`; + } else { + return '0 0 0 ? * *'; + } + } + /** * It takes an object of attributes and a node, and returns the same object of attributes, but with * any attribute that is a state reference replaced with the value of that state diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts index aef6847..b18d0f4 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/create/task-create.strategy.ts @@ -222,4 +222,4 @@ export class CreateTaskStrategy implements CreateStrategy { return [node.prev[0].element.id]; } } -} \ No newline at end of file +} diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts index d734dee..d936798 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/gateway-link.strategy.ts @@ -432,6 +432,7 @@ export class GatewayLinkStrategy implements LinkStrategy { const valueType = node.workflowNode.state.get('valueInputType'); if (value) switch (valueType) { + case InputTypes.Stepper: case InputTypes.Text: value = `'${value}'`; break; diff --git a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts index dd81fd3..2ed9de6 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/strategies/link/or-gateway-link.strategy.ts @@ -230,4 +230,4 @@ export class OrGatewayLinkStrategy implements LinkStrategy { return `${pair.operator}`; } } -} \ No newline at end of file +} diff --git a/projects/workflows-creator/src/lib/services/statement/events/oninterval.event.ts b/projects/workflows-creator/src/lib/services/statement/events/oninterval.event.ts index 60b3434..26fa0f1 100644 --- a/projects/workflows-creator/src/lib/services/statement/events/oninterval.event.ts +++ b/projects/workflows-creator/src/lib/services/statement/events/oninterval.event.ts @@ -2,8 +2,9 @@ import {LocalizedStringKeys, StartElementTypes} from '../../../enum'; import {RecordOfAnyType} from '../../../types'; import {BpmnEvent} from '../../../types/bpmn.types'; import {TriggerOnInterval} from '../../bpmn/elements/tasks/trigger-on-interval.task'; +import {TimeIntervalInput, ToIntervalInput} from '../inputs'; import {IntervalInput} from '../inputs/interval.input'; -import {ValueInput} from '../inputs/value.input'; +import {StepperInput} from '../inputs/stepper.input'; export class OnIntervalEvent extends BpmnEvent { groupType: string; @@ -14,7 +15,12 @@ export class OnIntervalEvent extends BpmnEvent { name = 'On Interval'; statement = 'Every '; properties = {}; - prompts = [ValueInput.identifier, IntervalInput.identifier]; + prompts = [ + StepperInput.identifier, + IntervalInput.identifier, + ToIntervalInput.identifier, + TimeIntervalInput.identifier, + ]; static identifier = 'OnIntervalEvent'; constructor( localizedStringMap: RecordOfAnyType, diff --git a/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts b/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts index a8458dd..f792117 100644 --- a/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts +++ b/projects/workflows-creator/src/lib/services/statement/events/onvalue.event.ts @@ -4,7 +4,7 @@ import {BpmnEvent} from '../../../types/bpmn.types'; import {GatewayElement} from '../../bpmn/elements/gateways/gateway.element'; import {ReadColumnValue} from '../../bpmn/elements/tasks/read-column.task'; import {ConditionInput} from '../inputs/condition.input'; -import { CriteriaInput } from '../inputs/criteria.input'; +import {CriteriaInput} from '../inputs/criteria.input'; import {ValueInput} from '../inputs/value.input'; export class OnValueEvent extends BpmnEvent { diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/index.ts b/projects/workflows-creator/src/lib/services/statement/inputs/index.ts index 3fdeb2c..9207aaa 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/index.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/index.ts @@ -7,4 +7,7 @@ export * from './value.input'; export * from './interval.input'; export * from './triggercolumn.input'; export * from './valuetype.input'; -export * from './criteria.input'; \ No newline at end of file +export * from './criteria.input'; +export * from './stepper.input'; +export * from './tointerval.input'; +export * from './timeinterval.input'; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts index dbae337..e51f618 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts @@ -3,8 +3,8 @@ import {InputTypes} from '../../../enum'; import {RecordOfAnyType} from '../../../types'; export class IntervalInput extends WorkflowPrompt { - prefix = ''; - suffix = ''; + prefix: string | {state: string} = {state: 'valuePrefix'}; + suffix: string | {state: string} = {state: 'intervalValueSuffix'}; typeFunction = () => InputTypes.List; inputKey = 'interval'; listNameField = 'text'; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/stepper.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/stepper.input.ts new file mode 100644 index 0000000..06433e9 --- /dev/null +++ b/projects/workflows-creator/src/lib/services/statement/inputs/stepper.input.ts @@ -0,0 +1,21 @@ +import {State, WorkflowPrompt} from '../../../classes'; +import {InputTypes} from '../../../enum'; +import {RecordOfAnyType} from '../../../types'; + +export class StepperInput extends WorkflowPrompt { + prefix = ''; + suffix = ''; + typeFunction = () => InputTypes.Stepper; + inputKey = 'value'; + listNameField = 'text'; + listValueField = 'value'; + placeholder = 'n'; + customPlaceholder: string | {state: string} = {state: 'stepperPlaceholder'}; + options = (state: State) => + state.get('stepperCount') as []; + static identifier = 'StepperInput'; + + getIdentifier(): string { + return StepperInput.identifier; + } +} diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/timeinterval.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/timeinterval.input.ts new file mode 100644 index 0000000..b25aa25 --- /dev/null +++ b/projects/workflows-creator/src/lib/services/statement/inputs/timeinterval.input.ts @@ -0,0 +1,30 @@ +import {State, WorkflowPrompt} from '../../../classes'; +import {InputTypes, IntervalType} from '../../../enum'; +import {BpmnNode, RecordOfAnyType} from '../../../types'; +export class TimeIntervalInput extends WorkflowPrompt { + prefix: string | {state: string} = {state: 'timeIntervalSuffix'}; + suffix = ''; + typeFunction = () => InputTypes.IntervalTime; + inputKey = 'TimeInterval'; + listNameField = 'text'; + listValueField = 'value'; + placeholder = 'hh:mm'; + customPlaceholder: string | {state: string} = {state: 'timeStatePlaceholder'}; + isHidden = (node: BpmnNode) => { + return ![ + IntervalType.Weeks, + IntervalType.Months, + IntervalType.Week, + IntervalType.Month, + IntervalType.Days, + IntervalType.Day, + ].includes(node.state.get('intervalType')); + }; + options = (state: State) => + state.get('timevalues'); + static identifier = 'TimeIntervalInput'; + + getIdentifier(): string { + return TimeIntervalInput.identifier; + } +} diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/tointerval.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/tointerval.input.ts new file mode 100644 index 0000000..fcf6c88 --- /dev/null +++ b/projects/workflows-creator/src/lib/services/statement/inputs/tointerval.input.ts @@ -0,0 +1,30 @@ +import {State, WorkflowPrompt} from '../../../classes'; +import {InputTypes, IntervalType} from '../../../enum'; +import {BpmnNode, RecordOfAnyType} from '../../../types'; + +export class ToIntervalInput extends WorkflowPrompt { + prefix = ''; + suffix = ''; + typeFunction = (state: State) => + state.get('valueInputTypes') as InputTypes; + inputKey = 'toInterval'; + listNameField = 'text'; + listValueField = 'value'; + placeholder = 'weekday'; + customPlaceholder: string | {state: string} = {state: 'dateStatePlaceholder'}; + isHidden = (node: BpmnNode) => { + return ![ + IntervalType.Weeks, + IntervalType.Months, + IntervalType.Week, + IntervalType.Month, + ].includes(node.state.get('intervalType')); + }; + options = (state: State) => + state.get('intervalOption'); + static identifier = 'ToIntervalInput'; + + getIdentifier(): string { + return ToIntervalInput.identifier; + } +} diff --git a/projects/workflows-creator/src/lib/workflow-builder.module.ts b/projects/workflows-creator/src/lib/workflow-builder.module.ts index fe0b382..f730147 100644 --- a/projects/workflows-creator/src/lib/workflow-builder.module.ts +++ b/projects/workflows-creator/src/lib/workflow-builder.module.ts @@ -89,7 +89,12 @@ import {TriggerColumnInput} from './services/statement/inputs/triggercolumn.inpu import {ValueTypeInput} from './services/statement/inputs/valuetype.input'; import {TooltipRenderComponent} from './builder/tooltip-render/tooltip-render.component'; import {LocalizationPipe} from './pipes/localization.pipe'; -import { CriteriaInput } from './services'; +import { + CriteriaInput, + StepperInput, + TimeIntervalInput, + ToIntervalInput, +} from './services'; @NgModule({ declarations: [ BuilderComponent, @@ -145,7 +150,10 @@ import { CriteriaInput } from './services'; {provide: BPMN_ELEMENTS, useClass: ProcessPropertiesElement, multi: true}, {provide: BPMN_INPUTS, useClass: ColumnInput, multi: true}, {provide: BPMN_INPUTS, useClass: CriteriaInput, multi: true}, + {provide: BPMN_INPUTS, useClass: StepperInput, multi: true}, + {provide: BPMN_INPUTS, useClass: TimeIntervalInput, multi: true}, {provide: BPMN_INPUTS, useClass: TriggerColumnInput, multi: true}, + {provide: BPMN_INPUTS, useClass: ToIntervalInput, multi: true}, {provide: BPMN_INPUTS, useClass: IntervalInput, multi: true}, {provide: BPMN_INPUTS, useClass: ConditionInput, multi: true}, {provide: BPMN_INPUTS, useClass: EmailDataInput, multi: true}, From d0a1cdb7463fbf24b0dafc1564df842f13d4c837 Mon Sep 17 00:00:00 2001 From: VipulSha99 <107537420+VipulSha99@users.noreply.github.com> Date: Mon, 24 Mar 2025 17:39:37 +0530 Subject: [PATCH 15/19] feat(core): allow email to get edited without removing sequence selection (#90) --- .../workflows-creator/src/lib/builder/group/group.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index a091558..fe28b9f 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -557,6 +557,9 @@ export class GroupComponent implements OnInit, AfterViewInit { element: NodeWithInput, input: WorkflowPrompt, ) { + if (input.inputKey === 'email') { + return; + } const currentIndex = element.inputs.findIndex( i => i.getIdentifier() === input.getIdentifier(), ); From 802051986761ef968b74ec19a66f4dfa93c8e153 Mon Sep 17 00:00:00 2001 From: Akanksha13-dev <84703175+Akanksha13-dev@users.noreply.github.com> Date: Thu, 13 Nov 2025 13:19:18 +0530 Subject: [PATCH 16/19] feat(core): to handle multi line action inputs (#91) Co-authored-by: Akanksha Singh --- .../src/lib/builder/builder.component.ts | 1 + .../lib/builder/group/group.component.html | 127 ++++++++++++------ .../lib/builder/group/group.component.scss | 5 +- .../src/lib/builder/group/group.component.ts | 60 ++++----- .../tooltip-render.component.ts | 8 +- .../services/statement/inputs/column.input.ts | 2 +- .../statement/inputs/criteria.input.ts | 2 +- .../services/statement/inputs/email.input.ts | 2 +- .../statement/inputs/interval.input.ts | 2 +- .../services/statement/inputs/value.input.ts | 2 +- .../statement/inputs/valuetype.input.ts | 2 +- 11 files changed, 127 insertions(+), 86 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index d779b16..3d26060 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -186,6 +186,7 @@ export class BuilderComponent implements OnInit, OnChanges { action: action.node as WorkflowAction, }); }); + this.hideElseBlockIfRequired(); this.updateDiagram(); } } diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.html b/projects/workflows-creator/src/lib/builder/group/group.component.html index 3c24b04..9bf27ec 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.html +++ b/projects/workflows-creator/src/lib/builder/group/group.component.html @@ -50,11 +50,15 @@ - +
- +
- {{ - (input.prefix.state - ? nodeWithInput.node.state.get(input.prefix.state) - : input.prefix) || '' - }} -
- {{ input.getValueName(nodeWithInput.node.state) }} - - {{ - nodeWithInput.node.state.get(input.customPlaceholder?.state) ?? - input.placeholder - }} - -
- {{ - (input.suffix?.state - ? nodeWithInput.node.state.get(input.suffix?.state) - : input.suffix) || '' - }} + +
+ +
+
+ + + + + + {{ + (input.prefix?.state + ? nodeWithInput.node.state.get(input.prefix.state) + : input.prefix) || '' + }} +
+ + {{ input.getValueName(nodeWithInput.node.state) }} + + + {{ + nodeWithInput.node.state.get(input.customPlaceholder?.state) ?? + input.placeholder + }} + +
+ {{ + (input.suffix?.state + ? nodeWithInput.node.state.get(input.suffix?.state) + : input.suffix) || '' + }} + + implements OnInit, AfterViewInit { ngOnInit(): void { this.events = this.nodes.getEvents(); this.triggerEvents = this.nodes.getEvents(true); - this.actions = this.nodes.getActions(); + this.actions = this.nodes + .getActions() + .sort((a, b) => + a.name + .toString() + .localeCompare(b.name.toString(), undefined, {sensitivity: 'base'}), + ); + this.typeSubjectPlaceholder = this.localizationSvc.getLocalizedString( LocalizedStringKeys.TypeSubject, ); @@ -190,36 +197,29 @@ export class GroupComponent implements OnInit, AfterViewInit { * use the default template */ ngAfterViewInit() { + // Create a base template map with defaults + const baseTemplateMap = { + [InputTypes.Boolean]: this.listTemplate, + [InputTypes.List]: this.listTemplate, + [InputTypes.Text]: this.textTemplate, + [InputTypes.Number]: this.numberTemplate, + [InputTypes.Percentage]: this.numberTemplate, + [InputTypes.Date]: this.dateTemplate, + [InputTypes.DateTime]: this.dateTimeTemplate, + [InputTypes.People]: this.searchableDropdownTemplate, + [InputTypes.Interval]: this.listTemplate, + [InputTypes.Email]: this.emailTemplate, + [InputTypes.OptionList]: this.listTemplate, + [InputTypes.Stepper]: this.listTemplate, + [InputTypes.IntervalDate]: this.listTemplate, + [InputTypes.IntervalTime]: this.listTemplate, + }; + + // Merge consumer's custom templates with base templates + // Consumer templates take priority, base templates are fallbacks this.templateMap = { - [InputTypes.Boolean]: - this.templateMap?.[InputTypes.Boolean] || this.listTemplate, - [InputTypes.List]: - this.templateMap?.[InputTypes.List] || this.listTemplate, - [InputTypes.Text]: - this.templateMap?.[InputTypes.Text] || this.textTemplate, - [InputTypes.Number]: - this.templateMap?.[InputTypes.Number] || this.numberTemplate, - [InputTypes.Percentage]: - this.templateMap?.[InputTypes.Percentage] || this.numberTemplate, - [InputTypes.Date]: - this.templateMap?.[InputTypes.Date] || this.dateTemplate, - [InputTypes.DateTime]: - this.templateMap?.[InputTypes.DateTime] || this.dateTimeTemplate, - [InputTypes.People]: - this.templateMap?.[InputTypes.People] || - this.searchableDropdownTemplate, - [InputTypes.Interval]: - this.templateMap?.[InputTypes.Interval] || this.listTemplate, - [InputTypes.Email]: - this.templateMap?.[InputTypes.Email] || this.emailTemplate, - [InputTypes.OptionList]: - this.templateMap?.[InputTypes.OptionList] || this.listTemplate, - [InputTypes.Stepper]: - this.templateMap?.[InputTypes.Stepper] || this.listTemplate, - [InputTypes.IntervalDate]: - this.templateMap?.[InputTypes.IntervalDate] || this.listTemplate, - [InputTypes.IntervalTime]: - this.templateMap?.[InputTypes.IntervalTime] || this.listTemplate, + ...baseTemplateMap, + ...this.templateMap, // Consumer's custom templates override defaults }; } diff --git a/projects/workflows-creator/src/lib/builder/tooltip-render/tooltip-render.component.ts b/projects/workflows-creator/src/lib/builder/tooltip-render/tooltip-render.component.ts index 0f74090..1d90794 100644 --- a/projects/workflows-creator/src/lib/builder/tooltip-render/tooltip-render.component.ts +++ b/projects/workflows-creator/src/lib/builder/tooltip-render/tooltip-render.component.ts @@ -1,17 +1,13 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {Component, Input} from '@angular/core'; @Component({ selector: 'workflow-tooltip-render', templateUrl: './tooltip-render.component.html', styleUrls: ['./tooltip-render.component.scss'], }) -export class TooltipRenderComponent implements OnInit { +export class TooltipRenderComponent { @Input() showsTooltip = true; @Input() tooltipText = 'Default tooltip text'; @Input() topPosition = 215; @Input() leftPosition = 400; - - constructor() {} - - ngOnInit(): void {} } diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/column.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/column.input.ts index 0d942ef..7495fef 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/column.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/column.input.ts @@ -9,7 +9,7 @@ export class ColumnInput extends WorkflowPrompt { inputKey = 'column'; listNameField = 'text'; listValueField = 'value'; - placeholder = 'Column'; + placeholder = 'column'; options = (state: State) => state.get('columns'); static identifier = 'ColumnInput'; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts index 8817e01..754a0f1 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/criteria.input.ts @@ -9,7 +9,7 @@ export class CriteriaInput extends WorkflowPrompt { inputKey = 'column'; listNameField = 'text'; listValueField = 'value'; - placeholder = 'Criteria'; + placeholder = 'criteria'; options = (state: State) => state.get('columns'); static identifier = 'CriteriaInput'; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/email.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/email.input.ts index 141ec59..019a7e6 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/email.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/email.input.ts @@ -9,7 +9,7 @@ export class EmailDataInput extends WorkflowPrompt { suffix = ''; typeFunction = () => InputTypes.Email; inputKey = 'email'; - placeholder = 'Email'; + placeholder = 'email'; static identifier = 'EmailDataInput'; getIdentifier(): string { diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts index e51f618..2bcf237 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/interval.input.ts @@ -9,7 +9,7 @@ export class IntervalInput extends WorkflowPrompt { inputKey = 'interval'; listNameField = 'text'; listValueField = 'value'; - placeholder = 'Interval'; + placeholder = 'interval'; options = (state: State) => state.get('intervalList'); static identifier = 'IntervalInput'; diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts index b1cb912..481b0bd 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/value.input.ts @@ -14,7 +14,7 @@ export class ValueInput extends WorkflowListPrompt { inputKey = 'value'; listNameField = 'text'; listValueField = 'value'; - placeholder = 'Something'; + placeholder = 'something'; customPlaceholder: string | {state: string} = {state: 'valuePlaceholder'}; isHidden = (node: BpmnNode) => { diff --git a/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts b/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts index ac19a9b..43c785b 100644 --- a/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts +++ b/projects/workflows-creator/src/lib/services/statement/inputs/valuetype.input.ts @@ -9,7 +9,7 @@ export class ValueTypeInput extends WorkflowListPrompt { inputKey = 'valueType'; listNameField = 'text'; listValueField = 'value'; - placeholder = 'Something'; + placeholder = 'something'; options = (state: State) => state.get('valueTypes') as []; From 5f723933fbde313170e5450e18ab0e94136d4bd4 Mon Sep 17 00:00:00 2001 From: Akanksha13-dev <84703175+Akanksha13-dev@users.noreply.github.com> Date: Mon, 24 Nov 2025 09:20:41 +0530 Subject: [PATCH 17/19] feat(core): filter action based on selected event (#94) Co-authored-by: Akanksha Singh --- .../src/lib/builder/builder.component.html | 1 + .../src/lib/builder/builder.component.ts | 55 +++++++++++++++++++ .../src/lib/builder/group/group.component.ts | 48 ++++++++++++---- .../services/abstract-node-service.class.ts | 2 +- .../src/lib/services/bpmn/node.service.ts | 38 +++++++++---- 5 files changed, 121 insertions(+), 23 deletions(-) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.html b/projects/workflows-creator/src/lib/builder/builder.component.html index c580a97..7a01dda 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.html +++ b/projects/workflows-creator/src/lib/builder/builder.component.html @@ -25,6 +25,7 @@ [isLast]="true" [isFirst]="true" [nodeType]="types.GROUP" + [eventGroups]="eventGroups" [popupTemplate]="nodePopup" [templateMap]="templateMap" [allColumns]="allColumns" diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index 3d26060..4ddf0c3 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -113,6 +113,20 @@ export class BuilderComponent implements OnInit, OnChanges { nodeList: AbstractBaseGroup[] = []; 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 @@ -225,6 +239,9 @@ export class BuilderComponent implements OnInit, OnChanges { * @param event - ElementsWithInput */ onEventAdded(event: ElementsWithInput) { + // 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, @@ -237,6 +254,44 @@ export class BuilderComponent 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. diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.ts b/projects/workflows-creator/src/lib/builder/group/group.component.ts index 5e375af..51bf406 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.ts +++ b/projects/workflows-creator/src/lib/builder/group/group.component.ts @@ -176,13 +176,7 @@ export class GroupComponent 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, @@ -323,15 +317,44 @@ export class GroupComponent 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; } /** @@ -362,6 +385,7 @@ export class GroupComponent 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); this.eventAdded.emit({ node: node, diff --git a/projects/workflows-creator/src/lib/classes/services/abstract-node-service.class.ts b/projects/workflows-creator/src/lib/classes/services/abstract-node-service.class.ts index 0ae7224..c7f2805 100644 --- a/projects/workflows-creator/src/lib/classes/services/abstract-node-service.class.ts +++ b/projects/workflows-creator/src/lib/classes/services/abstract-node-service.class.ts @@ -4,7 +4,7 @@ import {WorkflowNode} from '../../types/base.types'; import {AbstractBaseGroup} from '../nodes'; export abstract class NodeService { - abstract getActions(): WorkflowNode[]; + abstract getActions(selectedEvent?: string): WorkflowNode[]; abstract getEvents(trigger?: boolean): WorkflowNode[]; abstract getGroups( trigger?: boolean, diff --git a/projects/workflows-creator/src/lib/services/bpmn/node.service.ts b/projects/workflows-creator/src/lib/services/bpmn/node.service.ts index 386f973..07f0ab7 100644 --- a/projects/workflows-creator/src/lib/services/bpmn/node.service.ts +++ b/projects/workflows-creator/src/lib/services/bpmn/node.service.ts @@ -34,18 +34,36 @@ export class BpmnNodesService extends NodeService { * > 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 & {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); + }); } /** From 14edf50ba273eb3795e47afa8485dd92979e8691 Mon Sep 17 00:00:00 2001 From: Akanksha13-dev <84703175+Akanksha13-dev@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:39:55 +0530 Subject: [PATCH 18/19] feat(core): emit updated actions groups to parent (#95) Co-authored-by: Akanksha Singh --- .../workflows-creator/src/lib/builder/builder.component.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/workflows-creator/src/lib/builder/builder.component.ts b/projects/workflows-creator/src/lib/builder/builder.component.ts index 4ddf0c3..bbe56bd 100644 --- a/projects/workflows-creator/src/lib/builder/builder.component.ts +++ b/projects/workflows-creator/src/lib/builder/builder.component.ts @@ -91,6 +91,9 @@ export class BuilderComponent implements OnInit, OnChanges { @Output() stateChange = new EventEmitter>(); + @Output() + actionGroupsAdded = new EventEmitter[]>(); + @Output() diagramChange = new EventEmitter(); @@ -200,6 +203,7 @@ export class BuilderComponent implements OnInit, OnChanges { action: action.node as WorkflowAction, }); }); + this.actionGroupsAdded.emit(this.actionGroups); this.hideElseBlockIfRequired(); this.updateDiagram(); } From 52965c8b78e0cdd8b1ffcd3899d6470cd1305721 Mon Sep 17 00:00:00 2001 From: Akanksha13-dev <84703175+Akanksha13-dev@users.noreply.github.com> Date: Tue, 23 Dec 2025 09:38:10 +0530 Subject: [PATCH 19/19] fix(styles): on hover over delete for multi steps input add line through (#96) Co-authored-by: Akanksha Singh --- .../workflows-creator/src/lib/builder/group/group.component.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/projects/workflows-creator/src/lib/builder/group/group.component.scss b/projects/workflows-creator/src/lib/builder/group/group.component.scss index aeb2674..70f4871 100644 --- a/projects/workflows-creator/src/lib/builder/group/group.component.scss +++ b/projects/workflows-creator/src/lib/builder/group/group.component.scss @@ -61,6 +61,7 @@ .input-next-line { display: block; height: 5px; + text-decoration: inherit; } .input-text {