@openmrs/esm-form-engine-lib 3.0.1 → 3.1.0-pre.1691
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/__mocks__/forms/rfe-forms/diagnosis-test-form.json +60 -0
- package/__mocks__/forms/rfe-forms/mockHistoricalvisitsEncounter.json +40 -0
- package/dist/openmrs-esm-form-engine-lib.js +1 -1
- package/package.json +1 -1
- package/src/adapters/encounter-diagnosis-adapter.test.ts +232 -0
- package/src/adapters/encounter-diagnosis-adapter.ts +116 -0
- package/src/adapters/obs-adapter.test.ts +2 -0
- package/src/adapters/program-state-adapter.test.ts +2 -0
- package/src/components/inputs/multi-select/multi-select.component.tsx +5 -6
- package/src/components/inputs/ui-select-extended/ui-select-extended.component.tsx +0 -7
- package/src/components/inputs/ui-select-extended/ui-select-extended.test.tsx +14 -5
- package/src/components/renderer/form/form-renderer.component.tsx +5 -2
- package/src/components/renderer/form/state.ts +6 -1
- package/src/components/repeat/repeat.component.tsx +4 -0
- package/src/constants.ts +1 -0
- package/src/form-engine.test.tsx +170 -3
- package/src/hooks/useConcepts.ts +10 -11
- package/src/hooks/useFormStateHelpers.ts +5 -0
- package/src/hooks/usePatientPrograms.ts +27 -31
- package/src/hooks/useRestApiMaxResults.ts +35 -0
- package/src/processors/encounter/encounter-form-processor.ts +32 -25
- package/src/processors/encounter/encounter-processor-helper.ts +45 -3
- package/src/provider/form-provider.tsx +2 -0
- package/src/registry/inbuilt-components/inbuiltFieldValueAdapters.ts +5 -0
- package/src/transformers/default-schema-transformer.ts +32 -0
- package/src/types/domain.ts +36 -0
- package/src/types/schema.ts +6 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
{
|
2
|
+
"name": "Diagnosis test",
|
3
|
+
"pages": [
|
4
|
+
{
|
5
|
+
"label": "1",
|
6
|
+
"sections": [
|
7
|
+
{
|
8
|
+
"label": "Select diagnosis",
|
9
|
+
"isExpanded": "true",
|
10
|
+
"questions": [
|
11
|
+
{
|
12
|
+
"label": "Test Diagnosis 1",
|
13
|
+
"id": "diagnosis1",
|
14
|
+
"type": "diagnosis",
|
15
|
+
"questionOptions": {
|
16
|
+
"rendering": "repeating",
|
17
|
+
"dataSource": "diagnoses",
|
18
|
+
"isSearchable": "true",
|
19
|
+
"diagnosis": {
|
20
|
+
"isConfirmed": "true",
|
21
|
+
"rank": 1,
|
22
|
+
"conceptClasses": [
|
23
|
+
"8d4918b0-c2cc-11de-8d13-0010c6dffd0f",
|
24
|
+
"8d492954-c2cc-11de-8d13-0010c6dffd0f",
|
25
|
+
"8d492b2a-c2cc-11de-8d13-0010c6dffd0f"
|
26
|
+
]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"label": "Test Diagnosis 2",
|
32
|
+
"id": "diagnosis2",
|
33
|
+
"type": "diagnosis",
|
34
|
+
"questionOptions": {
|
35
|
+
"rendering": "repeating",
|
36
|
+
"dataSource": "diagnoses",
|
37
|
+
"isSearchable": "false",
|
38
|
+
"diagnosis": {
|
39
|
+
"isConfirmed": "true",
|
40
|
+
"rank": 1,
|
41
|
+
"conceptClasses": [
|
42
|
+
"8d4918b0-c2cc-11de-8d13-0010c6dffd0f",
|
43
|
+
"8d492954-c2cc-11de-8d13-0010c6dffd0f",
|
44
|
+
"8d492b2a-c2cc-11de-8d13-0010c6dffd0f"
|
45
|
+
]
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
]
|
50
|
+
}
|
51
|
+
]
|
52
|
+
}
|
53
|
+
],
|
54
|
+
"processor": "EncounterFormProcessor",
|
55
|
+
"encounterType": "e22e39fd-7db2-45e7-80f1-60fa0d5a4378",
|
56
|
+
"referencedForms": [],
|
57
|
+
"uuid": "29ce67d1-892b-45be-84ce-8e36aa9ca37f",
|
58
|
+
"description": "re",
|
59
|
+
"version": "1.0"
|
60
|
+
}
|
@@ -85,5 +85,45 @@
|
|
85
85
|
]
|
86
86
|
}
|
87
87
|
}
|
88
|
+
],
|
89
|
+
"diagnoses": [
|
90
|
+
{
|
91
|
+
"uuid": "95690fb4-0398-42d9-9ffc-8a134e6d829d",
|
92
|
+
"diagnosis": {
|
93
|
+
"coded": {
|
94
|
+
"uuid": "stage-1-uuid",
|
95
|
+
"display": "stage 1"
|
96
|
+
}
|
97
|
+
},
|
98
|
+
"condition": null,
|
99
|
+
"encounter": "d2edc41a-5abf-48f8-bb62-ca5507dd2e4c",
|
100
|
+
"certainty": "CONFIRMED",
|
101
|
+
"rank": 1,
|
102
|
+
"voided": false,
|
103
|
+
"display": "stage 1",
|
104
|
+
"patient": "d8b38f21-db01-4ded-93bf-6a9470206461",
|
105
|
+
"formFieldNamespace": "rfe-forms",
|
106
|
+
"formFieldPath": "rfe-forms-diagnosis1",
|
107
|
+
"resourceVersion": "1.8"
|
108
|
+
},
|
109
|
+
{
|
110
|
+
"uuid": "95690fb3-0398-42d9-9ffc-8a134e6d829d",
|
111
|
+
"diagnosis": {
|
112
|
+
"coded": {
|
113
|
+
"uuid": "stage-2-uuid",
|
114
|
+
"display": "stage 2"
|
115
|
+
}
|
116
|
+
},
|
117
|
+
"condition": null,
|
118
|
+
"encounter": "d2edc41a-5abf-48f8-bb62-ca5507dd2e4c",
|
119
|
+
"certainty": "CONFIRMED",
|
120
|
+
"rank": 1,
|
121
|
+
"voided": false,
|
122
|
+
"display": "stage 2",
|
123
|
+
"patient": "d8b38f21-db01-4ded-93bf-6a9470206461",
|
124
|
+
"formFieldNamespace": "rfe-forms",
|
125
|
+
"formFieldPath": "rfe-forms-diagnosis2",
|
126
|
+
"resourceVersion": "1.8"
|
127
|
+
}
|
88
128
|
]
|
89
129
|
}
|
@@ -1 +1 @@
|
|
1
|
-
var _openmrs_esm_form_engine_lib;(()=>{"use strict";var e,r,t,n,o,i,a,l,s,u,f,p,d,c,h,m,v,g,b,y,w,_={8008:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(
|
1
|
+
var _openmrs_esm_form_engine_lib;(()=>{"use strict";var e,r,t,n,o,i,a,l,s,u,f,p,d,c,h,m,v,g,b,y,w,_={8008:(e,r,t)=>{var n={"./start":()=>Promise.all([t.e(277),t.e(260),t.e(72),t.e(465),t.e(299),t.e(524)]).then((()=>()=>t(524)))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),i=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>i})}},P={};function S(e){var r=P[e];if(void 0!==r)return r.exports;var t=P[e]={id:e,loaded:!1,exports:{}};return _[e].call(t.exports,t,t.exports,S),t.loaded=!0,t.exports}S.m=_,S.c=P,S.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return S.d(r,{a:r}),r},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,S.t=function(t,n){if(1&n&&(t=this(t)),8&n)return t;if("object"==typeof t&&t){if(4&n&&t.__esModule)return t;if(16&n&&"function"==typeof t.then)return t}var o=Object.create(null);S.r(o);var i={};e=e||[null,r({}),r([]),r(r)];for(var a=2&n&&t;"object"==typeof a&&!~e.indexOf(a);a=r(a))Object.getOwnPropertyNames(a).forEach((e=>i[e]=()=>t[e]));return i.default=()=>t,S.d(o,i),o},S.d=(e,r)=>{for(var t in r)S.o(r,t)&&!S.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},S.f={},S.e=e=>Promise.all(Object.keys(S.f).reduce(((r,t)=>(S.f[t](e,r),r)),[])),S.u=e=>e+".js",S.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),S.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),t={},n="@openmrs/esm-form-engine-lib:",S.l=(e,r,o,i)=>{if(t[e])t[e].push(r);else{var a,l;if(void 0!==o)for(var s=document.getElementsByTagName("script"),u=0;u<s.length;u++){var f=s[u];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==n+o){a=f;break}}a||(l=!0,(a=document.createElement("script")).charset="utf-8",a.timeout=120,S.nc&&a.setAttribute("nonce",S.nc),a.setAttribute("data-webpack",n+o),a.src=e),t[e]=[r];var p=(r,n)=>{a.onerror=a.onload=null,clearTimeout(d);var o=t[e];if(delete t[e],a.parentNode&&a.parentNode.removeChild(a),o&&o.forEach((e=>e(n))),r)return r(n)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=p.bind(null,a.onerror),a.onload=p.bind(null,a.onload),l&&document.head.appendChild(a)}},S.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},S.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{S.S={};var e={},r={};S.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];S.o(S.S,t)||(S.S[t]={});var i=S.S[t],a="@openmrs/esm-form-engine-lib",l=(e,r,t,n)=>{var o=i[e]=i[e]||{},l=o[r];(!l||!l.loaded&&(!n!=!l.eager?n:a>l.from))&&(o[r]={get:t,from:a,eager:!!n})},s=[];return"default"===t&&(l("@openmrs/esm-framework","6.0.3-pre.2587",(()=>Promise.all([S.e(151),S.e(72),S.e(766)]).then((()=>()=>S(5151))))),l("@openmrs/esm-patient-common-lib","9.0.1-pre.6367",(()=>Promise.all([S.e(727),S.e(277),S.e(72),S.e(465),S.e(299),S.e(499)]).then((()=>()=>S(7727))))),l("dayjs","1.11.13",(()=>S.e(353).then((()=>()=>S(4353))))),l("i18next","23.16.0",(()=>S.e(635).then((()=>()=>S(2635))))),l("react-i18next","11.18.6",(()=>Promise.all([S.e(979),S.e(72)]).then((()=>()=>S(2979))))),l("react","18.3.1",(()=>S.e(540).then((()=>()=>S(6540))))),l("swr/_internal","2.2.5",(()=>Promise.all([S.e(993),S.e(72)]).then((()=>()=>S(4993))))),l("swr/immutable","2.2.5",(()=>Promise.all([S.e(72),S.e(465),S.e(225)]).then((()=>()=>S(4225))))),l("swr/infinite","2.2.5",(()=>Promise.all([S.e(72),S.e(465),S.e(41)]).then((()=>()=>S(3041)))))),e[t]=s.length?Promise.all(s).then((()=>e[t]=1)):1}}})(),(()=>{var e;S.g.importScripts&&(e=S.g.location+"");var r=S.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),S.p=e})(),o=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},i=(e,r)=>{e=o(e),r=o(r);for(var t=0;;){if(t>=e.length)return t<r.length&&"u"!=(typeof r[t])[0];var n=e[t],i=(typeof n)[0];if(t>=r.length)return"u"==i;var a=r[t],l=(typeof a)[0];if(i!=l)return"o"==i&&"n"==l||"s"==l||"u"==i;if("o"!=i&&"u"!=i&&n!=a)return n<a;t++}},a=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,o=1;o<e.length;o++)n--,t+="u"==(typeof(l=e[o]))[0]?"-":(n>0?".":"")+(n=2,l);return t}var i=[];for(o=1;o<e.length;o++){var l=e[o];i.push(0===l?"not("+s()+")":1===l?"("+s()+" || "+s()+")":2===l?i.pop()+" "+i.pop():a(l))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},l=(e,r)=>{if(0 in e){r=o(r);var t=e[0],n=t<0;n&&(t=-t-1);for(var i=0,a=1,s=!0;;a++,i++){var u,f,p=a<e.length?(typeof e[a])[0]:"";if(i>=r.length||"o"==(f=(typeof(u=r[i]))[0]))return!s||("u"==p?a>t&&!n:""==p!=n);if("u"==f){if(!s||"u"!=p)return!1}else if(s)if(p==f)if(a<=t){if(u!=e[a])return!1}else{if(n?u>e[a]:u<e[a])return!1;u!=e[a]&&(s=!1)}else if("s"!=p&&"n"!=p){if(n||a<=t)return!1;s=!1,a--}else{if(a<=t||f<p!=n)return!1;s=!1}else"s"!=p&&"n"!=p&&(s=!1,a--)}}var d=[],c=d.pop.bind(d);for(i=1;i<e.length;i++){var h=e[i];d.push(1==h?c()|c():2==h?c()&c():h?l(h,r):!c())}return!!c()},s=(e,r)=>e&&S.o(e,r),u=e=>(e.loaded=1,e.get()),f=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),p=(e,r,t)=>{var n=t?f(e[r]):e[r];return Object.keys(n).reduce(((e,r)=>!e||!n[e].loaded&&i(e,r)?r:e),0)},d=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+a(n)+")",c=e=>{throw new Error(e)},h=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},m=(e,r,t)=>t?t():((e,r)=>c("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(e=>function(r,t,n,o,i){var a=S.I(r);return a&&a.then&&!n?a.then(e.bind(e,r,S.S[r],t,!1,o,i)):e(r,S.S[r],t,n,o,i)})(((e,r,t,n,o,i)=>{if(!s(r,t))return m(e,t,i);var a=p(r,t,n);return l(o,a)||h(d(r,t,a,o)),u(r[t][a])})),g={},b={6072:()=>v("default","react",!1,[1,18],(()=>S.e(540).then((()=>()=>S(6540))))),6766:()=>v("default","i18next",!1,[1,23],(()=>S.e(635).then((()=>()=>S(2635))))),8465:()=>v("default","swr/_internal",!1,[1,2],(()=>S.e(993).then((()=>()=>S(4993))))),2731:()=>v("default","@openmrs/esm-patient-common-lib",!1,[1,9],(()=>S.e(727).then((()=>()=>S(7727))))),3941:()=>v("default","react-i18next",!1,[1,11],(()=>S.e(979).then((()=>()=>S(2979))))),9197:()=>v("default","@openmrs/esm-framework",!1,[1,6],(()=>Promise.all([S.e(151),S.e(766)]).then((()=>()=>S(5151))))),4209:()=>v("default","swr/immutable",!1,[1,2],(()=>S.e(606).then((()=>()=>S(4225))))),231:()=>v("default","dayjs",!1,[1,1],(()=>S.e(353).then((()=>()=>S(4353))))),6339:()=>v("default","swr/infinite",!1,[1,2],(()=>S.e(422).then((()=>()=>S(3041)))))},y={72:[6072],299:[2731,3941,9197],465:[8465],499:[4209],524:[231,4209,6339],766:[6766]},w={},S.f.consumes=(e,r)=>{S.o(y,e)&&y[e].forEach((e=>{if(S.o(g,e))return r.push(g[e]);if(!w[e]){var t=r=>{g[e]=0,S.m[e]=t=>{delete S.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete g[e],S.m[e]=t=>{throw delete S.c[e],r}};try{var o=b[e]();o.then?r.push(g[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}}))},(()=>{var e={719:0};S.f.j=(r,t)=>{var n=S.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(299|465|72|766)$/.test(r))e[r]=0;else{var o=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=o);var i=S.p+S.u(r),a=new Error;S.l(i,(t=>{if(S.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;a.message="Loading chunk "+r+" failed.\n("+o+": "+i+")",a.name="ChunkLoadError",a.type=o,a.request=i,n[1](a)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[i,a,l]=t,s=0;if(i.some((r=>0!==e[r]))){for(n in a)S.o(a,n)&&(S.m[n]=a[n]);l&&l(S)}for(r&&r(t);s<i.length;s++)o=i[s],S.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=globalThis.webpackChunk_openmrs_esm_form_engine_lib=globalThis.webpackChunk_openmrs_esm_form_engine_lib||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),S.nc=void 0;var j=S(8008);_openmrs_esm_form_engine_lib=j})();
|
package/package.json
CHANGED
@@ -0,0 +1,232 @@
|
|
1
|
+
import { type FormContextProps } from '../provider/form-provider';
|
2
|
+
import { type FormField } from '../types';
|
3
|
+
import { EncounterDiagnosisAdapter } from './encounter-diagnosis-adapter';
|
4
|
+
|
5
|
+
const formContext = {
|
6
|
+
methods: null,
|
7
|
+
workspaceLayout: 'maximized',
|
8
|
+
isSubmitting: false,
|
9
|
+
patient: {
|
10
|
+
id: '833db896-c1f0-11eb-8529-0242ac130003',
|
11
|
+
},
|
12
|
+
formJson: null,
|
13
|
+
visit: null,
|
14
|
+
sessionMode: 'enter',
|
15
|
+
sessionDate: new Date(),
|
16
|
+
location: {
|
17
|
+
uuid: '41e6e516-c1f0-11eb-8529-0242ac130003',
|
18
|
+
},
|
19
|
+
currentProvider: null,
|
20
|
+
layoutType: 'small-desktop',
|
21
|
+
domainObjectValue: {
|
22
|
+
uuid: '873455da-3ec4-453c-b565-7c1fe35426be',
|
23
|
+
obs: [],
|
24
|
+
diagnoses: [],
|
25
|
+
},
|
26
|
+
previousDomainObjectValue: null,
|
27
|
+
processor: null,
|
28
|
+
formFields: [],
|
29
|
+
formFieldAdapters: null,
|
30
|
+
formFieldValidators: null,
|
31
|
+
customDependencies: {
|
32
|
+
patientPrograms: [],
|
33
|
+
},
|
34
|
+
deletedFields: [],
|
35
|
+
getFormField: jest.fn(),
|
36
|
+
addFormField: jest.fn(),
|
37
|
+
updateFormField: jest.fn(),
|
38
|
+
removeFormField: () => {},
|
39
|
+
addInvalidField: jest.fn(),
|
40
|
+
removeInvalidField: jest.fn(),
|
41
|
+
setInvalidFields: jest.fn(),
|
42
|
+
setForm: jest.fn(),
|
43
|
+
setDeletedFields: jest.fn(),
|
44
|
+
} as FormContextProps;
|
45
|
+
|
46
|
+
const field = {
|
47
|
+
label: 'Test Diagnosis',
|
48
|
+
id: 'DiagNosIS',
|
49
|
+
type: 'diagnosis',
|
50
|
+
questionOptions: {
|
51
|
+
rendering: 'repeating',
|
52
|
+
diagnosis: {
|
53
|
+
rank: 1,
|
54
|
+
isConfirmed: false,
|
55
|
+
},
|
56
|
+
datasource: {
|
57
|
+
name: 'problem_datasource',
|
58
|
+
config: {
|
59
|
+
class: [
|
60
|
+
'8d4918b0-c2cc-11de-8d13-0010c6dffd0f',
|
61
|
+
'8d492954-c2cc-11de-8d13-0010c6dffd0f',
|
62
|
+
'8d492b2a-c2cc-11de-8d13-0010c6dffd0f',
|
63
|
+
],
|
64
|
+
},
|
65
|
+
},
|
66
|
+
},
|
67
|
+
meta: {
|
68
|
+
submission: {
|
69
|
+
newValue: null,
|
70
|
+
},
|
71
|
+
previousValue: null,
|
72
|
+
},
|
73
|
+
validators: [
|
74
|
+
{
|
75
|
+
type: 'form_field',
|
76
|
+
},
|
77
|
+
{
|
78
|
+
type: 'default_value',
|
79
|
+
},
|
80
|
+
],
|
81
|
+
isHidden: false,
|
82
|
+
isRequired: false,
|
83
|
+
isDisabled: false,
|
84
|
+
} as FormField;
|
85
|
+
|
86
|
+
const diagnoses = [
|
87
|
+
{
|
88
|
+
uuid: '8d975f9e-e9e6-452f-be7c-0e87c047f056',
|
89
|
+
diagnosis: {
|
90
|
+
coded: {
|
91
|
+
uuid: '127133AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
92
|
+
display: 'Schistosoma Mansonii Infection',
|
93
|
+
links: [],
|
94
|
+
},
|
95
|
+
},
|
96
|
+
condition: null,
|
97
|
+
encounter: {
|
98
|
+
uuid: '9a4b06bd-d655-414f-b9ce-69e940c337ce',
|
99
|
+
},
|
100
|
+
certainty: 'CONFIRMED',
|
101
|
+
rank: 1,
|
102
|
+
voided: false,
|
103
|
+
display: 'Schistosoma Mansonii Infection',
|
104
|
+
patient: {
|
105
|
+
uuid: '00affa97-0010-417c-87f5-de48362de915',
|
106
|
+
display: '1000VKV - Bett Tett',
|
107
|
+
},
|
108
|
+
formFieldNamespace: 'rfe-forms',
|
109
|
+
formFieldPath: 'rfe-forms-DiagNosIS_1',
|
110
|
+
links: [],
|
111
|
+
resourceVersion: '1.8',
|
112
|
+
},
|
113
|
+
{
|
114
|
+
uuid: 'b2d0e95b-d2f6-49d1-a477-acc7026edbd7',
|
115
|
+
diagnosis: {
|
116
|
+
coded: {
|
117
|
+
uuid: '137329AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
118
|
+
display: 'Infection due to Entamoeba Histolytica',
|
119
|
+
links: [],
|
120
|
+
},
|
121
|
+
},
|
122
|
+
condition: null,
|
123
|
+
encounter: {
|
124
|
+
uuid: '9a4b06bd-d655-414f-b9ce-69e940c337ce',
|
125
|
+
},
|
126
|
+
certainty: 'PROVISIONAL',
|
127
|
+
rank: 1,
|
128
|
+
voided: false,
|
129
|
+
display: 'Infection due to Entamoeba Histolytica',
|
130
|
+
patient: {
|
131
|
+
uuid: '00affa97-0010-417c-87f5-de48362de915',
|
132
|
+
display: '1000VKV - Bett Tett',
|
133
|
+
},
|
134
|
+
formFieldNamespace: 'rfe-forms',
|
135
|
+
formFieldPath: 'rfe-forms-DiagNosIS',
|
136
|
+
links: [],
|
137
|
+
resourceVersion: '1.8',
|
138
|
+
},
|
139
|
+
];
|
140
|
+
|
141
|
+
describe('EncounterDiagnosisAdapter', () => {
|
142
|
+
it('should should handle submission of a diagnosis field', async () => {
|
143
|
+
const value = '127133AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
144
|
+
EncounterDiagnosisAdapter.transformFieldValue(field, value, formContext);
|
145
|
+
expect(field.meta.submission.newValue).toEqual({
|
146
|
+
patient: '833db896-c1f0-11eb-8529-0242ac130003',
|
147
|
+
condition: null,
|
148
|
+
diagnosis: {
|
149
|
+
coded: '127133AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
150
|
+
},
|
151
|
+
certainty: 'PROVISIONAL',
|
152
|
+
rank: 1,
|
153
|
+
formFieldPath: 'rfe-forms-DiagNosIS',
|
154
|
+
formFieldNamespace: 'rfe-forms',
|
155
|
+
});
|
156
|
+
});
|
157
|
+
|
158
|
+
it('should get initial value for the diagnosis', async () => {
|
159
|
+
formContext.domainObjectValue.diagnoses.push(...diagnoses);
|
160
|
+
const diagnosis = await EncounterDiagnosisAdapter.getInitialValue(field, null, formContext);
|
161
|
+
expect(diagnosis).toEqual('137329AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
|
162
|
+
});
|
163
|
+
|
164
|
+
it('should return null for getPreviousValue', async () => {
|
165
|
+
const previousValue = await EncounterDiagnosisAdapter.getPreviousValue(field, null, formContext);
|
166
|
+
expect(previousValue).toBeNull();
|
167
|
+
});
|
168
|
+
|
169
|
+
it('should execute tearDown without issues', () => {
|
170
|
+
expect(() => EncounterDiagnosisAdapter.tearDown()).not.toThrow();
|
171
|
+
});
|
172
|
+
|
173
|
+
it('should edit a diagnosis value', () => {
|
174
|
+
formContext.sessionMode = 'edit';
|
175
|
+
|
176
|
+
const value = '128138AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
|
177
|
+
field.meta = {
|
178
|
+
initialValue: {
|
179
|
+
omrsObject: {
|
180
|
+
uuid: '0e20bb67-5d7f-41e0-96a1-751efc21a96f',
|
181
|
+
diagnosis: {
|
182
|
+
coded: {
|
183
|
+
uuid: '127133AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
184
|
+
display: 'Schistosoma Mansonii Infection',
|
185
|
+
},
|
186
|
+
},
|
187
|
+
},
|
188
|
+
refinedValue: null,
|
189
|
+
},
|
190
|
+
};
|
191
|
+
|
192
|
+
EncounterDiagnosisAdapter.transformFieldValue(field, value, formContext);
|
193
|
+
expect(field.meta.submission.newValue).toEqual({
|
194
|
+
patient: '833db896-c1f0-11eb-8529-0242ac130003',
|
195
|
+
condition: null,
|
196
|
+
diagnosis: {
|
197
|
+
coded: '128138AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
198
|
+
},
|
199
|
+
certainty: 'PROVISIONAL',
|
200
|
+
rank: 1,
|
201
|
+
formFieldPath: 'rfe-forms-DiagNosIS',
|
202
|
+
formFieldNamespace: 'rfe-forms',
|
203
|
+
uuid: '0e20bb67-5d7f-41e0-96a1-751efc21a96f',
|
204
|
+
});
|
205
|
+
expect(field.meta.submission.voidedValue).toBe(undefined);
|
206
|
+
});
|
207
|
+
|
208
|
+
it('should void removed diagnosis in edit mode', () => {
|
209
|
+
formContext.sessionMode = 'edit';
|
210
|
+
|
211
|
+
field.meta = {
|
212
|
+
initialValue: {
|
213
|
+
omrsObject: {
|
214
|
+
uuid: '0e20bb67-5d7f-41e0-96a1-751efc21a96f',
|
215
|
+
diagnosis: {
|
216
|
+
coded: {
|
217
|
+
uuid: '127133AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
218
|
+
display: 'Schistosoma Mansonii Infection',
|
219
|
+
},
|
220
|
+
},
|
221
|
+
},
|
222
|
+
refinedValue: null,
|
223
|
+
},
|
224
|
+
};
|
225
|
+
|
226
|
+
EncounterDiagnosisAdapter.transformFieldValue(field, null, formContext);
|
227
|
+
expect(field.meta.submission.voidedValue).toEqual({
|
228
|
+
voided: true,
|
229
|
+
uuid: '0e20bb67-5d7f-41e0-96a1-751efc21a96f',
|
230
|
+
});
|
231
|
+
});
|
232
|
+
});
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import { type OpenmrsResource } from '@openmrs/esm-framework';
|
2
|
+
import { type OpenmrsObs, type FormFieldValueAdapter, type FormProcessorContextProps } from '../types';
|
3
|
+
import { type FormContextProps } from '../provider/form-provider';
|
4
|
+
import { type OpenmrsEncounter, type FormField } from '../types';
|
5
|
+
import { gracefullySetSubmission } from '../utils/common-utils';
|
6
|
+
import { isEmpty } from '../validators/form-validator';
|
7
|
+
import { isTrue } from '../utils/boolean-utils';
|
8
|
+
|
9
|
+
export let assignedDiagnosesIds: string[] = [];
|
10
|
+
|
11
|
+
export const EncounterDiagnosisAdapter: FormFieldValueAdapter = {
|
12
|
+
transformFieldValue: function (field: FormField, value: any, context: FormContextProps) {
|
13
|
+
if (field.meta.initialValue?.omrsObject && isEmpty(value)) {
|
14
|
+
return gracefullySetSubmission(field, undefined, voidDiagnosis(field.meta.initialValue.omrsObject as OpenmrsObs));
|
15
|
+
}
|
16
|
+
if (!isEmpty(value)) {
|
17
|
+
const previousDiagnosis = field.meta.initialValue?.omrsObject as OpenmrsResource;
|
18
|
+
if (hasPreviousDiagnosisValueChanged(previousDiagnosis, value)) {
|
19
|
+
return gracefullySetSubmission(
|
20
|
+
field,
|
21
|
+
editDiagnosis(value, field, previousDiagnosis, context.patient.id),
|
22
|
+
undefined,
|
23
|
+
);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
const newValue = constructNewDiagnosis(value, field, context.patient.id);
|
27
|
+
gracefullySetSubmission(field, newValue, null);
|
28
|
+
return newValue;
|
29
|
+
},
|
30
|
+
getInitialValue: function (
|
31
|
+
field: FormField,
|
32
|
+
sourceObject: OpenmrsResource,
|
33
|
+
context: FormProcessorContextProps,
|
34
|
+
): Promise<any> {
|
35
|
+
const encounter = sourceObject ?? (context.domainObjectValue as OpenmrsEncounter);
|
36
|
+
const matchedDiagnosis = encounter.diagnoses.find(
|
37
|
+
(diagnosis) => diagnosis.formFieldPath === `rfe-forms-${field.id}`,
|
38
|
+
);
|
39
|
+
|
40
|
+
if (matchedDiagnosis) {
|
41
|
+
field.meta = {
|
42
|
+
...(field.meta || {}),
|
43
|
+
initialValue: {
|
44
|
+
omrsObject: matchedDiagnosis,
|
45
|
+
refinedValue: matchedDiagnosis.diagnosis?.coded.uuid,
|
46
|
+
},
|
47
|
+
};
|
48
|
+
if (!assignedDiagnosesIds.includes(matchedDiagnosis.diagnosis?.coded?.uuid)) {
|
49
|
+
assignedDiagnosesIds.push(matchedDiagnosis.diagnosis?.coded?.uuid);
|
50
|
+
}
|
51
|
+
return matchedDiagnosis.diagnosis?.coded.uuid;
|
52
|
+
}
|
53
|
+
return null;
|
54
|
+
},
|
55
|
+
getPreviousValue: function (
|
56
|
+
field: FormField,
|
57
|
+
sourceObject: OpenmrsResource,
|
58
|
+
context: FormProcessorContextProps,
|
59
|
+
): Promise<any> {
|
60
|
+
return null;
|
61
|
+
},
|
62
|
+
getDisplayValue: (field: FormField, value: any) => {
|
63
|
+
return field.questionOptions.answers?.find((option) => option.concept == value)?.label || value;
|
64
|
+
},
|
65
|
+
tearDown: function (): void {
|
66
|
+
assignedDiagnosesIds = [];
|
67
|
+
},
|
68
|
+
};
|
69
|
+
|
70
|
+
const constructNewDiagnosis = (value: string, field: FormField, patientUuid: string) => {
|
71
|
+
if (!value) {
|
72
|
+
return null;
|
73
|
+
}
|
74
|
+
return {
|
75
|
+
patient: patientUuid,
|
76
|
+
condition: null,
|
77
|
+
diagnosis: {
|
78
|
+
coded: value,
|
79
|
+
},
|
80
|
+
certainty: isTrue(field.questionOptions?.diagnosis?.isConfirmed) ? 'CONFIRMED' : 'PROVISIONAL',
|
81
|
+
rank: field.questionOptions.diagnosis?.rank ?? 1, // rank 1 denotes a diagnosis is primary, else secondary
|
82
|
+
formFieldPath: `rfe-forms-${field.id}`,
|
83
|
+
formFieldNamespace: 'rfe-forms',
|
84
|
+
};
|
85
|
+
};
|
86
|
+
|
87
|
+
function editDiagnosis(
|
88
|
+
newEncounterDiagnosis: string,
|
89
|
+
field: FormField,
|
90
|
+
previousDiagnosis: OpenmrsResource,
|
91
|
+
patientUuid: string,
|
92
|
+
) {
|
93
|
+
return {
|
94
|
+
patient: patientUuid,
|
95
|
+
condition: null,
|
96
|
+
diagnosis: {
|
97
|
+
coded: newEncounterDiagnosis,
|
98
|
+
},
|
99
|
+
certainty: isTrue(field.questionOptions?.diagnosis?.isConfirmed) ? 'CONFIRMED' : 'PROVISIONAL',
|
100
|
+
rank: field.questionOptions.diagnosis?.rank ?? 1, // rank 1 denotes a diagnosis is primary, else secondary
|
101
|
+
formFieldPath: `rfe-forms-${field.id}`,
|
102
|
+
formFieldNamespace: 'rfe-forms',
|
103
|
+
uuid: previousDiagnosis.uuid,
|
104
|
+
};
|
105
|
+
}
|
106
|
+
|
107
|
+
export function hasPreviousDiagnosisValueChanged(previousDiagnosis: OpenmrsResource, newValue: string) {
|
108
|
+
if (isEmpty(previousDiagnosis)) {
|
109
|
+
return false;
|
110
|
+
}
|
111
|
+
return previousDiagnosis.value !== newValue;
|
112
|
+
}
|
113
|
+
|
114
|
+
export function voidDiagnosis(diagnosis: OpenmrsResource) {
|
115
|
+
return { uuid: diagnosis.uuid, voided: true };
|
116
|
+
}
|
@@ -28,6 +28,7 @@ const formContext = {
|
|
28
28
|
formFieldAdapters: null,
|
29
29
|
formFieldValidators: null,
|
30
30
|
customDependencies: null,
|
31
|
+
deletedFields: [],
|
31
32
|
getFormField: jest.fn(),
|
32
33
|
addFormField: jest.fn(),
|
33
34
|
updateFormField: jest.fn(),
|
@@ -36,6 +37,7 @@ const formContext = {
|
|
36
37
|
removeInvalidField: jest.fn(),
|
37
38
|
setInvalidFields: jest.fn(),
|
38
39
|
setForm: jest.fn(),
|
40
|
+
setDeletedFields: jest.fn(),
|
39
41
|
} as FormContextProps;
|
40
42
|
|
41
43
|
describe('ObsAdapter - transformFieldValue', () => {
|
@@ -30,6 +30,7 @@ const formContext = {
|
|
30
30
|
customDependencies: {
|
31
31
|
patientPrograms: [],
|
32
32
|
},
|
33
|
+
deletedFields: [],
|
33
34
|
getFormField: jest.fn(),
|
34
35
|
addFormField: jest.fn(),
|
35
36
|
updateFormField: jest.fn(),
|
@@ -38,6 +39,7 @@ const formContext = {
|
|
38
39
|
removeInvalidField: jest.fn(),
|
39
40
|
setInvalidFields: jest.fn(),
|
40
41
|
setForm: jest.fn(),
|
42
|
+
setDeletedFields: jest.fn(),
|
41
43
|
} as FormContextProps;
|
42
44
|
|
43
45
|
const field = {
|
@@ -77,10 +77,6 @@ const MultiSelect: React.FC<FormFieldInputProps> = ({ field, value, errors, warn
|
|
77
77
|
return false;
|
78
78
|
}, [sessionMode, field.readonly, field.inlineRendering, layoutType, workspaceLayout]);
|
79
79
|
|
80
|
-
const label = useMemo(() => {
|
81
|
-
return field.isRequired ? <FieldLabel field={field} /> : <span>{t(field.label)}</span>;
|
82
|
-
}, [field.isRequired, field.label, t]);
|
83
|
-
|
84
80
|
return sessionMode == 'view' || sessionMode == 'embedded-view' ? (
|
85
81
|
<div className={styles.formField}>
|
86
82
|
<FieldValueView
|
@@ -104,7 +100,7 @@ const MultiSelect: React.FC<FormFieldInputProps> = ({ field, value, errors, warn
|
|
104
100
|
items={selectOptions}
|
105
101
|
initialSelectedItems={initiallySelectedQuestionItems}
|
106
102
|
label={''}
|
107
|
-
titleText={
|
103
|
+
titleText={<FieldLabel field={field} />}
|
108
104
|
itemToString={(item) => (item ? item.label : ' ')}
|
109
105
|
disabled={field.isDisabled}
|
110
106
|
invalid={errors.length > 0}
|
@@ -114,7 +110,10 @@ const MultiSelect: React.FC<FormFieldInputProps> = ({ field, value, errors, warn
|
|
114
110
|
readOnly={isTrue(field.readonly)}
|
115
111
|
/>
|
116
112
|
) : (
|
117
|
-
<CheckboxGroup
|
113
|
+
<CheckboxGroup
|
114
|
+
name={field.id}
|
115
|
+
legendText={<FieldLabel field={field} />}
|
116
|
+
readOnly={isTrue(field.readonly)}>
|
118
117
|
{field.questionOptions.answers?.map((value, index) => {
|
119
118
|
return (
|
120
119
|
<Checkbox
|
@@ -169,13 +169,6 @@ const UiSelectExtended: React.FC<FormFieldInputProps> = ({ field, errors, warnin
|
|
169
169
|
itemToString={(item) => item?.display}
|
170
170
|
selectedItem={selectedItem}
|
171
171
|
placeholder={isSearchable ? t('search', 'Search') + '...' : null}
|
172
|
-
shouldFilterItem={({ item, inputValue }) => {
|
173
|
-
if (!inputValue) {
|
174
|
-
// Carbon's initial call at component mount
|
175
|
-
return true;
|
176
|
-
}
|
177
|
-
return item.display?.toLowerCase().includes(inputValue.toLowerCase());
|
178
|
-
}}
|
179
172
|
onChange={({ selectedItem }) => {
|
180
173
|
isProcessingSelection.current = true;
|
181
174
|
setFieldValue(selectedItem?.uuid);
|
@@ -252,18 +252,27 @@ describe('UiSelectExtended', () => {
|
|
252
252
|
);
|
253
253
|
});
|
254
254
|
|
255
|
-
it('should
|
255
|
+
it('should display all items regardless of user input', async () => {
|
256
256
|
await act(async () => {
|
257
257
|
renderForm();
|
258
258
|
});
|
259
259
|
|
260
|
-
const transferLocationSelect = await findSelectInput(screen, 'Transfer Location');
|
260
|
+
const transferLocationSelect = await findSelectInput(screen, 'Transfer Location');
|
261
|
+
// Open the dropdown
|
261
262
|
await user.click(transferLocationSelect);
|
263
|
+
|
264
|
+
// Verify all items are displayed initially
|
265
|
+
expect(screen.getByText('Kololo')).toBeInTheDocument();
|
266
|
+
expect(screen.getByText('Naguru')).toBeInTheDocument();
|
267
|
+
expect(screen.getByText('Muyenga')).toBeInTheDocument();
|
268
|
+
|
269
|
+
// Type input
|
262
270
|
await user.type(transferLocationSelect, 'Nag');
|
263
|
-
|
271
|
+
|
272
|
+
// Verify all items are still displayed
|
273
|
+
expect(screen.getByText('Kololo')).toBeInTheDocument();
|
264
274
|
expect(screen.getByText('Naguru')).toBeInTheDocument();
|
265
|
-
expect(screen.
|
266
|
-
expect(screen.queryByText('Muyenga')).not.toBeInTheDocument();
|
275
|
+
expect(screen.getByText('Muyenga')).toBeInTheDocument();
|
267
276
|
});
|
268
277
|
});
|
269
278
|
|
@@ -37,7 +37,7 @@ export const FormRenderer = ({
|
|
37
37
|
formState: { isDirty },
|
38
38
|
} = methods;
|
39
39
|
|
40
|
-
const [{ formFields, invalidFields, formJson }, dispatch] = useReducer(formStateReducer, {
|
40
|
+
const [{ formFields, invalidFields, formJson, deletedFields }, dispatch] = useReducer(formStateReducer, {
|
41
41
|
...initialState,
|
42
42
|
formFields: evaluatedFields,
|
43
43
|
formJson: evaluatedFormJson,
|
@@ -52,6 +52,7 @@ export const FormRenderer = ({
|
|
52
52
|
addInvalidField,
|
53
53
|
removeInvalidField,
|
54
54
|
setForm,
|
55
|
+
setDeletedFields,
|
55
56
|
} = useFormStateHelpers(dispatch, formFields);
|
56
57
|
|
57
58
|
useEffect(() => {
|
@@ -75,6 +76,7 @@ export const FormRenderer = ({
|
|
75
76
|
formFields,
|
76
77
|
formJson,
|
77
78
|
invalidFields,
|
79
|
+
deletedFields,
|
78
80
|
addFormField,
|
79
81
|
updateFormField,
|
80
82
|
getFormField,
|
@@ -83,8 +85,9 @@ export const FormRenderer = ({
|
|
83
85
|
addInvalidField,
|
84
86
|
removeInvalidField,
|
85
87
|
setForm,
|
88
|
+
setDeletedFields,
|
86
89
|
};
|
87
|
-
}, [processorContext, workspaceLayout, methods, formFields, formJson, invalidFields]);
|
90
|
+
}, [processorContext, workspaceLayout, methods, formFields, formJson, invalidFields, deletedFields]);
|
88
91
|
|
89
92
|
useEffect(() => {
|
90
93
|
registerForm(formJson.name, isSubForm, context);
|