-
Notifications
You must be signed in to change notification settings - Fork 16
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
Core 1498 Fix preferences validation #416
Conversation
if (values?.webhook?.url) { | ||
const type = values?.webhook?.type?.type; | ||
if (type === null || type === undefined || type === '') { | ||
errors["webhook.type.type"] = t("webhookTypeError"); | ||
} | ||
} |
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 validation will run but will not mark errors on the form 😭
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.
Going off memory, I think errors
is an object with the same format as the model you provided.
So errors["webhook.type.type"]
would be accessing an object like {"webhook.type.type": "someValue"}
instead of {webhook: {type: {type: "someValue"}}}
. So I think if you update this to errors.webhook.type.type
you'll get the result you want.
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.
Ahh that makes sense although errors.webhook.type.type = err msg
resulted in error. So I guess I have to construct the error object manually 🤔
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.
Actually that reminds me! I don't think it's advertised anywhere, but Formik has a setIn
function (similar to the getIn
function that we're using in our helper form fields) that would be useful in this case.
errors = setIn(errors, "webhook.type.type", t("webhookTypeError"))
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.
errors = { webhook: { type: { type: t("webhookTypeError") } } };
worked for me 🎉
size="small" | ||
component={FormTextField} | ||
component={FormSelectField} |
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.
If I add field level validation, it will work but I have to touch the field first 😕 . Also I had to change it FormSelectField
instead of FormTextField
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.
Having to touch the field first sounds right to me. If the user opens a blank form, for example, we don't want every field to automatically be red just because they haven't filled it out yet. So validation should run after a field has been touched or when the user tries to submit.
src/serviceFacades/users.js
Outdated
@@ -94,7 +93,7 @@ function updateWebhooks(webhooks) { | |||
return callApi({ | |||
endpoint: `/api/webhooks`, | |||
method: "PUT", | |||
body: webhooks, | |||
body: webhooks ? webhooks : { "webhooks": [] }, |
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.
Allow users to delete webhooks.
const hasURL = values?.webhook?.url ? true : false; | ||
setEnableTestButton(hasURL && !isTesting); | ||
}, [isTesting, values]); | ||
|
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.
Enable Test
button only when there is url or another test is not in progress.
React.useEffect(() => { | ||
const hasURL = values?.webhook?.url ? true : false; | ||
setEnableTestButton(hasURL && !isTesting); | ||
setFieldTouched("webhook.type.type", hasURL, false); | ||
}, [isTesting, setFieldTouched, values]); | ||
|
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 I got validation message to show up immediately after user tabs out of (onBlur) of url field. Is this reasonable ? or there is better way to do this ?
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 seems ok to me, but I'll defer to @psarando since he probably has the most experience with Formik.
An alternative might be to add a validate prop to the url field which does this same logic. That way, the logic should only run when the url value changes instead of when any value in values
changes.
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 it's acceptable to only show the validation error message if the user actually touches the Type field, or attempts to save the form without the Type set (and as far as I can tell the Type isn't required for testing the URL).
If we set the required
prop on the Type field based on the URL field's value, then I don't think we need to manually set this field as "touched" here.
Also I think we should |
const type = values?.webhook?.type?.type; | ||
if (type === null || type === undefined || type === "") { |
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 this is a bit simpler:
const type = values?.webhook?.type?.type; | |
if (type === null || type === undefined || type === "") { | |
if (!values?.webhook?.type?.type) { |
@@ -82,7 +90,6 @@ export default function Webhooks(props) { | |||
name="webhook.type.type" | |||
id={buildID(baseId, ids.WEBHOOK_TYPES_SELECT)} | |||
label={t("type")} | |||
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.
This could actually be set to true
if there is a value entered for the URL field:
required={!!(values?.webhook?.url)}
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.
Actually, doing this only partially solved the problem 🤔 . Now the formik
built in Required
validation marker shows up but our custom error message still doesn't show until the field is touched.
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.
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.
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 might be because every field in the form should have an initial value, even if it's an empty string: jaredpalmer/formik#445 (comment)
If you're seeing uncontrolled to controlled
warnings in the console for this field, then that's probably it.
So the mapPropsToValues
might need to return an empty webhook.
Looking at these form field names, maybe it needs to return something like this:
return {
...bootstrap.preferences,
webhook: { url: "", type: { type: "" } },
}
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.
Ahh yes. I keep forgetting to check initial values.
React.useEffect(() => { | ||
const hasURL = values?.webhook?.url ? true : false; | ||
setEnableTestButton(hasURL && !isTesting); | ||
setFieldTouched("webhook.type.type", hasURL, false); | ||
}, [isTesting, setFieldTouched, values]); | ||
|
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 it's acceptable to only show the validation error message if the user actually touches the Type field, or attempts to save the form without the Type set (and as far as I can tell the Type isn't required for testing the URL).
If we set the required
prop on the Type field based on the URL field's value, then I don't think we need to manually set this field as "touched" here.
validate={(value) => { | ||
if (values?.webhook?.url && !value) { | ||
return t("webhookTypeError"); | ||
} | ||
}} | ||
> |
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.
Finally got the validation to work by removing required
and adding field level validation.
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.
LGTM 👍
const mapPropsToValues = (bootstrap) => { | ||
const emptyPref = { |
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.
✨
webhookTopics={webhookTopics} | ||
webhookTypes={webhookTypes} | ||
values={props.values} | ||
setFieldTouched={props.setFieldTouched} |
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 like this is no longer needed:
setFieldTouched={props.setFieldTouched} |
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.
LGTM
Thanks for the reviews. |
No description provided.