Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement JS Function / Scripting Component #1100

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
69 changes: 31 additions & 38 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export const PALETTE_GROUPS = [
label: 'Containers',
id: 'container'
},
{
label: 'Advanced',
id: 'advanced'
},
{
label: 'Action',
id: 'action'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function Condition(props) {
let description = 'Condition under which the field is hidden';

// special case for expression fields which do not render
if (field.type === 'expression') {
if ([ 'expression', 'script' ].includes(field.type)) {
label = 'Deactivate if';
description = 'Condition under which the field is deactivated';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { simpleBoolEntryFactory } from './factories';

export function DoNotSubmitEntry(props) {
const {
field,
getService
} = props;

const formFields = getService('formFields');

const fieldDescriptors = {
script: "function's",
expression: "expression's",
};

const entries = [
simpleBoolEntryFactory({
id: 'doNotSubmit',
label: `Do not submit the ${fieldDescriptors[field.type] || "field's"} result with the form submission`,
tooltip: 'Prevents the data associated with this form element from being submitted by the form. Use for intermediate calculations.',
path: [ 'doNotSubmit' ],
props,
isDefaultVisible: (field) => {
const { config } = formFields.get(field.type);
return config.keyed && config.allowDoNotSubmit;
}
})
];

return entries;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { FeelEntry, isFeelEntryEdited, TextAreaEntry, isTextAreaEntryEdited, SelectEntry, isSelectEntryEdited } from '@bpmn-io/properties-panel';
import { get } from 'min-dash';
import { simpleRangeIntegerEntryFactory } from './factories';

import { useService, useVariables } from '../hooks';

export function JSFunctionEntry(props) {
const {
editField,
field
} = props;

const entries = [
{
id: 'variable-mappings',
component: FunctionParameters,
editField: editField,
field: field,
isEdited: isFeelEntryEdited,
isDefaultVisible: (field) => field.type === 'script'
},
{
id: 'function',
component: FunctionDefinition,
editField: editField,
field: field,
isEdited: isTextAreaEntryEdited,
isDefaultVisible: (field) => field.type === 'script'
},
{
id: 'computeOn',
component: JSFunctionComputeOn,
isEdited: isSelectEntryEdited,
editField,
field,
isDefaultVisible: (field) => field.type === 'script'
},
simpleRangeIntegerEntryFactory({
id: 'interval',
label: 'Time interval (ms)',
path: [ 'interval' ],
min: 100,
max: 60000,
props,
isDefaultVisible: (field) => field.type === 'script' && field.computeOn === 'interval'
})
];

return entries;
}

function FunctionParameters(props) {
const {
editField,
field,
id
} = props;

const debounce = useService('debounce');

const variables = useVariables().map(name => ({ name }));

const path = [ 'functionParameters' ];

const getValue = () => {
return get(field, path, '');
};

const setValue = (value) => {
return editField(field, path, value || '');
};

const tooltip = <div>
Functions parameters should be described as an object, e.g.:
<pre><code>{`{
name: user.name,
age: user.age
}`}</code></pre>
</div>;

return FeelEntry({
debounce,
feel: 'required',
element: field,
getValue,
id,
label: 'Function parameters',
tooltip,
description: 'Define the parameters to pass to the javascript function.',
setValue,
variables
});
}

function FunctionDefinition(props) {
const {
editField,
field,
id
} = props;

const debounce = useService('debounce');

const path = [ 'jsFunction' ];

const getValue = () => {
return get(field, path, '');
};

const setValue = (value, error) => {
if (error) {
return;
}

return editField(field, path, value || '');
};

const validate = (value) => {

try {
new Function(value);
} catch (e) {
return `Invalid syntax: ${e.message}`;
}

return null;
};

return TextAreaEntry({
debounce,
element: field,
getValue,
validate,
description: 'Define the javascript function to execute.\nAccess the `data` object and use `setValue` to update the form state.',
id,
label: 'Javascript code',
setValue
});
}

function JSFunctionComputeOn(props) {
const { editField, field, id } = props;

const getValue = () => field.computeOn || '';

const setValue = (value) => {
editField(field, [ 'computeOn' ], value);
};

const getOptions = () => ([
{ value: 'load', label: 'Form load' },
{ value: 'change', label: 'Value change' },
{ value: 'interval', label: 'Time interval' }
]);

return SelectEntry({
id,
label: 'Compute on',
description: 'Define when to execute the function',
getValue,
setValue,
getOptions
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,28 @@ import { useService } from '../hooks';
import { TextFieldEntry, isTextFieldEntryEdited } from '@bpmn-io/properties-panel';
import { useCallback } from 'preact/hooks';


export function KeyEntry(props) {
const {
editField,
field,
getService
} = props;

const entries = [];

entries.push({
id: 'key',
component: Key,
editField: editField,
field: field,
isEdited: isTextFieldEntryEdited,
isDefaultVisible: (field) => {
const formFields = getService('formFields');
const { config } = formFields.get(field.type);
return config.keyed;
const formFields = getService('formFields');

const entries = [
{
id: 'key',
component: Key,
editField: editField,
field: field,
isEdited: isTextFieldEntryEdited,
isDefaultVisible: (field) => {
const { config } = formFields.get(field.type);
return config.keyed;
}
}
});
];

return entries;
}
Expand Down
Loading
Loading