11import { useState , useCallback , useEffect } from 'react' ;
22
3- import { getInputMapping } from '../utils/inputMapping.js' ;
3+ import { find } from 'lodash' ;
4+
5+ import { getInputMapping } from '../utils/bpmnUtils.js' ;
46
57/**
68 * Get and set input variables for the given element,
79 * based on the input mapping and available process variables.
810 *
911 * @param {* } element - BPMN element
10- * @param {Array } variables - Available process variables
12+ * @param {* } resolvedVariables - Available process variables
1113 */
12- export function useInput ( element , variables ) {
14+ export function useInput ( element , resolvedVariables ) {
1315
1416 const [ input , setInput ] = useState ( { } ) ;
1517 const [ dirty , setDirty ] = useState ( { } ) ;
@@ -19,66 +21,32 @@ export function useInput(element, variables) {
1921 return ;
2022 }
2123
24+ setInitialInput ( ) ;
25+ } , [ element , resolvedVariables ] ) ;
26+
27+ /**
28+ * Create initial input from the BPMN element input mapping.
29+ */
30+ const setInitialInput = useCallback ( ( ) => {
2231 const inputMapping = getInputMapping ( element ) ;
2332
24- if ( ! inputMapping ) {
33+ if ( ! inputMapping || ! resolvedVariables ) {
2534 return ;
2635 }
2736
28- const values = inputMapping . reduce ( ( acc , { target, source } ) => {
29-
30- const feelValue = getFeelValue ( source ) ;
31-
32- if ( ! feelValue ) {
33- return { ...acc , [ target ] : source } ;
34- }
35-
36- if ( isFeelConstant ( feelValue ) ) {
37- return { ...acc , [ target ] : feelValue } ;
38- }
39-
40- const knownVariable = variables ?. find ( variable => variable . name === target ) ;
41-
42- if ( ! knownVariable ) {
43- console . log ( 'no known variable for' , target ) ;
44- return { ...acc , [ feelValue ] : '' } ;
45- }
46-
47- if ( knownVariable . type === 'Context' && knownVariable . entries ) {
48- const sourceEntries = Object . fromEntries ( knownVariable . entries . map ( entry => [ entry . name , '' ] ) ) ;
49- return { ...acc , ...sourceEntries } ;
50- }
51-
52- if ( knownVariable . info ) {
53- return { ...acc , [ target ] : knownVariable . info } ;
54- }
55-
56- return { ...acc , [ feelValue ] : '' } ;
57- } , { } ) ;
58-
59- // Convert flat object with dot notation to nested object
60- const nestedValues = Object . entries ( values ) . reduce ( ( acc , [ key , value ] ) => {
61- const keys = key . split ( '.' ) ;
62- let current = acc ;
63-
64- for ( let i = 0 ; i < keys . length - 1 ; i ++ ) {
65- const keyPart = keys [ i ] ;
66- if ( ! ( keyPart in current ) ) {
67- current [ keyPart ] = { } ;
68- }
69- current = current [ keyPart ] ;
70- }
71-
72- current [ keys [ keys . length - 1 ] ] = value ;
73- return acc ;
74- } , { } ) ;
37+ const values = createFromInputMapping ( inputMapping , resolvedVariables ) ;
7538
7639 setInput ( prev => ( {
7740 ...prev ,
78- [ element . id ] : JSON . stringify ( nestedValues , null , 2 )
41+ [ element . id ] : values
7942 } ) ) ;
80- } , [ element , variables ] ) ;
43+ } , [ element , resolvedVariables ] ) ;
8144
45+ /**
46+ * Set input for the currently selected element.
47+ *
48+ * Mark the input as `dirty` to indicate it has been modified.
49+ */
8250 const handleInput = useCallback ( ( value ) => {
8351 setInput ( prev => ( {
8452 ...prev ,
@@ -92,25 +60,97 @@ export function useInput(element, variables) {
9260
9361 } , [ element ] ) ;
9462
63+ /**
64+ * Set input back to the initial values based on the BPMN element input mapping.
65+ */
66+ const handleReset = useCallback ( ( ) => {
67+
68+ setInitialInput ( ) ;
69+
70+ setDirty ( prev => ( {
71+ ...prev ,
72+ [ element . id ] : false
73+ } ) ) ;
74+ } , [ element , resolvedVariables ] ) ;
75+
9576 return {
9677 input : input [ element ?. id ] ,
9778 setInput : handleInput ,
79+ reset : handleReset
9880 } ;
9981}
10082
101- function getFeelValue ( string ) {
102- return string . startsWith ( '=' ) ? string . slice ( 1 ) : null ;
83+
84+ // helpers
85+
86+ function createFromInputMapping ( inputMapping , resolvedVariables ) {
87+
88+ const values = inputMapping . reduce ( ( acc , { target, source } ) => {
89+
90+ const variable = find ( resolvedVariables , { name : target } ) ;
91+
92+ if ( ! variable ) {
93+ return acc ;
94+ }
95+
96+ const { name, type, info } = variable ;
97+
98+ if ( type === 'Context' ) {
99+
100+ // TODO: We can't resolve Context variables yet
101+ return { ...acc , [ name ] : { } } ;
102+ }
103+
104+ if ( ! type && ! info && source . startsWith ( '=' ) ) {
105+
106+ // TODO: Remove when https://github.com/bpmn-io/variable-resolver/issues/52 is fixed.
107+ if ( source === '=false' ) {
108+ return acc ;
109+ }
110+
111+ return { ...acc , [ source . slice ( 1 ) ] : '' } ;
112+ }
113+
114+ return acc ;
115+ } , { } ) ;
116+
117+ const nestedValues = parseNestedValues ( values ) ;
118+
119+ return JSON . stringify ( nestedValues , null , 2 ) ;
103120}
104121
105- function isFeelConstant ( value ) {
122+ /**
123+ * Convert flat object with dot notation to nested object.
124+ *
125+ * Example:
126+ *
127+ * `{
128+ * 'foo.bar': 'baz'
129+ * }`
130+ * becomes:
131+ * `{
132+ * foo: {
133+ * bar: 'baz'
134+ * }
135+ * }`
136+ */
137+ function parseNestedValues ( values ) {
106138
107- if ( ! isNaN ( parseInt ( value ) ) ) {
108- return true ;
109- }
139+ const nestedValues = Object . entries ( values ) . reduce ( ( acc , [ key , value ] ) => {
140+ const keys = key . split ( '.' ) ;
141+ let current = acc ;
142+
143+ for ( let i = 0 ; i < keys . length - 1 ; i ++ ) {
144+ const keyPart = keys [ i ] ;
145+ if ( ! ( keyPart in current ) ) {
146+ current [ keyPart ] = { } ;
147+ }
148+ current = current [ keyPart ] ;
149+ }
110150
111- if ( value . toLowerCase ( ) === 'true' || value . toLowerCase ( ) === 'false' ) {
112- return true ;
113- }
151+ current [ keys [ keys . length - 1 ] ] = value ;
152+ return acc ;
153+ } , { } ) ;
114154
115- return false ;
155+ return nestedValues ;
116156}
0 commit comments