-
Notifications
You must be signed in to change notification settings - Fork 98
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
Add conditional rendering #403
Conversation
@nikku FEEL free to provide your feedback :) |
Try this out via |
4b0d4fc
to
a7a536a
Compare
"type": "textfield", | ||
"id": "Field", | ||
"key": "text", | ||
"condition": "=amount > 2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider renaming.
@@ -41,6 +41,7 @@ | |||
"@bpmn-io/snarkdown": "^2.1.0", | |||
"classnames": "^2.3.1", | |||
"didi": "^9.0.0", | |||
"feelin": "^0.41.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We haven't moved it out of @nikku'S repo/org, right? Should we do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Camunda can consider to fork it (i.e. publish via @bpmn-io/feelin
or the like). In this case it is likely the core modeling team to take responsibility over it.
But at this time I don't see it as strictly being required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do that as soon as we want to implement something in the library.
} | ||
|
||
try { | ||
const result = unaryTest(condition.slice(1), data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someone reading this may not know that you slice the first char to remove the "="
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment.
|
||
// TODO(@barmac): remove once https://github.com/moment/luxon/issues/193 is resolved | ||
function onwarn(warning, warn) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure that we want to ignore this? Can the built bundle still be consumed (conditions be evaluated)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
==> Let's add an integration test for this in form-js.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you expect to test? Something like 3c06472 ?
|
||
return result; | ||
} catch (error) { | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider not swallowing the error, but logging it (or emitting it via eventBus.fire(
error, ...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented via 848b703
} | ||
|
||
try { | ||
const result = unaryTest(condition.slice(1), data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess at this point we don't want to enable context sensitive parsing, right? Our inputs don't contain spaces and other special chars.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean. I need to pass data in order to correctly evaluate the condition, right?
import { unaryTest } from 'feelin'; | ||
import { isString } from 'min-dash'; | ||
|
||
export class ConditionChecker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome that this is pluggable. ❤️
|
||
/** | ||
* | ||
* @param {{ expression?: string } | undefined} condition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the result of this hook?
Return type is missing; unclear if it returns "true" to show or to hide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great addition (service + hook). Just found some nit-picks you may act upon.
Thanks, I will address the comments tomorrow :) |
function useVariables() { | ||
const form = useService('formEditor'); | ||
const schema = form.getSchema(); | ||
|
||
const variablesRef = useRef([]); | ||
|
||
const variables = getSchemaVariables(schema); | ||
const previousVariables = usePrevious(variables) || []; | ||
|
||
const variablesChanged = !areEqual(variables, previousVariables); | ||
|
||
if (variablesChanged) { | ||
variablesRef.current = variables.map(key => ({ name: key })); | ||
} | ||
|
||
return variablesRef.current; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we move this under /hooks
? I can imagine we will need this more often in the future (similar to useCondition
in the viewer
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think I could simplify this a bit...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK it's now simplified and exported from hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have to be careful here. The useService
hook that is used in the new useVariables
hook now needs a FormEditorContext
to work correctly. Note that the properties panel can also be rendered outside of the editor. We use our own useService
therefore: https://github.com/bpmn-io/form-js/blob/develop/packages/form-js-editor/src/features/properties-panel/hooks/usePropertiesPanelService.js
We either need the formEditor
to be provided as a parameter for this hook or, alternatively, move the useVariables
to the properties panels hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is probably why the tests started to fail after the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK it should be fine now.
*/ | ||
check(condition, data = {}) { | ||
if (!condition) { | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we allow to specify this defaultValue
? I could imagine other cases where we do not default a condition to true
, for example: readonly
=> default false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds to me more like a form field concern: it knows whether it should display or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Condition checker can be applied to anything, not only fields.
daad00c
to
8d73786
Compare
Based on https://github.com/camunda/product-hub/issues/56#issuecomment-1315173662, I will need to reverse the logic so that we use a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks quite good, just got a few cleanup suggestions :).
@@ -170,23 +170,24 @@ export default class Form { | |||
const data = this._getSubmitData(); | |||
|
|||
const errors = this.validate(); | |||
const filteredErrors = this._applyConditions(errors, data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should filter this upstream. It seems strange to me that we are still validating the fields which are hidden via condition, as I believe the form should just treat them as non-existent.
packages/form-js-viewer/src/Form.js
Outdated
|
||
return { | ||
...data, | ||
[ _path[ 0 ] ]: value | ||
}; | ||
}, {}); | ||
|
||
const filteredValues = this._applyConditions(rawValues, { ...initialData, ...rawValues }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again here, we're doing all the heavy lifting and filtering after the fact. I believe we should start filtering at the formField level. The way I would see it would be filterSomeHow(formFieldRegistry.getAll())
. Or maybe even formFieldRegistry.getVisible()
.
}); | ||
|
||
|
||
it('should use give precedence to form data to check condition', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lil typo
@barmac I'm not sure we should do the reversing in a separate issue. If I understand correctly you'd want to commit the current state once cleaned up to the The problem with that is that we should really avoid changes to the form schema, especially if we know they are going to be temporary and if they break backwards compatibility. I understand we don't want to be blocking this feature, but since this would break the backward compatibility of the schema, we'll still be blocked in practice from releasing until the inversion has been committed to |
Thanks for your feedback. It feels like we should have a conversation about this before the PR is merged. I'll set this up. |
@barmac can't run it in the playground: Bildschirmaufnahme.2022-11-23.um.17.56.42.mov |
2e3ae68
to
2ee4183
Compare
Condition is a FEEL unary test which can use any values passed to form to determine whether field should be displayed and submitted. Related to #374
4be7411
to
894c28d
Compare
This is now ready for review. It implements the "hide if" logic and includes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Just one comment, otherwise, let's merge and bring this out of the door 👍
|
||
const variablesList = useVariables(); | ||
|
||
// keep stable reference until https://github.com/bpmn-io/properties-panel/issues/196 is fixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be resolved now via 3a51c37
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! Let's check this in action.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK done
7725407
to
edb09b9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work!🥇
This PR implements conditional rendering via a
Field#conditional.hide
property. Condition needs to be a FEEL unary test which is parsed and evaluated by feelin. It is defined via the properties panel. Form designer can use any variables passed to the form object to define the condition.Closes #374
Closes #401
Closes #415
Follow-up issues: