Closed MaxTru closed 2 years ago
Comment from @marstamm in Modeler Weekly:
array
/ list
data type. Hence the dynamic creation of multiple values in a multi-element component might be difficult to implement for camunda-platform.Comment from @nikku in Modeler Weekly in response:
The Platform also supports a json
variable type. The JSON is delivered Stringified from the API and has to be parsed in the frontend. See this example of a variable result from the backend:
We can use the "Json" type to create lists and use them in the form. Keep in mind that:
Sync of next working steps (@Skaiir @pinussilvestrus)
Just had a chat with @vsgoulart who is our link to C8 tasklist and had some pretty valuable takeaways from it.
Following discussion: Implementing this ticket just feels like a no-brainer and everybody's agreed so far, so I've adopted this into the scope of dynamic forms.
Insights from C7 tasklist by @tasso94
A little aside related to the previous point, the fact that we don't output falsy values for most of our single select controls could also be considered a limitation.
Don't we? Can you share an example we can dive into?
Radio buttons for example:
A little aside related to the previous point, the fact that we don't output falsy values for most of our single select controls could also be considered a limitation.
How are these an example?
Like for a radio, what shall be the none value? Null initially? My intuition is that radio has "must be one of them" semantics.
Well, perhaps we're not understanding eachother but the point that was raised is that the selectable values defined statically inside of the form is lost to the process. A radio button is a singleselect. We don't output information about the options which were not selected. This just ties in with the point right before and is something Tassilo brought up. That information is restricted to our form and there's no way to access it from the process down the line.
This obviously depends on use case and it might just be better to do it the way we're currently doing it, I just brought it up as a thought.
Ah, so the the point is that we want to submit all results (by checked and unchecked)?
Example scenario: A multi checkbox with 10 different emails, we select 3 of those, those 3 get an in depth email about some process information, the 7 others only get a quick summary. If those were defined in the form options, the process scope is not aware of it, and hence we'd need to output the falsy selection as well to create the above described behavior.
For this example (which relates to falsy values) I'd argue that
(1) a list of X
emails is a process variable (or otherwise hardcoded engine binding); we'll support mapping such dynamic process variables to selects options
(2) returning only what is selected is safe, as at run-time can diff between what is being returned from the form and what has previously been fetched
Again, I may miss-understand something. In that case it could be best to actually model such scenario, ensure we all understand it, and carefully decide if we want to change existing semantics (start to submit falsy stuff).
Is there a way to do (2) if the data isn't fetched but hardcoded into the form definition?
But yea, if multi-select becomes a dedicated, new component (not the same as a check-box) we can be more creative with submit behaviors.
Is there a way to do (2) if the data isn't fetched but hardcoded into the form?
We could add the ability to submit additional static configuration with the form. That would be one resolution.
Like: Always submit emailUsers = [ { name, value=email } ]
and selectedEmailUsers=[...]
.
It may be worth discussing how far we want to go with static bindings, and also what to consciously not support for improved happiness of the 80%.
Agreed, the point only related to static definitions anyways. I agree completely that if you've got your data source as a process variable there's no argument there we wouldn't need it. Cool, we'll chat about it during the Kickoff.
Hi there
I got a support feature request (https://jira.camunda.com/browse/SUPPORT-12403) where a user is asking about support for:
Given:
{ "schemaVersion": 2, "exporter": { "name": "form-js (https://demo.bpmn.io)", "version": "0.1.0" } , "components": [ { "text": "# File an Invoice\n\nAdd your invoice details below.\n\nCustomer Id: ${customerId}", "type": "text", "id": "Field_1m5gj8s" }, { "action": "submit", "key": "submit", "label": "Submit", "type": "button", "id": "Field_03qrh3a" } ], "type": "default", "id": "Form_1ef51ca" }
Where ${customerId} get's replaced by the process variables
Is this in scope of this ticket here?
No it is not, or at least not planed for.
It is related to https://github.com/bpmn-io/form-js/issues/247 and I've linked the support case there.
Maybe it makes sense to investigate it in the course of our dynamic form endeavours @christian-konrad @Skaiir? I've heart this request just yesterday, and a couple of times in the past, too.
Thank you for the quick reply!
Thanks for sharing, I also added it to the "other topics" section above (not in this epic, but as a follow-up) 👍
@nikku We're going to bring FEEL into forms, and this looks like that would fit such an implementation as well. I think this could be taken on as part of the conditional rendering epic here: https://github.com/camunda/product-hub/issues/56.
Perhaps it's not the perfect epic for this but it's more related than dynamic select data.
Next release will be October the 11th, which gives us a timeline of 5.5 months for these changes to be completed. (Not that this much is needed)
Kickoff 29th April 2022
For more details, refer to this miro board.
Why wouldn't dynamic input data just be created prior to instantiating the form, passing a function into the form as input data would be considerably harder to control for security reasons, making it easy to inject malicious code?
Unless you are suggesting to allow the function to access internal form data, for example to accomplish cascading selects, one select determines the values of the next. We would then have some default params passed to the the functions like formData etc.
inputData = {
countryValues: [{label:"Canada",key:"CA"}, {"label":"Germany","key":"DE"}, ...],
citiesValues: async function(formData){
const {country} = formData;
const cities = await fetch(...);
return cities.filter(c => { return c.country === country}).map(c => {
return { label: c.name, value: c.key }
})
},
...
}
triggering all functions run when formData changes somehow, and also trigger a loading indicator when the promise is waiting to resolve would be advantageous.
This would be cool, but concerns of security issues remain.
EDIT: it would be even better if we could establish a memoization and run the function only when specific formData values changes. for example when formData.country changes:
inputData = {
countryValues: [{label:"Canada",key:"CA"}, {"label":"Germany","key":"DE"}, ...],
citiesValues: [["country"], async function(country){ ... do something with country when it changes and return new values ...}]
}
Example scenario: A multi checkbox with 10 different emails, we select 3 of those, those 3 get an in depth email about some process information, the 7 others only get a quick summary. If those were defined in the form options, the process scope is not aware of it, and hence we'd need to output the falsy selection as well to create the above described behavior.
For this example (which relates to falsy values) I'd argue that
(1) a list of
X
emails is a process variable (or otherwise hardcoded engine binding); we'll support mapping such dynamic process variables to selects options (2) returning only what is selected is safe, as at run-time can diff between what is being returned from the form and what has previously been fetchedAgain, I may miss-understand something. In that case it could be best to actually model such scenario, ensure we all understand it, and carefully decide if we want to change existing semantics (start to submit falsy stuff).
Wouldn't it just be better to handle that in the process, the process would have the initial list of email and now the selected few. by removing the selected emails from the full list process variable and store it in a filtered process variable list in the process and then send summary emails to those, and detailed emails to the selected values. No other form select works by submitting not selected values.
Well, perhaps we're not understanding eachother but the point that was raised is that the selectable values defined statically inside of the form is lost to the process. A radio button is a singleselect. We don't output information about the options which were not selected. This just ties in with the point right before and is something Tassilo brought up. That information is restricted to our form and there's no way to access it from the process down the line.
I think a better way of passing data from input to output would be to create a hidden type form component, this way you could pass any value from the input to the output if required. This would be in line with how a regular web form would pass data that doesn't require user interaction. Bind the select and the hidden to the same input property, the select component would pass the selected values and the hidden component would pass the complete list.
But yea, if multi-select becomes a dedicated, new component (not the same as a check-box) we can be more creative with submit behaviors.
Is there a way to do (2) if the data isn't fetched but hardcoded into the form?
We could add the ability to submit additional static configuration with the form. That would be one resolution.
Like: Always submit
emailUsers = [ { name, value=email } ]
andselectedEmailUsers=[...]
.It may be worth discussing how far we want to go with static bindings, and also what to consciously not support for improved happiness of the 80%.
Could we create an option in the form schema to provide a preSubmit function that could arbitrarily structure the submitted data any way the developer would like prior to form submission? Passing this function the formData, InputData, and perhaps components
I think a better way of passing data from input to output would be to create a hidden type form component (https://github.com/bpmn-io/form-js/issues/200#issuecomment-1123170808)
@dfulgham This is what we settled on (@pinussilvestrus @Skaiir please confirm).
Wouldn't it just be better to handle that in the process, the process would have the initial list of email and now the selected few (https://github.com/bpmn-io/form-js/issues/200#issuecomment-1123167429)
@dfulgham Exactly. We'll not persue this direction (@pinussilvestrus @Skaiir please confirm).
Generally speaking we shall not re-invent the web, but rather build in the spirit of existing web forms (including hidden inputs you mentioned for secret data passing). This is what we do to date, this is what we'll do in the future.
Could we create an option in the form schema to provide a preSubmit function that could arbitrarily structure the submitted data any way the developer would like prior to form submission?
What would be the dedicated use-case? As you mentioned I can absolutely wrap the form and do whatever I want before import, and after submit.
Why wouldn't dynamic input data just be created prior to instantiating the form (https://github.com/bpmn-io/form-js/issues/200#issuecomment-1123160041)
The sole reason for passing a function would be to allow dynamic lookup, i.e. when huge amounts of data exist that cannot be pre-loaded (i.e. list of emails to auto-complete). In this case you can provide a lookup function.
The default use-case for our dynamic form works is indeed that data (and options) are dynamically populated via input variables, however just-in-time lookup is one of the options we see with popular multi-select libraries, i.e. select2.
What would be the dedicated use-case? As you mentioned I can absolutely wrap the form and do whatever I want before import, and after submit. (#200 (comment))
It was for the use case where the developer wanted access to the Component Elements (i.e. statically set value lists) and the Input values at time of submission (i.e. in the case of fetched data).
Just brainstorming ways to accommodate the use case put forward by you @nikku but I think these could also be enabled with the hidden component type, allowing the input data at time of submission to be submitted. And I don't personally think I would use the case of needing any statically set values, if I needed them i'd rather set those values with an input value dynamically.
Why wouldn't dynamic input data just be created prior to instantiating the form
The sole reason for passing a function would be to allow dynamic lookup, i.e. when huge amounts of data exist that cannot be pre-loaded (i.e. list of emails to auto-complete). In this case you can provide a lookup function.
The default use-case for our dynamic form works is indeed that data (and options) are dynamically populated via input variables, however just-in-time lookup is one of the options we see with popular multi-select libraries, i.e. select2.
Yes, i worked my way to this understanding too while providing the example of cascaded selects
But yea, if multi-select becomes a dedicated, new component (not the same as a check-box) we can be more creative with submit behaviors.
Is there a way to do (2) if the data isn't fetched but hardcoded into the form?
We could add the ability to submit additional static configuration with the form. That would be one resolution. Like: Always submit
emailUsers = [ { name, value=email } ]
andselectedEmailUsers=[...]
. It may be worth discussing how far we want to go with static bindings, and also what to consciously not support for improved happiness of the 80%.Could we create an option in the form schema to provide a preSubmit function that could arbitrarily structure the submitted data any way the developer would like prior to form submission? Passing this function the formData, InputData, and perhaps components
That could deserve an extra issue (if not already existing). Feel free to open one and we can discover this particular use case over there 👍
I think a better way of passing data from input to output would be to create a hidden type form component (https://github.com/bpmn-io/form-js/issues/200#issuecomment-1123170808)
@dfulgham This is what we settled on (@pinussilvestrus @Skaiir please confirm).
I wouldn't say we settled on anything as part of this epic with regards to passing data. In the end this raises questions about how we differentiate 'form' scope from 'input' scope, and this all will play into conditional rendering, FEEL, which are later epics for this and hence we'll defer the particular data passing case to then.
A hidden form component to do mappings would be a good way to handle this case though, so would pre-submit actions. These are both good brainstorms and we'll consider them both.
Following a sync, I'll provide a little bit of summary / context for @currandwyer :
Current icon set in use
text field - number - checkbox (individual) - radio (multiple) select - text (supports markdown and basic html) - button
We also have some unused icons. Here is the whole collection: Form icons.zip
The icons which are blocking progress currently are:
Some icons we might want to implement in the future would be:
Note that at this stage, we are very early in defining the requirements. Some icons will not make it, some are redundant and we might opt for a configuration option instead. These are only for context and we're not looking to produce them yet.
A library contributor has provided their implementation of a Fieldset icon already, I've provided it in the attached collection , if you think it's satisfactory, we can use that straight away. This is not within the scope but I'd love bit of feedback on it 😄.
More context:
Discussion thread on the Taglist The issue regarding the new basic fields
FYI @tasso94 => we documented our assumptions for the C7 tasklist integration (see breakdown). Could you please raise your hand in case this is unclear to you? Thanks
- Our working assumption is as following: C7 developers need to pass or retrieve data for the multi-element form components > by using the json type. https://github.com/bpmn-io/form-js/issues/200#issuecomment-979800606
- The C7 tasklist glue code / adapter would then transform this into a consumable format for form-js (essentially a JSON List > string)
What you documented sounds good to me. 🙂 👍
As part of this, we need to check if the external worker and java developer APIs support JSON data.
The C7 JS as well as the Java Client both support Json
typed variables:
One update regarding the breakdown: We will handle the form-js-playground integration separately, as it does not only depend on dynamic data anymore.
For transparency: We just released an alpha version with the dynamic input data feature included: https://github.com/bpmn-io/form-js/pull/282.
For visibility, tracking, linting and documentation concerns have moved over to https://github.com/bpmn-io/internal-docs/issues/596. We will now handle these things as part of release instead of continuously, as it reduces overheads and makes it easier for us to work with our various integrations.
Related: https://github.com/bpmn-io/internal-docs/issues/597
We will now handle these things as part of release instead of continuously, as it reduces overheads and makes it easier for us to work with our various integrations.
When did we decide this? And who decided it?
@nikku
This was initially in agreement with myself and @pinussilvestrus. We pitched this internally and @CatalinaMoisuc understands where we're coming from as well. If you want to clarify what it's all about we can have a chat.
@Skaiir see also my comment here: https://github.com/bpmn-io/internal-docs/issues/597#issuecomment-1188693392.
Also, what I agreed on is that it makes sense to wait with i.e. the tracking and documentation until we clarify with Tasklist their requirements. Your argument in that favour was that: we might need to change implementation for being able to integrate with Tasklist so it makes sense to wait so we don't have to make changes i.e. rewrite the docs.
See below:
To recap and make sure we are on the same page, until Tasklist is ready for these changes you plan to:
- prepare the implementation to make it compatible with Tasklist (when your contact persons from Tasklist are back)
- implement potential changes required by Tasklist (when your contact persons from Tasklist are back)
- prepare docs (depends on the integration with Tasklist - the previous two bullet points - so has to be done after potential changes are implemented)
- clarify what we should track and prepare that (doesn't have any dependencies, can just me done) And once we have the Tasklist release, we do integration testing and prepare that to release in Modeler.
Now given that @nikku mentioned that Tasklist is also releasing alphas monthly then we don't actually have to wait until October and moreover, if we agree on the approach to take with camunda-form-js
in #597, we might even want to release earlier.
I wouldn't worry too much about implementation requirements change now, as we clarified the API beforehand in discussions with the respective teams.
I think the point here is that we should not feel blocked in closing epics because we have to wait for certain activities that need at least final confirmation (linting, tracking, as mentioned above). These things can be handled in a separate manner (e.g. via a integration tracking issue).
However, I also agree we have the initiative we are trying to roll on (cf. https://github.com/bpmn-io/internal-docs/issues/597#issuecomment-1188693392). We should all agree as a team on the best approach, also including our users (our product teams).
Discuss development & integration strategy for form-js features
Note that:
In bpmn.js we use linting for detecting incompatibilities between Modeling and the execution platform. For instance: Connectors are only supported as of 8.0 and use a linting rule to highlight the incompatibility when an older execution platform is used
There are monthly alpha releases in Camunda Platform 8. The customer can create a cluster and choose channels alpha and choose the version i.e. Zeebe-8.1.0-alpha1
There is no linting available in Web Modeler for forms, furthermore, the feature only exists in camunda-modeler library
Next steps:
Draw the dependencies and how this feature can work end to end and highlight the implications for Web Modeler and Tasklist
Make linting available also in Web Modeler
Add linting rule to ensure that for older execution platforms that do not support these new properties are warned that the feature is not available
Agree on when this linting rule and the new form-js makes sense to be released in Web Modeler (depends on Tasklist alpha releases)
Discover how gracefully Tasklist handles the incompatibilities in case one user wants to deploy an incompatibile form feature to an older Tasklist version
cc @nikku, @christian-konrad, @Skaiir, @pinussilvestrus, @philippfromme
P.S. feel free to edit if I missed anything important.
As discussed, @Skaiir as the DRI, please make sure you open issues for the next steps and make the dependencies transparent in this epic.
What should we do?
Our users (e.g. SUPPORT-12025) require forms to be created dynamically based on input data, for example depending on a category, display specific form fields. Dynamic forms allow you to automatically create form fields and layouts based on ingesting data from any source.
This does not mean that we're going to add data transformation capabilities in form-js (as of now). The library itself only provides a simple in-out API to provide the necessary data and pipe it out afterward.
Prerequisites
Cf. Research Miro Board
form-js
currently delivers, and what it currently doesn't deliver (from the data schema perspective)form-js-playground
into Camunda Modeler 👍Breakdown
@bpmn-io/form-js@0.8.0-alpha.0
Other topics (related and follow up, but not in the scope of this epic)
Why should we do it?
Be able to create forms dynamically on given data.
Context: https://github.com/camunda/product-hub/issues/55 Cf. Value Proposition Cf. https://jira.camunda.com/browse/SUPPORT-12025