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

Core 1498 Fix preferences validation #416

Merged
merged 9 commits into from
Sep 27, 2021
Merged

Conversation

sri2k1us
Copy link
Member

No description provided.

Comment on lines 389 to 394
if (values?.webhook?.url) {
const type = values?.webhook?.type?.type;
if (type === null || type === undefined || type === '') {
errors["webhook.type.type"] = t("webhookTypeError");
}
}
Copy link
Member Author

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 😭

Copy link
Member

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.

Copy link
Member Author

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 🤔

Copy link
Member

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"))

Copy link
Member Author

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}
Copy link
Member Author

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

Copy link
Member

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.

@@ -94,7 +93,7 @@ function updateWebhooks(webhooks) {
return callApi({
endpoint: `/api/webhooks`,
method: "PUT",
body: webhooks,
body: webhooks ? webhooks : { "webhooks": [] },
Copy link
Member Author

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.

Comment on lines +67 to +70
const hasURL = values?.webhook?.url ? true : false;
setEnableTestButton(hasURL && !isTesting);
}, [isTesting, values]);

Copy link
Member Author

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.

Comment on lines 66 to 71
React.useEffect(() => {
const hasURL = values?.webhook?.url ? true : false;
setEnableTestButton(hasURL && !isTesting);
setFieldTouched("webhook.type.type", hasURL, false);
}, [isTesting, setFieldTouched, values]);

Copy link
Member Author

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 ?

Copy link
Member

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.

Copy link
Member

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.

@sri2k1us
Copy link
Member Author

Also I think we should hide KB shortcuts we can implement them.

Comment on lines 390 to 391
const type = values?.webhook?.type?.type;
if (type === null || type === undefined || type === "") {
Copy link
Member

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:

Suggested change
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
Copy link
Member

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)}

Copy link
Member Author

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After field is touched:
image

Copy link
Member

@psarando psarando Sep 23, 2021

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: "" } },
}

Copy link
Member Author

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.

Comment on lines 66 to 71
React.useEffect(() => {
const hasURL = values?.webhook?.url ? true : false;
setEnableTestButton(hasURL && !isTesting);
setFieldTouched("webhook.type.type", hasURL, false);
}, [isTesting, setFieldTouched, values]);

Copy link
Member

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.

Comment on lines +95 to 100
validate={(value) => {
if (values?.webhook?.url && !value) {
return t("webhookTypeError");
}
}}
>
Copy link
Member Author

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.

@sri2k1us sri2k1us marked this pull request as ready for review September 24, 2021 15:22
Copy link
Member

@psarando psarando left a 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 = {
Copy link
Member

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}
Copy link
Member

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:

Suggested change
setFieldTouched={props.setFieldTouched}

Copy link
Member

@ash3rz ash3rz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM :shipit:

@sri2k1us
Copy link
Member Author

Thanks for the reviews.

@sri2k1us sri2k1us merged commit 9db9130 into cyverse-de:master Sep 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants