@openmrs/esm-fast-data-entry-app 1.0.0-pre.9 → 1.0.1-pre.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +10 -0
- package/.husky/pre-push +1 -6
- package/.yarn/plugins/@yarnpkg/plugin-version.cjs +550 -0
- package/.yarn/versions/7ee3eceb.yml +0 -0
- package/README.md +39 -12
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/docs/config-icrc-forms.png +0 -0
- package/docs/config-other-forms.png +0 -0
- package/docs/configuring-form-categories.md +77 -0
- package/docs/fde-workflow.mov +0 -0
- package/docs/form-workflow-state-diagram.png +0 -0
- package/jest.config.json +20 -18
- package/package.json +97 -106
- package/src/FormBootstrap.tsx +151 -0
- package/src/Root.tsx +14 -3
- package/src/add-group-modal/AddGroupModal.tsx +209 -0
- package/src/add-group-modal/styles.scss +35 -0
- package/src/config-schema.ts +63 -31
- package/src/context/FormWorkflowContext.tsx +114 -0
- package/src/context/FormWorkflowReducer.ts +277 -0
- package/src/context/GroupFormWorkflowContext.tsx +141 -0
- package/src/context/GroupFormWorkflowReducer.ts +272 -0
- package/src/empty-state/EmptyDataIllustration.tsx +51 -0
- package/src/empty-state/EmptyState.tsx +33 -0
- package/src/empty-state/styles.scss +55 -0
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +230 -0
- package/src/form-entry-workflow/form-review-card/FormReviewCard.tsx +50 -0
- package/src/form-entry-workflow/form-review-card/index.ts +3 -0
- package/src/form-entry-workflow/form-review-card/styles.scss +39 -0
- package/src/form-entry-workflow/index.ts +3 -0
- package/src/form-entry-workflow/patient-banner/PatientBanner.test.tsx +9 -0
- package/src/form-entry-workflow/patient-banner/PatientBanner.tsx +86 -0
- package/src/form-entry-workflow/patient-banner/index.ts +3 -0
- package/src/form-entry-workflow/patient-banner/styles.scss +45 -0
- package/src/form-entry-workflow/patient-search-header/PatientSearchHeader.tsx +63 -0
- package/src/form-entry-workflow/patient-search-header/index.ts +3 -0
- package/src/form-entry-workflow/patient-search-header/styles.scss +22 -0
- package/src/form-entry-workflow/styles.scss +64 -0
- package/src/form-entry-workflow/workflow-review/WorkflowReview.tsx +35 -0
- package/src/form-entry-workflow/workflow-review/index.ts +3 -0
- package/src/form-entry-workflow/workflow-review/styles.scss +34 -0
- package/src/forms-app-menu-link.tsx +3 -2
- package/src/forms-page/FormsPage.tsx +129 -0
- package/src/forms-page/forms-table/FormsTable.tsx +131 -0
- package/src/forms-page/forms-table/index.ts +3 -0
- package/src/forms-page/forms-table/styles.scss +20 -0
- package/src/forms-page/index.ts +3 -0
- package/src/forms-page/styles.scss +11 -0
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +413 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.test.tsx +9 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.tsx +45 -0
- package/src/group-form-entry-workflow/group-banner/index.ts +3 -0
- package/src/group-form-entry-workflow/group-banner/styles.scss +60 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +106 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +63 -0
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +93 -0
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +64 -0
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +35 -0
- package/src/group-form-entry-workflow/group-search/group-search.scss +94 -0
- package/src/group-form-entry-workflow/group-search/mock-group-data.ts +79 -0
- package/src/group-form-entry-workflow/group-search/useGroupSearch.ts +14 -0
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +42 -0
- package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
- package/src/group-form-entry-workflow/group-search-header/styles.scss +20 -0
- package/src/group-form-entry-workflow/index.ts +3 -0
- package/src/group-form-entry-workflow/styles.scss +86 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/useFormState.ts +23 -0
- package/src/hooks/useGetAllForms.ts +45 -0
- package/src/hooks/useGetEncounter.ts +21 -0
- package/src/hooks/useGetPatient.ts +23 -0
- package/src/hooks/useKeyPress.ts +31 -0
- package/src/hooks/usePostCohort.ts +18 -0
- package/src/index.ts +20 -4
- package/src/patient-card/PatientCard.tsx +67 -0
- package/src/patient-card/index.ts +3 -0
- package/src/patient-card/styles.scss +45 -0
- package/translations/en.json +49 -4
- package/tsconfig.json +26 -23
- package/.eslintrc +0 -4
- package/.github/workflows/node.js.yml +0 -79
- package/.husky/pre-commit +0 -6
- package/dist/24.js +0 -3
- package/dist/24.js.LICENSE.txt +0 -16
- package/dist/24.js.map +0 -1
- package/dist/294.js +0 -3
- package/dist/294.js.LICENSE.txt +0 -14
- package/dist/294.js.map +0 -1
- package/dist/296.js +0 -2
- package/dist/296.js.map +0 -1
- package/dist/299.js +0 -2
- package/dist/299.js.map +0 -1
- package/dist/382.js +0 -3
- package/dist/382.js.LICENSE.txt +0 -8
- package/dist/382.js.map +0 -1
- package/dist/415.js +0 -2
- package/dist/415.js.map +0 -1
- package/dist/574.js +0 -1
- package/dist/595.js +0 -3
- package/dist/595.js.LICENSE.txt +0 -1
- package/dist/595.js.map +0 -1
- package/dist/69.js +0 -2
- package/dist/69.js.map +0 -1
- package/dist/735.js +0 -3
- package/dist/735.js.LICENSE.txt +0 -29
- package/dist/735.js.map +0 -1
- package/dist/777.js +0 -2
- package/dist/777.js.map +0 -1
- package/dist/860.js +0 -2
- package/dist/860.js.map +0 -1
- package/dist/906.js +0 -2
- package/dist/906.js.map +0 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +0 -369
- package/dist/openmrs-esm-fast-data-entry-app.js.map +0 -1
- package/dist/openmrs-esm-fast-data-entry-app.old +0 -2
- package/src/boxes/extensions/blue-box.tsx +0 -15
- package/src/boxes/extensions/box.scss +0 -23
- package/src/boxes/extensions/brand-box.tsx +0 -15
- package/src/boxes/extensions/red-box.tsx +0 -15
- package/src/boxes/slot/boxes.css +0 -23
- package/src/boxes/slot/boxes.tsx +0 -19
- package/src/forms/FormsRoot.tsx +0 -32
- package/src/forms/FormsTable.tsx +0 -64
- package/src/forms/mockData.ts +0 -43
- package/src/greeter/greeter.css +0 -4
- package/src/greeter/greeter.test.tsx +0 -29
- package/src/greeter/greeter.tsx +0 -25
- package/src/hello.css +0 -3
- package/src/hello.test.tsx +0 -45
- package/src/hello.tsx +0 -30
- package/src/patient-getter/patient-getter.resource.ts +0 -31
- package/src/patient-getter/patient-getter.test.tsx +0 -28
- package/src/patient-getter/patient-getter.tsx +0 -28
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,12 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# OpenMRS ESM Fast Data Entry App
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# OpenMRS ESM Fast Data Entry App
|
|
4
|
+
|
|
5
|
+
The Fast Data Entry App is a module for the [OpenMRS](https://openmrs.org/) healthcare platform which allows for a natural workflow when entering many pre-recorded forms at a time. It is not meant for point-of-care workflows, but rather as a way to do retrospective data entry.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
Currently the app consists of two main parts, a Forms Page to list available forms and a Form Workflow which allows the rapid input of forms.
|
|
9
|
+
|
|
10
|
+
### Forms Page
|
|
11
|
+
The Forms page lists all forms able to be seen by a user, filtered by that user's permission to edit the given form. Additionally implementors are able to customize the page by creating form categories and listing the forms inside of each category. These categories can then be shown or hidden using configuration (see more [here](docs/configuring-form-categories.md)). From these lists forms are able to be opened in the Form Workflow using the 'Fill form' button.
|
|
12
|
+
|
|
13
|
+
### Form Workflow
|
|
14
|
+
Forms can be entered quickly with the Form Entry Workflow. This workflow depends on a state machine managed by the [FormWorkflowReducer](src/context/FormWorkflowReducer.ts).
|
|
15
|
+
|
|
16
|
+
See the video below of a normal workflow.
|
|
17
|
+
|
|
18
|
+
https://user-images.githubusercontent.com/5445264/181378774-341b2a2f-3ecc-4052-b960-d61ba07980fb.mov
|
|
19
|
+
|
|
20
|
+
State diagram for the Form Workflow.
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
## Running this code
|
|
25
|
+
|
|
26
|
+
Clone the repo locally, then install and run using
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
yarn # to install dependencies
|
|
30
|
+
yarn start # to run the dev server
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
To customize your development build pass other arguments to yarn start (which under the hood is running `npx openmrs develop`). For example to point to a backend other than [dev3](https://dev3.openmrs.org/) specify the `--backend` option. See the full example below for running against an ICRC backend.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
yarn start --importmap "https://spa-modules.nyc3.digitaloceanspaces.com/import-map.json" --backend "https://openmrs-dev-v2.test.icrc.org/" --add-cookie "MRHSession=abcdefghijklmnop012345678910" --spa-path "/ui"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
To see more options run `npx openmrs --help`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
var _openmrs_esm_fast_data_entry_app;(()=>{function b(a){var c=h[a];if(void 0!==c)return c.exports;var d=h[a]={id:a,loaded:!1,exports:{}};return G[a].call(d.exports,d,d.exports,b),d.loaded=!0,d.exports}var j,k,q,v,w,x,y,z,A,B,C,D,E,F,G={7140:(b,c,d)=>{var f={"./start":()=>d.e(132).then(()=>()=>d(8132))},e=(a,b)=>(d.R=b,b=d.o(f,a)?f[a]():Promise.resolve().then(()=>{throw new Error("Module \""+a+"\" does not exist in container.")}),d.R=void 0,b),a=(b,c)=>{if(d.S){var e=d.S["default"];if(e&&e!==b)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return d.S["default"]=b,d.I("default",c)}};d.d(c,{get:()=>e,init:()=>a})}},h={};b.m=G,b.c=h,b.n=a=>{var c=a&&a.__esModule?()=>a.default:()=>a;return b.d(c,{a:c}),c},b.d=(a,c)=>{for(var d in c)b.o(c,d)&&!b.o(a,d)&&Object.defineProperty(a,d,{enumerable:!0,get:c[d]})},b.f={},b.e=a=>Promise.all(Object.keys(b.f).reduce((c,d)=>(b.f[d](a,c),c),[])),b.u=a=>a+".js",b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(a){if("object"==typeof window)return window}}(),b.o=(a,b)=>Object.prototype.hasOwnProperty.call(a,b),j={},k="@openmrs/esm-fast-data-entry-app:",b.l=(c,e,g)=>{if(j[c])j[c].push(e);else{var h,a;if(void 0!==g)for(var m,n=document.getElementsByTagName("script"),o=0;o<n.length;o++)if(m=n[o],m.getAttribute("src")==c||m.getAttribute("data-webpack")==k+g){h=m;break}h||(a=!0,(h=document.createElement("script")).charset="utf-8",h.timeout=120,b.nc&&h.setAttribute("nonce",b.nc),h.setAttribute("data-webpack",k+g),h.src=c),j[c]=[e];var q=(b,f)=>{h.onerror=h.onload=null,clearTimeout(d);var e=j[c];if(delete j[c],h.parentNode&&h.parentNode.removeChild(h),e&&e.forEach(a=>a(f)),b)return b(f)},d=setTimeout(q.bind(null,void 0,{type:"timeout",target:h}),12e4);h.onerror=q.bind(null,h.onerror),h.onload=q.bind(null,h.onload),a&&document.head.appendChild(h)}},b.r=a=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(a,"__esModule",{value:!0})},b.nmd=a=>(a.paths=[],a.children||(a.children=[]),a),(()=>{b.S={};var c={},d={};b.I=(e,f)=>{f||(f=[]);var g=d[e];if(g||(g=d[e]={}),!(0<=f.indexOf(g))){if(f.push(g),c[e])return c[e];b.o(b.S,e)||(b.S[e]={});var h=b.S[e],i=(b,c,d,e)=>{var f=h[b]=h[b]||{},a=f[c];a&&(a.loaded||(!e==!a.eager?!("@openmrs/esm-fast-data-entry-app">a.from):!e))||(f[c]={get:d,from:"@openmrs/esm-fast-data-entry-app",eager:!!e})},j=[];return"default"===e&&(i("@carbon/react","1.11.0",()=>Promise.all([b.e(820),b.e(327),b.e(569),b.e(672),b.e(183)]).then(()=>()=>b(8569))),i("@openmrs/esm-framework","4.0.2-pre.275",()=>Promise.all([b.e(595),b.e(672)]).then(()=>()=>b(595))),i("react-dom","18.2.0",()=>Promise.all([b.e(935),b.e(672)]).then(()=>()=>b(3935))),i("react-i18next","11.18.5",()=>Promise.all([b.e(247),b.e(672)]).then(()=>()=>b(8247))),i("react-router-dom","6.3.0",()=>Promise.all([b.e(68),b.e(672)]).then(()=>()=>b(6068))),i("react","18.2.0",()=>b.e(294).then(()=>()=>b(7294)))),c[e]=j.length?Promise.all(j).then(()=>c[e]=1):1}}})(),(()=>{var a;b.g.importScripts&&(a=b.g.location+"");var c=b.g.document;if(!a&&c&&(c.currentScript&&(a=c.currentScript.src),!a)){var d=c.getElementsByTagName("script");d.length&&(a=d[d.length-1].src)}if(!a)throw new Error("Automatic publicPath is not supported in this browser");a=a.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),b.p=a})(),q=a=>{var b=a=>a.split(".").map(a=>+a==a?+a:a),c=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(a),d=c[1]?b(c[1]):[];return c[2]&&(d.length++,d.push.apply(d,b(c[2]))),c[3]&&(d.push([]),d.push.apply(d,b(c[3]))),d},v=(b,c)=>{b=q(b),c=q(c);for(var d=0;;){if(d>=b.length)return d<c.length&&"u"!=(typeof c[d])[0];var f=b[d],a=(typeof f)[0];if(d>=c.length)return"u"==a;var g=c[d],h=(typeof g)[0];if(a!=h)return"o"==a&&"n"==h||"s"==h||"u"==a;if("o"!=a&&"u"!=a&&f!=g)return f<g;d++}},w=a=>{function b(){return g.pop().replace(/^\((.+)\)$/,"$1")}var c=a[0],d="";if(1===a.length)return"*";if(c+.5){d+=0==c?">=":-1==c?"<":1==c?"^":2==c?"~":0<c?"=":"!=";for(var e=1,f=1;f<a.length;f++)e--,d+="u"==(typeof(h=a[f]))[0]?"-":(0<e?".":"")+(e=2,h);return d}var g=[];for(f=1;f<a.length;f++){var h=a[f];g.push(0===h?"not("+b()+")":1===h?"("+b()+" || "+b()+")":2===h?g.pop()+" "+g.pop():w(h))}return b()},x=(b,e)=>{if(0 in b){e=q(e);var g=b[0],j=0>g;j&&(g=-g-1);for(var a=0,k=1,m=!0;;k++,a++){var o,t,v=k<b.length?(typeof b[k])[0]:"";if(a>=e.length||"o"==(t=(typeof(o=e[a]))[0]))return!m||("u"==v?k>g&&!j:""==v!=j);if("u"==t){if(!m||"u"!=v)return!1;}else if(!m)"s"!=v&&"n"!=v&&(m=!1,k--);else if(v==t){if(!(k<=g)){if(j?o>b[k]:o<b[k])return!1;o!=b[k]&&(m=!1)}else if(o!=b[k])return!1;}else if("s"!=v&&"n"!=v){if(j||k<=g)return!1;m=!1,k--}else{if(k<=g||t<v!=j)return!1;m=!1}}}var d=[],p=d.pop.bind(d);for(a=1;a<b.length;a++){var c=b[a];d.push(1==c?p()|p():2==c?p()&p():c?x(c,e):!p())}return!!p()},y=(a,b)=>{var c=a[b];return Object.keys(c).reduce((a,b)=>a&&(c[a].loaded||!v(a,b))?a:b,0)},z=(a,b,c,d)=>"Unsatisfied version "+c+" from "+(c&&a[b][c].from)+" of shared singleton module "+b+" (required "+w(d)+")",A=(b,c,d,e)=>{var f=y(b,d);return x(e,f)||"undefined"!=typeof console&&console.warn&&console.warn(z(b,d,f,e)),B(b[d][f])},B=a=>(a.loaded=1,a.get()),C=(c=>function(d,e,f,g){var a=b.I(d);return a&&a.then?a.then(c.bind(c,d,b.S[d],e,f,g)):c(0,b.S[d],e,f,g)})((c,d,e,f,g)=>d&&b.o(d,e)?A(d,0,e,f):g()),D={},E={1672:()=>C("default","react",[1,18],()=>b.e(294).then(()=>()=>b(7294))),5183:()=>C("default","react-dom",[1,18],()=>b.e(935).then(()=>()=>b(3935))),1132:()=>C("default","@openmrs/esm-framework",[0],()=>Promise.all([b.e(595),b.e(672)]).then(()=>()=>b(595))),1338:()=>C("default","react-router-dom",[1,6],()=>b.e(68).then(()=>()=>b(6068))),3397:()=>C("default","react-i18next",[1,11],()=>b.e(247).then(()=>()=>b(8247))),4422:()=>C("default","@carbon/react",[1,1,9,0],()=>Promise.all([b.e(820),b.e(327),b.e(569),b.e(183)]).then(()=>()=>b(8569)))},F={132:[1132],183:[5183],397:[3397],672:[1672],804:[1338],877:[4422]},b.f.consumes=(a,c)=>{b.o(F,a)&&F[a].forEach(d=>{if(b.o(D,d))return c.push(D[d]);var e=a=>{D[d]=0,b.m[d]=c=>{delete b.c[d],c.exports=a()}},f=a=>{delete D[d],b.m[d]=()=>{throw delete b.c[d],a}};try{var g=E[d]();g.then?c.push(D[d]=g.then(e).catch(f)):e(g)}catch(a){f(a)}})},(()=>{var c={447:0};b.f.j=(d,e)=>{var f=b.o(c,d)?c[d]:void 0;if(0!==f)if(f)e.push(f[2]);else if(/^(183|397|672)$/.test(d))c[d]=0;else{var g=new Promise((b,e)=>f=c[d]=[b,e]);e.push(f[2]=g);var a=b.p+b.u(d),h=new Error;b.l(a,e=>{if(b.o(c,d)&&(0!==(f=c[d])&&(c[d]=void 0),f)){var g=e&&("load"===e.type?"missing":e.type),a=e&&e.target&&e.target.src;h.message="Loading chunk "+d+" failed.\n("+g+": "+a+")",h.name="ChunkLoadError",h.type=g,h.request=a,f[1](h)}},"chunk-"+d,d)}};var a=(d,e)=>{var f,g,[h,j,i]=e,k=0;if(h.some(a=>0!==c[a])){for(f in j)b.o(j,f)&&(b.m[f]=j[f]);i&&i(b)}for(d&&d(e);k<h.length;k++)g=h[k],b.o(c,g)&&c[g]&&c[g][0](),c[g]=0},d=self.webpackChunk_openmrs_esm_fast_data_entry_app=self.webpackChunk_openmrs_esm_fast_data_entry_app||[];d.forEach(a.bind(null,0)),d.push=a.bind(null,d.push.bind(d))})(),b.nc=void 0;var m=b(7140);_openmrs_esm_fast_data_entry_app=m})();
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Configuring Form Categories for Fast Data Entry App
|
|
2
|
+
|
|
3
|
+
Configuration of which Form Categories to show, and which forms exist within each category is possible via configuration of Fast Data Entry App [config-schema](../src/config-schema.ts). For example, the configuration would setup one category "ICRC Forms" which contains one form, DASS-21. Note that formUUID must match the form UUID on the backend instance, and name is only for human readability and has no actual function.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"@openmrs/esm-fast-data-entry-app": {
|
|
8
|
+
"formCategories": [
|
|
9
|
+
{
|
|
10
|
+
"name": "ICRC Forms",
|
|
11
|
+
"forms": [
|
|
12
|
+
{
|
|
13
|
+
"formUUID": "373086b0-0a65-3763-ab83-21b8867bbc6f",
|
|
14
|
+
"name": "DASS-21"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"formCategoriesToShow": [
|
|
20
|
+
"ICRC Forms"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This config results in the following UI:
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
Note that All Forms is always present and contains all forms the system can find.
|
|
31
|
+
|
|
32
|
+
Let's see another example. The following config will load up one more form category called "Other Forms" to show, but both entries in that form category are not able to be found in the system, so no forms will render when we navigate to the "Other Forms". Also note that "Third Category of Forms" is declared, but since it's not included in the formCategoriesToShow array it is not displayed on the UI.
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"@openmrs/esm-fast-data-entry-app": {
|
|
37
|
+
"formCategories": [{
|
|
38
|
+
"name": "ICRC Forms",
|
|
39
|
+
"forms": [{
|
|
40
|
+
"formUUID": "373086b0-0a65-3763-ab83-21b8867bbc6f",
|
|
41
|
+
"name": "DASS-21"
|
|
42
|
+
}]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "Other Forms",
|
|
46
|
+
"forms": [{
|
|
47
|
+
"formUUID": "00000000-0a65-3763-ab83-21b",
|
|
48
|
+
"name": "No Matching UUID"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"formUUID": "This isn't a UUID!",
|
|
52
|
+
"name": "Invalid UUID"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "Third Category of Forms",
|
|
58
|
+
"forms": [{
|
|
59
|
+
"formUUID": "ce7a6da7-444a-3038-bfc2-334ff84b86c0",
|
|
60
|
+
"name": "CRIES-8"
|
|
61
|
+
}]
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"formCategoriesToShow": [
|
|
65
|
+
"ICRC Forms",
|
|
66
|
+
"Other Forms"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This will render the following UI
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
For more information on using the OpenMRS configuration system see [this page](https://o3-dev.docs.openmrs.org/#/main/config)
|
|
Binary file
|
|
Binary file
|
package/jest.config.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"^
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"transform": {
|
|
4
|
+
"^.+\\.tsx?$": "@swc/jest"
|
|
5
|
+
},
|
|
6
|
+
"transformIgnorePatterns": ["/node_modules/(?!@openmrs)"],
|
|
7
|
+
"moduleNameMapper": {
|
|
8
|
+
"\\.(s?css)$": "identity-obj-proxy",
|
|
9
|
+
"@openmrs/esm-framework": "@openmrs/esm-framework/mock",
|
|
10
|
+
"^lodash-es/(.*)$": "lodash/$1",
|
|
11
|
+
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"setupFilesAfterEnv": [
|
|
14
|
+
"<rootDir>/src/setup-tests.ts"
|
|
15
|
+
],
|
|
16
|
+
"testEnvironment": "jsdom",
|
|
17
|
+
"testEnvironmentOptions": {
|
|
18
|
+
"url": "http://localhost/"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,106 +1,97 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@openmrs/esm-fast-data-entry-app",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"license": "MPL-2.0",
|
|
5
|
-
"description": "An OpenMRS 3.x microfrontend",
|
|
6
|
-
"browser": "dist/openmrs-esm-fast-data-entry-app.js",
|
|
7
|
-
"main": "src/index.ts",
|
|
8
|
-
"source": true,
|
|
9
|
-
"scripts": {
|
|
10
|
-
"start": "openmrs develop",
|
|
11
|
-
"serve": "webpack serve --mode=development",
|
|
12
|
-
"build": "webpack --mode production",
|
|
13
|
-
"analyze": "webpack --mode=production --env.analyze=true",
|
|
14
|
-
"lint": "eslint src --
|
|
15
|
-
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
16
|
-
"typescript": "tsc",
|
|
17
|
-
"test": "jest --config jest.config.json",
|
|
18
|
-
"verify": "concurrently 'yarn:lint' 'yarn:test' 'yarn:typescript'",
|
|
19
|
-
"coverage": "yarn test -- --coverage",
|
|
20
|
-
"prepare": "husky install"
|
|
21
|
-
},
|
|
22
|
-
"husky": {
|
|
23
|
-
"hooks": {
|
|
24
|
-
"pre-commit": "pretty-quick --staged && yarn verify"
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"browserslist": [
|
|
28
|
-
"extends browserslist-config-openmrs"
|
|
29
|
-
],
|
|
30
|
-
"keywords": [
|
|
31
|
-
"openmrs",
|
|
32
|
-
"microfrontends"
|
|
33
|
-
],
|
|
34
|
-
"repository": {
|
|
35
|
-
"type": "git",
|
|
36
|
-
"url": "git+https://github.com/openmrs/openmrs-esm-fast-data-entry-app.git"
|
|
37
|
-
},
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
},
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"@openmrs/esm-framework": "
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"react
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"@
|
|
66
|
-
"@
|
|
67
|
-
"@
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"pretty-quick": "^3.1.0",
|
|
99
|
-
"react": "^16.13.1",
|
|
100
|
-
"react-dom": "^16.14.0",
|
|
101
|
-
"react-i18next": "^11.16.9",
|
|
102
|
-
"react-router-dom": "^5.2.0",
|
|
103
|
-
"rxjs": "^6.5.4",
|
|
104
|
-
"typescript": "^4.3.2"
|
|
105
|
-
}
|
|
106
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@openmrs/esm-fast-data-entry-app",
|
|
3
|
+
"version": "1.0.1-pre.8",
|
|
4
|
+
"license": "MPL-2.0",
|
|
5
|
+
"description": "An OpenMRS 3.x microfrontend",
|
|
6
|
+
"browser": "dist/openmrs-esm-fast-data-entry-app.js",
|
|
7
|
+
"main": "src/index.ts",
|
|
8
|
+
"source": true,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "openmrs develop",
|
|
11
|
+
"serve": "webpack serve --mode=development",
|
|
12
|
+
"build": "webpack --mode production",
|
|
13
|
+
"analyze": "webpack --mode=production --env.analyze=true",
|
|
14
|
+
"lint": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" --fix --max-warnings=0 -c .eslintrc.js",
|
|
15
|
+
"prettier": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
16
|
+
"typescript": "tsc",
|
|
17
|
+
"test": "jest --config jest.config.json --passWithNoTests",
|
|
18
|
+
"verify": "concurrently 'yarn:lint' 'yarn:test' 'yarn:typescript'",
|
|
19
|
+
"coverage": "yarn test -- --coverage ",
|
|
20
|
+
"prepare": "husky install"
|
|
21
|
+
},
|
|
22
|
+
"husky": {
|
|
23
|
+
"hooks": {
|
|
24
|
+
"pre-commit": "pretty-quick --staged && yarn verify"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"browserslist": [
|
|
28
|
+
"extends browserslist-config-openmrs"
|
|
29
|
+
],
|
|
30
|
+
"keywords": [
|
|
31
|
+
"openmrs",
|
|
32
|
+
"microfrontends"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/openmrs/openmrs-esm-fast-data-entry-app.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/openmrs/openmrs-esm-fast-data-entry-app#readme",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/openmrs/openmrs-esm-fast-data-entry-app/issues"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@carbon/react": "^1.9.0",
|
|
47
|
+
"@openmrs/esm-framework": "*",
|
|
48
|
+
"react": "18.x",
|
|
49
|
+
"react-dom": "18.x",
|
|
50
|
+
"react-i18next": "11.x",
|
|
51
|
+
"react-router-dom": "6.x"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@carbon/react": "^1.9.0",
|
|
55
|
+
"@openmrs/esm-framework": "next",
|
|
56
|
+
"@swc/core": "^1.2.245",
|
|
57
|
+
"@swc/jest": "^0.2.22",
|
|
58
|
+
"@testing-library/dom": "^7.20.0",
|
|
59
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
60
|
+
"@testing-library/react": "^13.3.0",
|
|
61
|
+
"@testing-library/user-event": "^14.4.3",
|
|
62
|
+
"@types/jest": "^28.1.7",
|
|
63
|
+
"@types/react-dom": "^18.0.6",
|
|
64
|
+
"@types/react-router-dom": "^5.3.3",
|
|
65
|
+
"@types/testing-library__jest-dom": "^5.14.5",
|
|
66
|
+
"@types/webpack-env": "^1.16.0",
|
|
67
|
+
"@typescript-eslint/parser": "^5.14.0",
|
|
68
|
+
"concurrently": "^6.2.0",
|
|
69
|
+
"eslint": "^8.20.0",
|
|
70
|
+
"eslint-config-prettier": "^8.3.0",
|
|
71
|
+
"eslint-config-react-app": "^7.0.1",
|
|
72
|
+
"eslint-config-ts-react-important-stuff": "^3.0.0",
|
|
73
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
74
|
+
"husky": "^8.0.1",
|
|
75
|
+
"identity-obj-proxy": "^3.0.0",
|
|
76
|
+
"jest": "^28.1.3",
|
|
77
|
+
"jest-cli": "^28.1.3",
|
|
78
|
+
"jest-environment-jsdom": "^28.1.3",
|
|
79
|
+
"openmrs": "next",
|
|
80
|
+
"prettier": "^2.3.0",
|
|
81
|
+
"pretty-quick": "^3.1.0",
|
|
82
|
+
"react": "^18.2.0",
|
|
83
|
+
"react-dom": "^18.2.0",
|
|
84
|
+
"react-i18next": "^11.18.4",
|
|
85
|
+
"react-router-dom": "^6.3.0",
|
|
86
|
+
"semver": "^7.3.7",
|
|
87
|
+
"swc-loader": "^0.2.3",
|
|
88
|
+
"swr": "^1.3.0",
|
|
89
|
+
"typescript": "^4.7.3",
|
|
90
|
+
"webpack": "^5.73.0"
|
|
91
|
+
},
|
|
92
|
+
"packageManager": "yarn@3.2.2",
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"react-hook-form": "^7.34.2"
|
|
95
|
+
},
|
|
96
|
+
"stableVersion": "1.0.0"
|
|
97
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { detach, ExtensionSlot } from "@openmrs/esm-framework";
|
|
3
|
+
import useGetPatient from "./hooks/useGetPatient";
|
|
4
|
+
|
|
5
|
+
export interface Order {
|
|
6
|
+
uuid: string;
|
|
7
|
+
dateActivated: string;
|
|
8
|
+
dose: number;
|
|
9
|
+
doseUnits: {
|
|
10
|
+
uuid: string;
|
|
11
|
+
display: string;
|
|
12
|
+
};
|
|
13
|
+
orderNumber: number;
|
|
14
|
+
display: string;
|
|
15
|
+
drug: {
|
|
16
|
+
uuid: string;
|
|
17
|
+
name: string;
|
|
18
|
+
strength: string;
|
|
19
|
+
};
|
|
20
|
+
duration: number;
|
|
21
|
+
durationUnits: {
|
|
22
|
+
uuid: string;
|
|
23
|
+
display: string;
|
|
24
|
+
};
|
|
25
|
+
frequency: {
|
|
26
|
+
uuid: string;
|
|
27
|
+
display: string;
|
|
28
|
+
};
|
|
29
|
+
numRefills: number;
|
|
30
|
+
orderer: {
|
|
31
|
+
uuid: string;
|
|
32
|
+
person: {
|
|
33
|
+
uuid: string;
|
|
34
|
+
display: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
orderType: {
|
|
38
|
+
uuid: string;
|
|
39
|
+
display: string;
|
|
40
|
+
};
|
|
41
|
+
route: {
|
|
42
|
+
uuid: string;
|
|
43
|
+
display: string;
|
|
44
|
+
};
|
|
45
|
+
auditInfo: {
|
|
46
|
+
dateVoided: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Observation {
|
|
51
|
+
uuid: string;
|
|
52
|
+
concept: {
|
|
53
|
+
uuid: string;
|
|
54
|
+
display: string;
|
|
55
|
+
conceptClass: {
|
|
56
|
+
uuid: string;
|
|
57
|
+
display: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
display: string;
|
|
61
|
+
groupMembers: null | Array<{
|
|
62
|
+
uuid: string;
|
|
63
|
+
concept: {
|
|
64
|
+
uuid: string;
|
|
65
|
+
display: string;
|
|
66
|
+
};
|
|
67
|
+
value: {
|
|
68
|
+
uuid: string;
|
|
69
|
+
display: string;
|
|
70
|
+
};
|
|
71
|
+
}>;
|
|
72
|
+
value: unknown;
|
|
73
|
+
obsDatetime: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface Encounter {
|
|
77
|
+
uuid: string;
|
|
78
|
+
encounterDatetime: string;
|
|
79
|
+
encounterProviders: Array<{
|
|
80
|
+
uuid: string;
|
|
81
|
+
display: string;
|
|
82
|
+
encounterRole: {
|
|
83
|
+
uuid: string;
|
|
84
|
+
display: string;
|
|
85
|
+
};
|
|
86
|
+
provider: {
|
|
87
|
+
uuid: string;
|
|
88
|
+
person: {
|
|
89
|
+
uuid: string;
|
|
90
|
+
display: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}>;
|
|
94
|
+
encounterType: {
|
|
95
|
+
uuid: string;
|
|
96
|
+
display: string;
|
|
97
|
+
};
|
|
98
|
+
obs: Array<Observation>;
|
|
99
|
+
orders: Array<Order>;
|
|
100
|
+
}
|
|
101
|
+
interface FormParams {
|
|
102
|
+
formUuid: string;
|
|
103
|
+
patientUuid: string;
|
|
104
|
+
visitUuid?: string;
|
|
105
|
+
visitTypeUuid?: string;
|
|
106
|
+
encounterUuid?: string;
|
|
107
|
+
showDiscardSubmitButtons?: boolean;
|
|
108
|
+
handlePostResponse?: (Encounter) => void;
|
|
109
|
+
handleEncounterCreate?: (Object) => void;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const FormBootstrap = ({
|
|
113
|
+
formUuid,
|
|
114
|
+
patientUuid,
|
|
115
|
+
visitUuid,
|
|
116
|
+
visitTypeUuid,
|
|
117
|
+
encounterUuid,
|
|
118
|
+
handlePostResponse,
|
|
119
|
+
handleEncounterCreate,
|
|
120
|
+
}: FormParams) => {
|
|
121
|
+
const patient = useGetPatient(patientUuid);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
return () => detach("form-widget-slot", "form-widget-slot");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<div>
|
|
129
|
+
{formUuid && patientUuid && patient && (
|
|
130
|
+
<ExtensionSlot
|
|
131
|
+
extensionSlotName="form-widget-slot"
|
|
132
|
+
state={{
|
|
133
|
+
view: "form",
|
|
134
|
+
formUuid,
|
|
135
|
+
visitUuid: visitUuid ?? "",
|
|
136
|
+
visitTypeUuid: visitTypeUuid ?? "",
|
|
137
|
+
patientUuid,
|
|
138
|
+
patient,
|
|
139
|
+
encounterUuid: encounterUuid ?? "",
|
|
140
|
+
closeWorkspace: () => undefined,
|
|
141
|
+
handlePostResponse,
|
|
142
|
+
handleEncounterCreate,
|
|
143
|
+
showDiscardSubmitButtons: false,
|
|
144
|
+
}}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export default FormBootstrap;
|
package/src/Root.tsx
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { BrowserRouter, Route } from "react-router-dom";
|
|
2
|
+
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
|
3
3
|
import { appPath } from "./constant";
|
|
4
|
-
|
|
4
|
+
const FormsPage = React.lazy(() => import("./forms-page"));
|
|
5
|
+
const FormEntryWorkflow = React.lazy(() => import("./form-entry-workflow"));
|
|
6
|
+
const GroupFormEntryWorkflow = React.lazy(
|
|
7
|
+
() => import("./group-form-entry-workflow")
|
|
8
|
+
);
|
|
5
9
|
|
|
6
10
|
const Root = () => {
|
|
7
11
|
return (
|
|
8
12
|
<main>
|
|
9
13
|
<BrowserRouter basename={appPath}>
|
|
10
|
-
<
|
|
14
|
+
<Routes>
|
|
15
|
+
<Route path="/" element={<FormsPage />} />
|
|
16
|
+
<Route path="/form/:formUuid" element={<FormEntryWorkflow />} />
|
|
17
|
+
<Route
|
|
18
|
+
path="/groupform/:formUuid"
|
|
19
|
+
element={<GroupFormEntryWorkflow />}
|
|
20
|
+
/>
|
|
21
|
+
</Routes>
|
|
11
22
|
</BrowserRouter>
|
|
12
23
|
</main>
|
|
13
24
|
);
|