Skip to content

Commit 74db55f

Browse files
danfunkburnettkcoderabbitai[bot]
authored
Deleting messages and changing message properties was not possible if correlation key reused between messages (#125)
* avoid error when message ref doesn't exist on correlation property (rare, but ran into it). When deleting an object with a message, be aware that you might be deeply nested in other things. * MatchingConditionArray, TaskEventMessageProvider.js - fixing the ids of div elements to make them easier to find in tests. MessageHelpers - And added a deleteMessage function that will remove a message AND it's correlation properties. (The reason I came here) MessageHelpers, MessageInterceptor.js - fixing the misspelled name of syncCorrelationProperties. MessageCorrSpec tests that when you update a message through a message editor, it will correctly update the correlation properties, and not leave invalid properties lying around. MessageSelect - will now remove the old message definition (including correlation properties), and replace it with the new message definition when a message is returned from the message editor. As we do this when we receive a new message,there is no need for the cleanupOldMessage function when selecting a different message. MessageSpec - a hell of a time with this. "spiffExtensionOptions" is a constant that I could not seem to clear out between differest spec file tests. I finally resorted to creating a "clearMessages" function that would force the list of messages to get cleared out when needed. Co-authored-by: burnettk Co-authored-by: jasquat * forgot a test file in last commit. * fixing a minor error. * Update test/spec/MessagesSpec.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update test/spec/MessagesSpec.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Kevin Burnett <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent e8b5073 commit 74db55f

File tree

9 files changed

+244
-60
lines changed

9 files changed

+244
-60
lines changed

app/app.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,16 @@ bpmnModeler.on('import.parse.complete', (event) => {
303303

304304
bpmnModeler.importXML(diagramXML).then(() => {});
305305

306+
// Use this to simulate an add/update from the message editor.
307+
// bpmnModeler.on('spiff.message.edit', (event) => {
308+
// event.eventBus.fire('spiff.add_message.returned', {
309+
// elementId: "ActivityA",
310+
// name: "messageA",
311+
// correlation_properties:
312+
// { "new_name": { retrieval_expression: "new_exp" }}
313+
// });
314+
// });
315+
306316
// This handles the download and upload buttons - it isn't specific to
307317
// the BPMN modeler or these extensions, just a quick way to allow you to
308318
// create and save files, so keeping it outside the example.

app/spiffworkflow/messages/MessageHelpers.js

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ export function findCorrelationPropertiesByMessage(element) {
182182

183183
const { businessObject } = element;
184184
const root = getRoot(businessObject);
185-
const correlationProperties = [];
186185

187186
if (isMessageEvent(element)) {
188187
if (
@@ -197,27 +196,29 @@ export function findCorrelationPropertiesByMessage(element) {
197196
if (!businessObject.messageRef) return;
198197
messageId = businessObject.messageRef.id;
199198
}
199+
return findCorrelationPropertiesByMessageId(messageId, root)
200+
}
200201

201-
if (isIterable(root.rootElements)) {
202-
for (const rootElement of root.rootElements) {
203-
if (rootElement.$type === 'bpmn:CorrelationProperty') {
204-
rootElement.correlationPropertyRetrievalExpression =
205-
rootElement.correlationPropertyRetrievalExpression
206-
? rootElement.correlationPropertyRetrievalExpression
207-
: [];
208-
const existingExpressionIndex =
209-
rootElement.correlationPropertyRetrievalExpression.findIndex(
210-
(retrievalExpr) =>
211-
retrievalExpr.messageRef &&
212-
retrievalExpr.messageRef.id === messageId,
213-
);
214-
existingExpressionIndex !== -1
215-
? correlationProperties.push(rootElement)
216-
: null;
217-
}
202+
export function findCorrelationPropertiesByMessageId(messageId, root) {
203+
const correlationProperties = [];
204+
205+
for (const rootElement of root.rootElements) {
206+
if (rootElement.$type === 'bpmn:CorrelationProperty') {
207+
rootElement.correlationPropertyRetrievalExpression =
208+
rootElement.correlationPropertyRetrievalExpression
209+
? rootElement.correlationPropertyRetrievalExpression
210+
: [];
211+
const existingExpressionIndex =
212+
rootElement.correlationPropertyRetrievalExpression.findIndex(
213+
(retrievalExpr) =>
214+
retrievalExpr.messageRef &&
215+
retrievalExpr.messageRef.id === messageId,
216+
);
217+
existingExpressionIndex !== -1
218+
? correlationProperties.push(rootElement)
219+
: null;
218220
}
219221
}
220-
221222
return correlationProperties;
222223
}
223224

@@ -819,7 +820,7 @@ function findOrCreateMainCorrelationKey(definitions, bpmnFactory, moddle) {
819820
return mainCorrelationKey;
820821
}
821822

822-
export function synCorrleationProperties(
823+
export function syncCorrelationProperties(
823824
element,
824825
definitions,
825826
moddle,
@@ -832,11 +833,9 @@ export function synCorrleationProperties(
832833
for (let cProperty of correlationProps) {
833834
let isUsed = false;
834835
for (const cpExpression of cProperty.correlationPropertyRetrievalExpression) {
835-
const msgRef = findMessageElement(
836-
businessObject,
837-
cpExpression.messageRef.id,
838-
definitions,
839-
);
836+
const msgRef = cpExpression.messageRef
837+
? findMessageElement(businessObject, cpExpression.messageRef.id, definitions)
838+
: undefined;
840839
isUsed =
841840
msgRef &&
842841
msgObject &&
@@ -878,3 +877,31 @@ export function synCorrleationProperties(
878877
}
879878
}
880879
}
880+
881+
export function deleteMessage(definitions, messageId) {
882+
const rootElements = definitions.rootElements;
883+
884+
// Delete correlation retrieval expressions (Which live outside the message)
885+
const corProps = findCorrelationPropertiesByMessage
886+
887+
// Delete the message object
888+
const index = rootElements.findIndex(
889+
(element) =>
890+
element.$type === 'bpmn:Message' && element.id === messageId
891+
);
892+
if (rootElements && index !== -1) {
893+
rootElements.splice(index, 1);
894+
definitions.rootElements = rootElements;
895+
}
896+
897+
// Delete retrieval expressions related to message
898+
const props = findCorrelationPropertiesByMessageId(messageId, definitions)
899+
for (let prop of props) {
900+
let propIndex = prop.correlationPropertyRetrievalExpression.findIndex(
901+
(retrievalExpr) =>
902+
retrievalExpr.messageRef &&
903+
retrievalExpr.messageRef.id === messageId,
904+
);
905+
prop.correlationPropertyRetrievalExpression.splice(propIndex, 1);
906+
}
907+
}

app/spiffworkflow/messages/MessageInterceptor.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
2-
import { isMessageElement, isMessageRefUsed, setParentCorrelationKeys, synCorrleationProperties } from './MessageHelpers';
2+
import { isMessageElement, isMessageRefUsed, setParentCorrelationKeys, syncCorrelationProperties, getRoot} from './MessageHelpers';
33

44
const HIGH_PRIORITY = 90500;
55

@@ -16,8 +16,8 @@ export default class MessageInterceptor extends CommandInterceptor {
1616
if (isMessageElement(shape)) {
1717

1818
let oldMessageRef = (businessObject.eventDefinitions) ? businessObject.eventDefinitions[0].messageRef : businessObject.messageRef;
19-
20-
let definitions = rootElement.businessObject.$parent;
19+
20+
let definitions = getRoot(rootElement, moddle)
2121
if (!definitions.get('rootElements')) {
2222
definitions.set('rootElements', []);
2323
}
@@ -38,7 +38,7 @@ export default class MessageInterceptor extends CommandInterceptor {
3838
}
3939

4040
// Automatic deletion of previous message correlation properties
41-
synCorrleationProperties(shape, definitions, moddle);
41+
syncCorrelationProperties(shape, definitions, moddle);
4242
}
4343

4444
// Update Correlation key if Process has collaboration

app/spiffworkflow/messages/propertiesPanel/elementLevelProvider/MatchingConditionArray.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function MatchingCorrelationEntries(props) {
2626
const entries = (correlationPropertyArray && correlationPropertyArray.length !== 0) ? correlationPropertyArray.map(
2727
(correlationPropertyModdleElement, index) => {
2828
return {
29-
id: `${idPrefix}-correlation-property-name`,
29+
id: `${idPrefix}-correlation-property-`,
3030
component: MatchingConditionTextField,
3131
correlationPropertyModdleElement,
3232
element,

app/spiffworkflow/messages/propertiesPanel/elementLevelProvider/MessageSelect.jsx

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
isMessageEvent,
1111
isMessageRefUsed,
1212
setParentCorrelationKeys,
13-
synCorrleationProperties,
13+
syncCorrelationProperties,
14+
deleteMessage
1415
} from '../../MessageHelpers';
1516
import { SPIFF_ADD_MESSAGE_RETURNED_EVENT } from '../../../constants';
1617

@@ -80,8 +81,7 @@ export function MessageSelect(props) {
8081
}
8182

8283
if (oldMessageRef) {
83-
cleanupOldMessage(definitions, oldMessageRef.id);
84-
synCorrleationProperties(element, definitions, moddle, messageObject);
84+
syncCorrelationProperties(element, definitions, moddle, messageObject);
8585
}
8686

8787
try {
@@ -111,6 +111,16 @@ export function MessageSelect(props) {
111111
correlation_properties: cProperties,
112112
};
113113

114+
// Delete the original message object if one exists, so we can replace it with the new definition.
115+
const { businessObject } = element;
116+
const definitions = getRoot(businessObject);
117+
let oldMessage = findMessageById(definitions, newMsg.identifier);
118+
if(oldMessage) {
119+
deleteMessage(definitions, oldMessage.id);
120+
}
121+
122+
123+
// Update the list of options to display
114124
spiffExtensionOptions['spiff.messages'] =
115125
Array.isArray(spiffExtensionOptions['spiff.messages']) &&
116126
spiffExtensionOptions['spiff.messages']
@@ -243,17 +253,3 @@ function findMessageObject(messageId) {
243253
return null;
244254
}
245255
}
246-
247-
function cleanupOldMessage(definitions, oldMessageId) {
248-
if (!isMessageRefUsed(definitions, oldMessageId)) {
249-
const rootElements = definitions.rootElements;
250-
const oldMessageIndex = rootElements.findIndex(
251-
(element) =>
252-
element.$type === 'bpmn:Message' && element.id === oldMessageId
253-
);
254-
if (rootElements && oldMessageIndex !== -1) {
255-
rootElements.splice(oldMessageIndex, 1);
256-
definitions.rootElements = rootElements;
257-
}
258-
}
259-
}

app/spiffworkflow/messages/propertiesPanel/elementLevelProvider/TaskEventMessageProvider.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,13 @@ export function createMessageGroup(
142142

143143
// Adding Correlation Conditions Section
144144
const isMatchingCorrelation = businessObject.get('spiffworkflow:isMatchingCorrelation');
145+
const id = businessObject.get('messageRef')?.id ?? "undefined";
145146
if (isMatchingCorrelation && isMatchingCorrelation !== "false" && canReceiveMessage(element)) {
146147
results.push({
147148
id: "correlationConditions",
148149
label: translate('Matching Conditions'),
149150
...MatchingCorrelationEntries({
151+
idPrefix: id,
150152
element,
151153
moddle,
152154
commandStack,

test/spec/MessagesCorrSpec.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import TestContainer from 'mocha-test-container-support';
2+
import {
3+
query as domQuery,
4+
queryAll as domQueryAll,
5+
} from 'min-dom';
6+
import {
7+
BpmnPropertiesPanelModule,
8+
BpmnPropertiesProviderModule,
9+
} from 'bpmn-js-properties-panel';
10+
import {
11+
bootstrapPropertiesPanel,
12+
expectSelected,
13+
findEntry,
14+
findGroupEntry,
15+
findSelect,
16+
findTextarea,
17+
findInput,
18+
pressButton,
19+
findButtonByClass,
20+
getPropertiesPanel,
21+
changeInput,
22+
findDivByClass
23+
} from './helpers';
24+
import spiffModdleExtension from '../../app/spiffworkflow/moddle/spiffworkflow.json';
25+
import messages from '../../app/spiffworkflow/messages';
26+
import { fireEvent } from '@testing-library/preact';
27+
import { getBpmnJS, inject } from 'bpmn-js/test/helper';
28+
import { findCorrelationProperties, findMessageModdleElements } from '../../app/spiffworkflow/messages/MessageHelpers';
29+
import {spiffExtensionOptions} from "../../app/spiffworkflow/extensions/propertiesPanel/SpiffExtensionSelect";
30+
31+
describe('Multiple messages should work', function () {
32+
const xml = require('./bpmn/two_messages.bpmn').default;
33+
let container;
34+
35+
beforeEach(function () {
36+
container = TestContainer.get(this);
37+
});
38+
39+
beforeEach(
40+
bootstrapPropertiesPanel(xml, {
41+
container,
42+
debounceInput: false,
43+
additionalModules: [
44+
messages,
45+
BpmnPropertiesPanelModule,
46+
BpmnPropertiesProviderModule,
47+
],
48+
moddleExtensions: {
49+
spiffworkflow: spiffModdleExtension,
50+
},
51+
})
52+
);
53+
54+
55+
const new_message_event = (eventBus) => {
56+
eventBus.fire('spiff.add_message.returned', {
57+
elementId: "ActivityA",
58+
name: "messageA",
59+
correlation_properties:
60+
{ "new_name": { retrieval_expression: "new_exp" }}
61+
});
62+
};
63+
64+
65+
it('and it should be possible to change a correlation property name', async function () {
66+
const modeler = getBpmnJS();
67+
68+
const sendShape = await expectSelected('ActivityA');
69+
expect(sendShape, "Can't find Send Task").to.exist;
70+
71+
const oldName = "old_name"
72+
const newName = "new_name"
73+
74+
const labels = domQueryAll(`.bio-properties-panel-label`, container);
75+
const oldNameFound = Array.from(labels).some(label => label.textContent.includes(oldName));
76+
expect(oldNameFound).to.be.true;
77+
78+
//Update message
79+
new_message_event(modeler.get('eventBus'))
80+
const sendShape2 = await expectSelected('ActivityA');
81+
82+
// The old name should no longer be there, but the new name should exist.
83+
const labels2 = domQueryAll(`.bio-properties-panel-label`, container);
84+
const oldNameFound2 = Array.from(labels2).some(label => label.textContent.includes(oldName));
85+
expect(oldNameFound2).to.be.false;
86+
const newNameFound2 = Array.from(labels2).some(label => label.textContent.includes(newName));
87+
expect(newNameFound2).to.be.true;
88+
89+
90+
});
91+
92+
});

0 commit comments

Comments
 (0)