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

feat(data-integrity): add checks-selector #348

Merged
merged 29 commits into from
Mar 16, 2022

Conversation

Birkbjo
Copy link
Member

@Birkbjo Birkbjo commented Feb 25, 2022

https://jira.dhis2.org/browse/DHIS2-12286

Don't be too intimidated of all the file changes, most are updated fixtures for tests.

Should probably create a generic field component for 'java.lang.Set', however we still need to override the TransferOption due to the label not supporting a react-component. I plan to update this in UI though.

Note that the https://debug.dhis2.org/dev/api/dataIntegrity.json. endpoint contains properties like description, recommendation and introduction.

These are very inconsistent, and most jobs do not have all these properties - and description seem to just be a human readable name. After a brief discussion with Joe, we decided a simple MVP is good enough for now. So we opted to just show the name and severity.

This endpoint is "semi-dynamic", in the sense that it's described by a yaml-file, but still compiled at build-time, it also does not have support for translations. I've included translations for all the current jobs, but also have a simple fallback for any other jobs with a simple "snake"-case converter. This should all ideally be done on the backend, but we do what we have to work with what've got.

@Birkbjo Birkbjo requested review from a team as code owners February 25, 2022 17:19
@Birkbjo Birkbjo force-pushed the DHIS2-12286/feat/data-integrity-config branch from cfe9042 to 9343cf2 Compare February 25, 2022 17:24
@dhis2-bot
Copy link
Contributor

dhis2-bot commented Feb 25, 2022

🚀 Deployed on https://pr-348--dhis2-scheduler.netlify.app

@Mohammer5 Mohammer5 requested a review from a team February 28, 2022 10:14
Copy link
Contributor

@mediremi mediremi left a comment

Choose a reason for hiding this comment

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

LGTM ✔️

cypress.json Outdated
"env": {
"dhis2DataTestPrefix": "dhis2-scheduler",
"networkMode": "live",
"dhis2ApiVersion": "37"
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this not also be 38?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I would think so as well... Hendrik added this, but I guess the param from the command takes precedence, but will fix.

const checked = value === 'true'

if (!checked) {
// clear checks when "Run all" is selected
Copy link
Contributor

Choose a reason for hiding this comment

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

We have destroyOnUnregister enabled, see here, which should take care of removing the value if the field is unregistered. But I see you linked an open issue about conditional rendering causing issues. We're rendering the parameter fields conditionally, could what you encountered be solved in a similar manner?

Copy link
Member Author

@Birkbjo Birkbjo Mar 10, 2022

Choose a reason for hiding this comment

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

Well, I got errors that crashed the app, so I added the hidden-prop to fix this. It wasn't just because of conditional rendering, but conditional rendering in combination with updating the state of the component.

It does not seem like the value is cleared when conditionally rendering the field either. As you can toggle back and forth, and the selected checks will be there. We also need to mark the form as dirty when toggling back and forth (which onChange([]) does) - since we need to be able to switch from "some selected checks" to "run all", and be able to save the form (which is disabled when it's not dirty).

Copy link
Contributor

@ismay ismay Mar 10, 2022

Choose a reason for hiding this comment

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

I see. It seems like you're initializing the state for runSelected based on the previous value of the field. Which will be there if the user toggles back and forth between "run all" and "run only". It'll be lost anyway as soon as the user switches to another job type. If you lose that bit of logic and initialize runSelected to false there's no longer a need to clear the onChange (provided you conditionally render the transfer field in the field group), or use useField. That means you shouldn't run into the linked bug either (at least I didn't during testing, but let me know if I missed it).

I'd go with that. We don't save state for parameter settings between jobs anyway, and if not saving it for this section doesn't require workarounds and simplifies things I would personally go in that direction.

Copy link
Member Author

@Birkbjo Birkbjo Mar 10, 2022

Choose a reason for hiding this comment

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

If you lose that bit of logic and initialize runSelected to false

I'm not sure I follow, this would make it so that when you edit a Data integrity check with "selected checks", it would change it to Run all? That does not work.
The reason for checking for previous value of the field is so that you select the correct "toggle" based on the value of checks. Simple use case is to add a new check for a previous job; always defaulting to false, would make the user need to select the run selected checks?

I'd go with that. We don't save state for parameter settings between jobs anyway, and if not saving it for this section doesn't require workarounds and simplifies things I would personally go in that direction.

This is not the reason for the logic; see above. It's for when editing a job.

Copy link
Contributor

Choose a reason for hiding this comment

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

Haha, oh yeah of course you're right. Minor oversight on my part 😅. Wait, let me check one thing that might still satisfy that requirement.

Copy link
Member Author

@Birkbjo Birkbjo Mar 11, 2022

Choose a reason for hiding this comment

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

Thanks for looking into this! Actually makes sense for useField to prevent unregistering of the field. However, I don't really think this is much better than the current solution? And may have unintended side effect - see below. This is a bug in react-final-form anyway, and it's referenced in the code - so once it's fixed we could move the "hidden"-prop and conditionally render instead.

It might be cleaner to unmount the field, however we still need some logic to actually clear the data, if you edit an already existing job, and toggle from "selected checks" to "run all" in your example above, you won't be able to save the form. I think this is because the field is not mounted, and thus does not count as dirty? So the form would then be "pristine".

Other than that, your solution would potentially fix an annoying situation by not unmounting the field; we need to "change" the validation-function when Run all is selected, since we don't want to validate the checks in that case. Not sure if the current "complexity" is worth it, or if we should just drop validation entirely, as it's not actually that bad to not select any checks.

I do wonder if our usage of initialValues in the app is a little flawed. They'll be lost as soon as final form unregisters a field and clears the value, like when a user switches jobTypes for an existing job.

Yeah, haven't looked too much into that, but seems like we would need to change the destroyOnUnmount or something if we would like to keep the initialValues when unmounting fields?

Copy link
Member Author

Choose a reason for hiding this comment

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

Other than that, your solution would potentially fix an annoying situation by not unmounting the field; we need to "change" the validation-function when Run all is selected, since we don't want to validate the checks in that case. Not sure if the current "complexity" is worth it, or if we should just drop validation entirely, as it's not actually that bad to not select any checks.

Regarding this, I decided to fix this by having empty array meaning "run selected only", and null or undefined, meaning "run all". Should be a simple enough fix for the situation above.

Copy link
Contributor

@ismay ismay Mar 14, 2022

Choose a reason for hiding this comment

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

Yeah, haven't looked too much into that, but seems like we would need to change the destroyOnUnmount or something if we would like to keep the initialValues when unmounting fields?

Yeah, yeah the reason that that's there is so that if you switch a jobType, the existing parameters don't persist. Otherwise those parameters will be sent to the backend if the user submits, even if they don't match the current job. I suppose the backend would probably drop unrecognized job parameters, but it seemed more correct to me at the time.

That's also why I was thinking of a way to automatically remove the transfer values if it unregisters. My assumption was that selecting run all would mean you don't need the checks job parameter at all. But of course, run all is identical to selecting all checks (I assume?). Which is obvious of course, but I'd not even stopped to consider that.

So, first off, I'll approve the PR since I don't want to block you. Since I rewrote a lot of this app I tend to get a little product-managery about it, but that's not actually my position.

That being said. I can't help myself thinking that the design could be simplified. Instead of a "run all" radio button I'd just render the transfer at all times and forego the radios. After all, the transfer already has a convenient "select all" control. That would simplify our code and the UI if you ask me. Do you know if there's a technical reason why we didn't go with that approach?

(Also, let me know if I'm misunderstanding anything here. We're getting a little into the weeds technically, so maybe I'm overlooking sth here)

Copy link
Member Author

@Birkbjo Birkbjo Mar 14, 2022

Choose a reason for hiding this comment

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

So, first off, I'll approve the PR since I don't want to block you. Since I rewrote a lot of this app I tend to get a little product-managery about it, but that's not actually my position.

I absolutely understand this, no worries! There's a lot of decision that's taken here, and I don't know the full background. I've just tried to implement this feature without too drastic changes.

That being said. I can't help myself thinking that the design could be simplified. Instead of a "run all" radio button I'd just render the transfer at all times and forego the radios. After all, the transfer already has a convenient "select all" control. That would simplify our code and the UI if you ask me. Do you know if there's a technical reason why we didn't go with that approach?

I do agree with this point, and this was my first implementation, with a "If no checks are selected, all checks will be run"-message in the "SelectedEmptyComponent". But I talked to Joe, and he proposed the implemented solution. The reason being that it might be a bit confusing that actually selecting nothing selects all, and the reason below:
Manually having to select all would also probably not be the best (even with the "select all"-button), since if new checks are added in the backend, you would have to manually select them again. In the current solution, all checks will run regardless of user interaction. You might argue that the user have more "control" of not adding new checks - but this is how it always has been and we don't want this change to be too disruptive. It would potentially be confusing to users why some checks are not running.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. Since we already talked a bit on slack, I'll just add here what I said there: seems tricky to really simplify the UI then on our end. The requirements kind of dictate the current solution. Would be nice if eventually we could get rid of the two types of "all checks", because now effectively we have "all current and future checks" and "all explicitly selected checks". To me that wasn't really clear from the UI. Anyway, something for the future I guess. Thanks for explaining!

@ismay
Copy link
Contributor

ismay commented Mar 10, 2022

Ok, I see some of my questions were already answered in the PR description. Sorry about that. I'll go through them and close what you already explained.

@Birkbjo Birkbjo merged commit aa7baf4 into master Mar 16, 2022
@Birkbjo Birkbjo deleted the DHIS2-12286/feat/data-integrity-config branch March 16, 2022 08:47
dhis2-bot added a commit that referenced this pull request Mar 16, 2022
# [100.1.0](v100.0.4...v100.1.0) (2022-03-16)

### Features

* **data-integrity:** add checks-selector ([#348](#348)) ([aa7baf4](aa7baf4))
@dhis2-bot
Copy link
Contributor

🎉 This PR is included in version 100.1.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants