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(#7462) add cht-form web component for standalone Enketo form support #8153

Merged
merged 69 commits into from
Nov 22, 2023

Conversation

jkuester
Copy link
Contributor

@jkuester jkuester commented Mar 28, 2023

Closes #7462

See the issue for more context/commentary, but ultimately this PR adds configuration and a minimal amount of code into webapp to allow for generating a custom web component that will allow for rendering/interaction with CHT forms outside of a formal CHT instance. The web component is built from the existing Angular code in webapp, but is packaged into .js/.css files in such a way that it can be consumed externally by non-Angular webpages.

See medic/cht-conf-test-harness#245 for an example of how this web component will be used!

Also see https://github.com/medic/support-scripts/pull/12 for a super simple web page that uses the web component!

contact-save service refactor

In the previous refactoring of the EnketoService/FormService (#8455) I missed the contact-save.service code. This service owns all of the logic for saving contact forms (the form.service is used for rendering contact and app forms and for saving app forms). The Web Component needs to depend on the contact-save service logic for processing the submitted contact form data into the expected contact documents. However we do not want to also depend on the logic in the contact-save service for doing additional CHT things like running the client-side transitions.

So, I have refactored the contact-save service to move all the CHT-specific logic to the form.service (similar to what we did with the enketo.service code). Existing webapp code now will use the form-service for rendering/saving both app and contact forms. Then, the Web Component can depend directly on the contact-save.service (as well as the enketo.service) without pulling in a ton of extra dependencies.

(Note that as with the EnketoService/FormService refactor, I have tried to achieve the best balance of high unit test coverage vs spending days refactoring the tests. So, largely I duplicated the existing contact-save tests into the forms.service test file and made sure they all passed. Then I did my best to de-dupe the tests between the contact-save and the forms.service test file so there was not too much redundancy. However, I did not update the new forms.service tests (the ones I copied in) to mock the contact-save service. For the sake of time, I left them as they were in the contact-save service test file. This is not ideal, but I think is an acceptable trade-off...)

Caveats

@tatilepizs is adding proper e2e tests in a separate PR that will eventually be merged into this one. So, what you currently see in the tests directory just represents a prototype of future tests.

The contents of webapp/web-componenets/example are also just a prototype of a site that actually uses the web component. This directory will not be included when merging to master, but I am keeping it in here for now because it is useful when manually testing the web component.

Code review checklist

  • Readable: Concise, well named, follows the style guide, documented if necessary.
  • Documented: Configuration and user documentation on cht-docs
  • Tested: Unit and/or e2e where appropriate
  • Backwards compatible: Works with existing data and configuration or includes a migration. Any breaking changes documented in the release notes.

Compose URLs

If Build CI hasn't passed, these may 404:

License

The software is provided under AGPL-3.0. Contributions to this project are accepted under the same license.

@sonarcloud
Copy link

sonarcloud bot commented Sep 11, 2023

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 1 Bug
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 6 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

idea Catch issues before they fail your Quality Gate with our IDE extension sonarlint SonarLint

Component works to load hard-coded form!

Add enketo.component code to new component

Include z-score stub service!

Component builds with EnektoForm included!

Add TranslateModule to cht-form app.module

Basic component working (without Enekto)

feat: clean up stubs and tsconfig

feat: add stub services to get it to build!

Add initial code for cht-form component (still broken)

Initial config for cht-forms-component.  Things build, but nothing happens
Add some documentation for how to customize for different layout.
Copy link
Contributor

@tatilepizs tatilepizs left a 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. Thanks @jkuester

# Conflicts:
#	tests/page-objects/default/enketo/generic-form.wdio.page.js
#	tests/page-objects/default/enketo/pregnancy.wdio.page.js
#	webapp/src/ts/modules/contacts/contacts-edit.component.ts
#	webapp/tests/karma/ts/modules/contacts/contacts-edit.component.spec.ts
@jkuester
Copy link
Contributor Author

jkuester commented Nov 6, 2023

@garethbowen @dianabarsan FYI, I think we are pretty close to getting this landed! Ultimately we have not really deviated at all from the design discussed in #7462, so I feel pretty good about what have have! That being said, I did want to circle back with you for a final check of the overall structure since this is breaking some new ground in our code base. Let me know if there is anything here you find concerning or you think could be done better! Thanks!

Copy link
Member

@garethbowen garethbowen left a comment

Choose a reason for hiding this comment

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

Amazing.

I've added a few nitpick comments. The main question I have relates to whether we componentise the css and js and then actually use the web component in CHT webapp. It's probably too much work for right now, but curious if you think that's where we should plan to end up...

package.json Show resolved Hide resolved
tests/e2e/cht-form/wdio.conf.js Outdated Show resolved Hide resolved
tests/page-objects/default/enketo/delivery.wdio.page.js Outdated Show resolved Hide resolved
tests/page-objects/default/reports/reports.wdio.page.js Outdated Show resolved Hide resolved
webapp/tests/karma/karma-unit.base.conf.js Show resolved Hide resolved
webapp/web-components/cht-form/src/index.html Show resolved Hide resolved
@@ -0,0 +1,29 @@
<div class="reports">
<div class="content">
<div class="page" style="top: 0">
Copy link
Member

Choose a reason for hiding this comment

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

I feel like we're using the web component backwards... ie: the web component would usually define the CSS it needs and then be included in webapp which overwrites and extends with specific CSS. This comment implies that the web component is bringing in the entire webapp CSS and then overwriting it back to stock. Is that right? Is this because splitting out the CSS would be a big lift so we're leaving it for now?

@jkuester
Copy link
Contributor Author

jkuester commented Nov 6, 2023

@garethbowen for the sake of visibility, I wanted to address your comment regarding if the webapp should just be refactored to use the cht-form component here at the top level (since I think this may have relevance to future discussions on the subject). TLDR is yes, we have avoided splitting out css or refactoring the rest of the webapp to depend on the cht-form component for the sake of time. The goal was to start here with an MVP that had enough functionality to be useful to the test-harness, but also be generic enough to leave the door open to future reuse in the CHT, itself (as well as other places).

This approach was first considered back on the issue thread. At that time, I said that having webapp depend on cht-form:

is better, but the reality of our current situation might make the second proposal (leaving all the code in webapp) better just from a practical perspective. Then we can gradually work towards de-coupling the Enketo logic so that it would be feasible for the webapp code to actually consume the cht-form (and we could centralized the enketo-related logic....)

Most of that rational still holds, but we know a lot more now then we did back then about how this is all going to fit together

It might be possible for the CHT webapp code to depend on cht-form as an Angular component

Originally, I was thinking that for webapp to depend on cht-form, the only option would be to have webapp consume the built cht-form web component (and consume the js/css artifacts). This would be "best" from an encapsulation perspective, but would perhaps make things a lot more confusing from a code-reuse perspective (if cht-form depended on the same Angular service as the other CHT webapp code, then I guess you might end up with duplicate copies of the service code??? 🤔 ). As we have progressed in this project, though, I now think it might be possible to have a single component that both can be built into a web component as well as be integrated as a normal Angular component into the rest of the webapp code. I have not tested this yet, though.

Even if this works, it would not really solve all our problems here. We would still have to be careful with what the cht-form component depended on to make sure we are not pulling too much into the web component. Also, I do not think it would solve/simplify the css challenges. Ultimately, I am still undecided regarding if we even want to use the cht-form component as a normal Angular component, or if it would be better in the long term to just depend on the built cht-form artifacts....

Despite all of the refactoring work, there is still some tightly coupled code in webapp around forms

Things have been vastly improved, but in an effort to reduce the code-change footprint, we have minimized any changes to the code that consumes the enketo/form services. The CHT webapp enketo component is a no-logic wrapper for displaying Enketo forms. It is getting used to display contact/app/training forms, but those other components all have custom logic that now leverages the Form service in different ways to achieve their desired behavior. The cht-form component, on the other hand, is an opinionated wrapper for Enketo forms that handles interacting with the underlying Enekto and ContactSave services directly. I think the fault-lines in the code are now more clear than ever and even this discussion is evidence that we can see how cht-form might start to fit in with the rest of the CHT webapp code. However, the cht-form is still pretty far from being a drop-in replacement for the current enekto component.


At the end of the day, I feel like we have made a lot of positive progress here and the cht-form component should be reasonably maintainable even just as a spin-off of the main webapp code-base. While I am sure there are ways to further improve this structure (up to and including a refactoring that makes the CHT webapp code depend on cht-form) it is not yet obvious to me exactly what is the best way to proceed (or even what benefits would actually be realized from that work)...

Copy link
Member

@m5r m5r left a comment

Choose a reason for hiding this comment

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

Solid PR, now with even more solid tests on top of it! 💪

I've left only 2 comments there, one tiny fix and one API design question that I'd like to discuss before shipping the web component

tests/e2e/cht-form/wdio.conf.js Outdated Show resolved Hide resolved
webapp/web-components/cht-form/README.md Show resolved Hide resolved
@jkuester
Copy link
Contributor Author

@m5r I am off the rest of the week. I responded to your comments above, and if you agree with leaving the code as-is, can you go ahead and merge this to master? It would simplify some of what Tatiana is trying to do (as well and the Enekto uplift) if we can get this merged in and then rebase on top of it... So, I hate to leave it waiting until next week!

@m5r m5r merged commit 15bd199 into master Nov 22, 2023
38 checks passed
@m5r m5r deleted the 7462_forms_module branch November 22, 2023 21:25
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.

Make code for Enketo forms reusable outside cht-core
4 participants