Skip to content

Commit d697586

Browse files
authored
Merge pull request #1947 from ProcessMaker/feature/FOUR-26707
FOUR-26707 Implement Conditional Destination Redirect
2 parents dcea024 + b297d69 commit d697586

File tree

10 files changed

+882
-34
lines changed

10 files changed

+882
-34
lines changed

package-lock.json

Lines changed: 65 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"socket.io-client": "^4.7.2",
6666
"svg-inline-loader": "^0.8.2",
6767
"tinycolor2": "^1.4.2",
68+
"uuid": "^13.0.0",
6869
"vue": "^2.6.12",
6970
"vue-deepset": "^0.6.3",
7071
"vue-inline-svg": "^2.1.3",
@@ -81,7 +82,7 @@
8182
"@cypress/code-coverage": "^3.12.10",
8283
"@faker-js/faker": "^8.1.0",
8384
"@panter/vue-i18next": "^0.15.2",
84-
"@processmaker/processmaker-bpmn-moddle": "0.16.0",
85+
"@processmaker/processmaker-bpmn-moddle": "0.16.1",
8586
"@types/jest": "^24.9.1",
8687
"@vue/babel-preset-app": "^5.0.4",
8788
"@vue/cli-plugin-babel": "~5.0.0",
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<template>
2+
<div>
3+
<label>{{ $t(label) }}</label>
4+
<div class="d-flex justify-content-between align-items-center mb-2">
5+
<span
6+
class="text-muted small"
7+
v-html="conditionalRedirectDescription"
8+
/>
9+
<b-form-checkbox
10+
id="conditionalRedirectEnabled"
11+
v-model="isEnabled"
12+
name="conditionalRedirectEnabled"
13+
:aria-checked="isEnabled"
14+
switch
15+
data-test="conditional-toggle"
16+
/>
17+
</div>
18+
<div v-if="isEnabled">
19+
<button
20+
type="button"
21+
class="btn btn-light"
22+
@click="addCondition"
23+
:disabled="maxConditionsReached"
24+
data-test="conditional-add-button"
25+
>
26+
<i class="fas fa-plus-circle" />
27+
</button>
28+
29+
<div
30+
v-for="condition in conditions"
31+
:key="condition.id"
32+
data-test="conditional-box"
33+
>
34+
<TaskDestination
35+
:value="condition"
36+
:taskDestinationOptions="taskDestinationOptions"
37+
:conditionId="condition.id"
38+
:maxConditionsReached="maxConditionsReached"
39+
@input="onSaveCondition"
40+
@duplicate="onDuplicateCondition"
41+
@remove="onRemoveCondition"
42+
/>
43+
</div>
44+
45+
<hr class="my-2">
46+
47+
<div class="d-flex justify-content-end">
48+
<small class="text-muted text-right">
49+
{{ $t('Rules are evaluated top to bottom.') }}
50+
</small>
51+
</div>
52+
</div>
53+
</div>
54+
</template>
55+
56+
<script>
57+
import TaskDestination from './TaskDestination.vue';
58+
import { v4 as uuidv4 } from 'uuid';
59+
60+
const MAX_CONDITIONS = 10;
61+
62+
export default {
63+
components: {
64+
TaskDestination,
65+
},
66+
props: {
67+
value: {
68+
type: String,
69+
},
70+
label: {
71+
type: String,
72+
required: true,
73+
},
74+
options: {
75+
type: Array,
76+
required: true,
77+
},
78+
},
79+
data() {
80+
return {
81+
taskDestination: null,
82+
isEnabled: false,
83+
conditions: [],
84+
taskDestinationOptions: [],
85+
MAX_CONDITIONS,
86+
};
87+
},
88+
computed: {
89+
conditionalRedirectDescription() {
90+
return this.$t('Enable to add rules that route users to different tasks. If none match, the <b>Task Destination</b> is used.');
91+
},
92+
maxConditionsReached() {
93+
return this.conditions.length >= MAX_CONDITIONS;
94+
},
95+
},
96+
watch: {
97+
isEnabled: {
98+
handler() {
99+
this.updateConditionalRedirect();
100+
},
101+
},
102+
},
103+
mounted() {
104+
this.initTaskDestinationOptions();
105+
106+
if (this.value) {
107+
try {
108+
const local = JSON.parse(this.value);
109+
110+
this.isEnabled = local.isEnabled ?? false;
111+
this.conditions = local.conditions ?? [];
112+
} catch (error) {
113+
console.warn(error, 'Error parsing conditional redirect', this.value);
114+
}
115+
}
116+
},
117+
methods: {
118+
initTaskDestinationOptions() {
119+
this.taskDestinationOptions = this.options.map(({ value, content }) => ({
120+
value,
121+
content: this.$t(content),
122+
}));
123+
124+
this.taskDestination = this.taskDestinationOptions?.[0] ?? null;
125+
},
126+
updateConditionalRedirect() {
127+
const data = JSON.stringify({
128+
isEnabled: this.isEnabled,
129+
conditions: this.conditions,
130+
});
131+
132+
this.$emit('input', data);
133+
},
134+
addCondition() {
135+
if (this.maxConditionsReached) {
136+
return;
137+
}
138+
139+
this.conditions.push({
140+
id: uuidv4(),
141+
condition: '',
142+
taskDestination: null,
143+
});
144+
145+
this.updateConditionalRedirect();
146+
},
147+
onSaveCondition(value) {
148+
const index = this.conditions.findIndex((condition) => condition.id === value.conditionId);
149+
150+
if (index !== -1) {
151+
this.conditions[index] = {
152+
...this.conditions[index],
153+
...value.condition,
154+
};
155+
}
156+
157+
this.updateConditionalRedirect();
158+
},
159+
onDuplicateCondition(conditionId) {
160+
if (this.maxConditionsReached) {
161+
return;
162+
}
163+
164+
const condition = this.conditions.find((condition) => condition.id === conditionId);
165+
166+
this.conditions.push({
167+
...condition,
168+
id: uuidv4(),
169+
});
170+
171+
this.updateConditionalRedirect();
172+
},
173+
onRemoveCondition(conditionId) {
174+
this.conditions = this.conditions.filter((condition) => condition.id !== conditionId);
175+
176+
this.updateConditionalRedirect();
177+
},
178+
},
179+
};
180+
</script>

0 commit comments

Comments
 (0)