@openmrs/esm-form-engine-lib 3.0.1-pre.1676 → 3.0.1-pre.1681

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.
@@ -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(277),t.e(260),t.e(72),t.e(465),t.e(299),t.e(891)]).then((()=>()=>t(9891)))},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],766:[6766],891:[231,4209,6339]},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})();
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-form-engine-lib",
3
- "version": "3.0.1-pre.1676",
3
+ "version": "3.0.1-pre.1681",
4
4
  "description": "React Form Engine for O3",
5
5
  "browser": "dist/openmrs-esm-form-engine-lib.js",
6
6
  "main": "src/index.ts",
@@ -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
+ }
@@ -15,6 +15,7 @@ import { useFormFactory } from '../../provider/form-factory-provider';
15
15
  const renderingByTypeMap: Record<string, RenderType> = {
16
16
  obsGroup: 'group',
17
17
  testOrder: 'select',
18
+ diagnosis: 'ui-select-extended',
18
19
  };
19
20
 
20
21
  const Repeat: React.FC<FormFieldInputProps> = ({ field }) => {
package/src/constants.ts CHANGED
@@ -5,6 +5,7 @@ export const encounterRepresentation =
5
5
  'custom:(uuid,encounterDatetime,encounterType:(uuid,name,description),location:(uuid,name),' +
6
6
  'patient:(uuid,display),encounterProviders:(uuid,provider:(uuid,name),encounterRole:(uuid,name)),' +
7
7
  'orders:(uuid,display,concept:(uuid,display),voided),' +
8
+ 'diagnoses:(uuid,certainty,condition,formFieldPath,formFieldNamespace,display,rank,voided,diagnosis:(coded:(uuid,display))),' +
8
9
  'obs:(uuid,obsDatetime,comment,voided,groupMembers,formFieldNamespace,formFieldPath,concept:(uuid,name:(uuid,name)),value:(uuid,name:(uuid,name),' +
9
10
  'names:(uuid,conceptNameType,name))))';
10
11
  export const FormsStore = 'forms-engine-store';
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import dayjs from 'dayjs';
3
3
  import userEvent from '@testing-library/user-event';
4
- import { act, cleanup, render, screen, within } from '@testing-library/react';
4
+ import { act, cleanup, render, screen, waitFor, within } from '@testing-library/react';
5
5
  import {
6
6
  ExtensionSlot,
7
7
  OpenmrsDatePicker,
@@ -44,9 +44,11 @@ import viralLoadStatusForm from '__mocks__/forms/rfe-forms/viral-load-status-for
44
44
  import readOnlyValidationForm from '__mocks__/forms/rfe-forms/read-only-validation-form.json';
45
45
  import jsExpressionValidationForm from '__mocks__/forms/rfe-forms/js-expression-validation-form.json';
46
46
  import hidePagesAndSectionsForm from '__mocks__/forms/rfe-forms/hide-pages-and-sections-form.json';
47
+ import diagnosisForm from '__mocks__/forms/rfe-forms/diagnosis-test-form.json';
47
48
 
48
49
  import FormEngine from './form-engine.component';
49
- import { type SessionMode } from './types';
50
+ import { type FormSchema, type OpenmrsEncounter, type SessionMode } from './types';
51
+ import { useEncounter } from './hooks/useEncounter';
50
52
 
51
53
  const patientUUID = '8673ee4f-e2ab-4077-ba55-4980f408773e';
52
54
  const visit = mockVisit;
@@ -59,6 +61,7 @@ const mockExtensionSlot = jest.mocked(ExtensionSlot);
59
61
  const mockUsePatient = jest.mocked(usePatient);
60
62
  const mockUseSession = jest.mocked(useSession);
61
63
  const mockOpenmrsDatePicker = jest.mocked(OpenmrsDatePicker);
64
+ const mockUseEncounter = jest.mocked(useEncounter);
62
65
 
63
66
  mockOpenmrsDatePicker.mockImplementation(({ id, labelText, value, onChange, isInvalid, invalidText }) => {
64
67
  return (
@@ -79,6 +82,48 @@ mockOpenmrsDatePicker.mockImplementation(({ id, labelText, value, onChange, isIn
79
82
  when(mockOpenmrsFetch).calledWith(formsResourcePath).mockReturnValue({ data: demoHtsOpenmrsForm });
80
83
  when(mockOpenmrsFetch).calledWith(clobDataResourcePath).mockReturnValue({ data: demoHtsForm });
81
84
 
85
+ jest.mock('lodash-es/debounce', () => jest.fn((fn) => fn));
86
+
87
+ jest.mock('lodash-es', () => ({
88
+ ...jest.requireActual('lodash-es'),
89
+ debounce: jest.fn((fn) => fn),
90
+ }));
91
+
92
+ jest.mock('./registry/registry', () => {
93
+ const originalModule = jest.requireActual('./registry/registry');
94
+ return {
95
+ ...originalModule,
96
+ getRegisteredDataSource: jest.fn().mockResolvedValue({
97
+ fetchData: jest.fn().mockImplementation((...args) => {
98
+ if (args[1].class?.length && !args[1].referencedValue?.key) {
99
+ // concept DS
100
+ return Promise.resolve([
101
+ {
102
+ uuid: 'stage-1-uuid',
103
+ display: 'stage 1',
104
+ },
105
+ {
106
+ uuid: 'stage-2-uuid',
107
+ display: 'stage 2',
108
+ },
109
+ {
110
+ uuid: 'stage-3-uuid',
111
+ display: 'stage 3',
112
+ },
113
+ ]);
114
+ }
115
+ }),
116
+ fetchSingleItem: jest.fn().mockImplementation((uuid: string) => {
117
+ return Promise.resolve({
118
+ uuid,
119
+ display: 'stage 1',
120
+ });
121
+ }),
122
+ toUuidAndDisplay: (data) => data,
123
+ }),
124
+ };
125
+ });
126
+
82
127
  jest.mock('../src/api', () => {
83
128
  const originalModule = jest.requireActual('../src/api');
84
129
 
@@ -117,6 +162,16 @@ jest.mock('./hooks/useConcepts', () => ({
117
162
  }),
118
163
  }));
119
164
 
165
+ jest.mock('./hooks/useEncounter', () => ({
166
+ useEncounter: jest.fn().mockImplementation((formJson: FormSchema) => {
167
+ return {
168
+ encounter: formJson.encounter ? (mockHxpEncounter as OpenmrsEncounter) : null,
169
+ isLoading: false,
170
+ error: undefined,
171
+ };
172
+ }),
173
+ }));
174
+
120
175
  describe('Form engine component', () => {
121
176
  const user = userEvent.setup();
122
177
 
@@ -1047,7 +1102,118 @@ describe('Form engine component', () => {
1047
1102
  });
1048
1103
  });
1049
1104
 
1050
- function renderForm(formUUID, formJson, intent?: string, mode?: SessionMode) {
1105
+ describe('Encounter diagnosis', () => {
1106
+ it('should test addition of a diagnosis', async () => {
1107
+ await act(async () => {
1108
+ renderForm(null, diagnosisForm);
1109
+ });
1110
+
1111
+ const testDiagnosis1AddButton = screen.getAllByRole('button', { name: 'Add' })[0];
1112
+ await user.click(testDiagnosis1AddButton);
1113
+
1114
+ await waitFor(() => {
1115
+ expect(screen.getAllByRole('combobox', { name: /^test diagnosis 1$/i }).length).toEqual(2);
1116
+ });
1117
+
1118
+ expect(screen.getByRole('button', { name: /Remove/i })).toBeInTheDocument();
1119
+ });
1120
+
1121
+ it('should render all diagnosis fields', async () => {
1122
+ await act(async () => {
1123
+ renderForm(null, diagnosisForm);
1124
+ });
1125
+ const diagnosisFields = screen.getAllByRole('combobox', { name: /test diagnosis 1|test diagnosis 2/i });
1126
+ expect(diagnosisFields.length).toBe(2);
1127
+ });
1128
+
1129
+ it('should be possible to delete cloned fields', async () => {
1130
+ await act(async () => {
1131
+ renderForm(null, diagnosisForm);
1132
+ });
1133
+
1134
+ const testDiagnosis1AddButton = screen.getAllByRole('button', { name: 'Add' })[0];
1135
+ await user.click(testDiagnosis1AddButton);
1136
+
1137
+ await waitFor(() => {
1138
+ expect(screen.getAllByRole('combobox', { name: /^test diagnosis 1$/i }).length).toEqual(2);
1139
+ });
1140
+ const removeButton = screen.getByRole('button', { name: /Remove/i });
1141
+
1142
+ await user.click(removeButton);
1143
+
1144
+ expect(removeButton).not.toBeInTheDocument();
1145
+ });
1146
+
1147
+ it('should save diagnosis field on form submission', async () => {
1148
+ await act(async () => {
1149
+ renderForm(null, diagnosisForm);
1150
+ });
1151
+
1152
+ const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
1153
+ const combobox = await findSelectInput(screen, 'Test Diagnosis 1');
1154
+ expect(combobox).toHaveAttribute('placeholder', 'Search...');
1155
+
1156
+ await user.click(combobox);
1157
+ await user.type(combobox, 'stage');
1158
+
1159
+ expect(screen.getByText(/stage 1/)).toBeInTheDocument();
1160
+ expect(screen.getByText(/stage 2/)).toBeInTheDocument();
1161
+ expect(screen.getByText(/stage 3/)).toBeInTheDocument();
1162
+
1163
+ await user.click(screen.getByText('stage 1'));
1164
+ await user.click(screen.getByRole('button', { name: /save/i }));
1165
+ expect(saveEncounterMock).toHaveBeenCalledTimes(1);
1166
+ const [_, encounter] = saveEncounterMock.mock.calls[0];
1167
+ expect(encounter.diagnoses.length).toBe(1);
1168
+ expect(encounter.diagnoses[0]).toEqual({
1169
+ patient: '8673ee4f-e2ab-4077-ba55-4980f408773e',
1170
+ condition: null,
1171
+ diagnosis: {
1172
+ coded: 'stage-1-uuid',
1173
+ },
1174
+ certainty: 'CONFIRMED',
1175
+ rank: 1,
1176
+ formFieldPath: `rfe-forms-diagnosis1`,
1177
+ formFieldNamespace: 'rfe-forms',
1178
+ });
1179
+ });
1180
+
1181
+ it('should edit diagnosis field on form submission', async () => {
1182
+ await act(async () => {
1183
+ renderForm(null, diagnosisForm, null, 'edit', mockHxpEncounter.uuid);
1184
+ });
1185
+ mockUseEncounter.mockImplementation(() => ({ encounter: mockHxpEncounter, error: null, isLoading: false }));
1186
+ const saveEncounterMock = jest.spyOn(api, 'saveEncounter');
1187
+
1188
+ const field1 = await findSelectInput(screen, 'Test Diagnosis 1');
1189
+ expect(field1).toHaveValue('stage 1');
1190
+
1191
+ await user.click(field1);
1192
+ await user.type(field1, 'stage');
1193
+ expect(screen.getByText(/stage 1/)).toBeInTheDocument();
1194
+ expect(screen.getByText(/stage 2/)).toBeInTheDocument();
1195
+ expect(screen.getByText(/stage 3/)).toBeInTheDocument();
1196
+ await user.click(screen.getByText(/stage 3/));
1197
+ await user.click(screen.getByRole('button', { name: /save/i }));
1198
+ expect(saveEncounterMock).toHaveBeenCalledTimes(1);
1199
+ const [_, encounter] = saveEncounterMock.mock.calls[0];
1200
+ expect(encounter.diagnoses.length).toBe(1);
1201
+ expect(encounter.diagnoses[0]).toEqual({
1202
+ patient: '8673ee4f-e2ab-4077-ba55-4980f408773e',
1203
+ condition: null,
1204
+ diagnosis: {
1205
+ coded: 'stage-3-uuid',
1206
+ },
1207
+ certainty: 'CONFIRMED',
1208
+ rank: 1,
1209
+ formFieldPath: `rfe-forms-diagnosis1`,
1210
+ formFieldNamespace: 'rfe-forms',
1211
+ uuid: '95690fb4-0398-42d9-9ffc-8a134e6d829d',
1212
+ });
1213
+ });
1214
+ });
1215
+
1216
+ function renderForm(formUUID, formJson, intent?: string, mode?: SessionMode, encounterUUID?: string) {
1051
1217
  render(
1052
1218
  <FormEngine
1053
1219
  formJson={formJson}
@@ -1055,6 +1221,7 @@ describe('Form engine component', () => {
1055
1221
  patientUUID={patientUUID}
1056
1222
  formSessionIntent={intent}
1057
1223
  visit={visit}
1224
+ encounterUUID={encounterUUID}
1058
1225
  mode={mode ? mode : 'enter'}
1059
1226
  />,
1060
1227
  );
@@ -162,11 +162,21 @@ export class EncounterFormProcessor extends FormProcessor {
162
162
  // save encounter
163
163
  try {
164
164
  const { data: savedEncounter } = await saveEncounter(abortController, encounter, encounter.uuid);
165
- const saveOrders = savedEncounter.orders.map((order) => order.orderNumber);
166
- if (saveOrders.length) {
165
+ const savedOrders = savedEncounter.orders.map((order) => order.orderNumber);
166
+ const savedDiagnoses = savedEncounter.diagnoses.map((diagnosis) => diagnosis.display);
167
+ if (savedOrders.length) {
167
168
  showSnackbar({
168
169
  title: translateFn('ordersSaved', 'Order(s) saved successfully'),
169
- subtitle: saveOrders.join(', '),
170
+ subtitle: savedOrders.join(', '),
171
+ kind: 'success',
172
+ isLowContrast: true,
173
+ });
174
+ }
175
+ // handle diagnoses
176
+ if (savedDiagnoses.length) {
177
+ showSnackbar({
178
+ title: translateFn('diagnosisSaved', 'Diagnosis(es) saved successfully'),
179
+ subtitle: savedDiagnoses.join(', '),
170
180
  kind: 'success',
171
181
  isLowContrast: true,
172
182
  });
@@ -17,6 +17,7 @@ import { DefaultValueValidator } from '../../validators/default-value-validator'
17
17
  import { cloneRepeatField } from '../../components/repeat/helpers';
18
18
  import { assignedOrderIds } from '../../adapters/orders-adapter';
19
19
  import { type OpenmrsResource } from '@openmrs/esm-framework';
20
+ import { assignedDiagnosesIds } from '../../adapters/encounter-diagnosis-adapter';
20
21
 
21
22
  export function prepareEncounter(
22
23
  context: FormContextProps,
@@ -30,6 +31,8 @@ export function prepareEncounter(
30
31
  const obsForSubmission = [];
31
32
  prepareObs(obsForSubmission, allFormFields);
32
33
  const ordersForSubmission = prepareOrders(allFormFields);
34
+ const diagnosesForSubmission = prepareDiagnosis(allFormFields);
35
+
33
36
  let encounterForSubmission: OpenmrsEncounter = {};
34
37
 
35
38
  if (encounter) {
@@ -59,6 +62,7 @@ export function prepareEncounter(
59
62
  }
60
63
  encounterForSubmission.obs = obsForSubmission;
61
64
  encounterForSubmission.orders = ordersForSubmission;
65
+ encounterForSubmission.diagnoses = diagnosesForSubmission;
62
66
  } else {
63
67
  encounterForSubmission = {
64
68
  patient: patient.id,
@@ -77,6 +81,7 @@ export function prepareEncounter(
77
81
  },
78
82
  visit: visit?.uuid,
79
83
  orders: ordersForSubmission,
84
+ diagnoses: diagnosesForSubmission,
80
85
  };
81
86
  }
82
87
  return encounterForSubmission;
@@ -314,6 +319,33 @@ export async function hydrateRepeatField(
314
319
  }),
315
320
  );
316
321
  }
322
+
323
+ const unMappedDiagnoses = encounter.diagnoses.filter((diagnosis) => {
324
+ return (
325
+ !diagnosis.voided &&
326
+ !assignedDiagnosesIds.includes(diagnosis?.diagnosis?.coded.uuid) &&
327
+ diagnosis.formFieldPath.startsWith(`rfe-forms-${field.id}_`)
328
+ );
329
+ });
330
+
331
+ if (field.type === 'diagnosis') {
332
+ return Promise.all(
333
+ unMappedDiagnoses.map(async (diagnosis) => {
334
+ const idSuffix = parseInt(diagnosis.formFieldPath.split('_')[1]);
335
+ const clone = cloneRepeatField(field, diagnosis, idSuffix);
336
+ initialValues[clone.id] = await formFieldAdapters[field.type].getInitialValue(
337
+ clone,
338
+ { diagnoses: [diagnosis] } as any,
339
+ context,
340
+ );
341
+ if (!assignedDiagnosesIds.includes(diagnosis.diagnosis.coded.uuid)) {
342
+ assignedDiagnosesIds.push(diagnosis.diagnosis.coded.uuid);
343
+ }
344
+
345
+ return clone;
346
+ }),
347
+ );
348
+ }
317
349
  // handle obs groups
318
350
  return Promise.all(
319
351
  unMappedGroups.map(async (group) => {
@@ -332,3 +364,12 @@ export async function hydrateRepeatField(
332
364
  }),
333
365
  ).then((results) => results.flat());
334
366
  }
367
+
368
+ function prepareDiagnosis(fields: FormField[]) {
369
+ const diagnoses = fields
370
+ .filter((field) => field.type === 'diagnosis' && hasSubmission(field))
371
+ .map((field) => field.meta.submission.newValue || field.meta.submission.voidedValue)
372
+ .filter((o) => o);
373
+
374
+ return diagnoses;
375
+ }
@@ -10,6 +10,7 @@ import { ObsCommentAdapter } from '../../adapters/obs-comment-adapter';
10
10
  import { OrdersAdapter } from '../../adapters/orders-adapter';
11
11
  import { PatientIdentifierAdapter } from '../../adapters/patient-identifier-adapter';
12
12
  import { ProgramStateAdapter } from '../../adapters/program-state-adapter';
13
+ import { EncounterDiagnosisAdapter } from '../../adapters/encounter-diagnosis-adapter';
13
14
  import { type FormFieldValueAdapter } from '../../types';
14
15
 
15
16
  export const inbuiltFieldValueAdapters: RegistryItem<FormFieldValueAdapter>[] = [
@@ -61,4 +62,8 @@ export const inbuiltFieldValueAdapters: RegistryItem<FormFieldValueAdapter>[] =
61
62
  type: 'patientIdentifier',
62
63
  component: PatientIdentifierAdapter,
63
64
  },
65
+ {
66
+ type: 'diagnosis',
67
+ component: EncounterDiagnosisAdapter,
68
+ },
64
69
  ];
@@ -148,6 +148,9 @@ function transformByType(question: FormField) {
148
148
  ? 'date'
149
149
  : question.questionOptions.rendering;
150
150
  break;
151
+ case 'diagnosis':
152
+ handleDiagnosis(question);
153
+ break;
151
154
  }
152
155
  }
153
156
 
@@ -276,3 +279,32 @@ function handleQuestionsWithObsComments(sectionQuestions: Array<FormField>): Arr
276
279
 
277
280
  return augmentedQuestions;
278
281
  }
282
+
283
+ function handleDiagnosis(question: FormField) {
284
+ if (
285
+ ('dataSource' in question.questionOptions && question.questionOptions['dataSource'] === 'diagnoses') ||
286
+ question.type === 'diagnosis'
287
+ ) {
288
+ question.questionOptions.datasource = {
289
+ name: 'problem_datasource',
290
+ config: {
291
+ class: question.questionOptions.diagnosis?.conceptClasses,
292
+ },
293
+ };
294
+ if (question.questionOptions.diagnosis?.conceptSet) {
295
+ question.questionOptions = {
296
+ ...question.questionOptions,
297
+ concept: question.questionOptions.diagnosis?.conceptSet,
298
+ datasource: {
299
+ name: 'problem_datasource',
300
+ config: {
301
+ useSetMembersByConcept: true,
302
+ },
303
+ },
304
+ };
305
+ }
306
+ question.questionOptions.isSearchable = true;
307
+
308
+ delete question.questionOptions['dataSource'];
309
+ }
310
+ }
@@ -12,6 +12,7 @@ export interface OpenmrsEncounter {
12
12
  visit?: OpenmrsResource | string;
13
13
  encounterProviders?: Array<Record<string, any>>;
14
14
  form?: OpenmrsFormResource;
15
+ diagnoses?: Array<Diagnosis>;
15
16
  }
16
17
 
17
18
  export interface OpenmrsObs extends OpenmrsResource {
@@ -191,3 +192,34 @@ export interface PatientIdentifier {
191
192
  location?: string;
192
193
  preferred?: boolean;
193
194
  }
195
+
196
+ export interface DiagnosisPayload {
197
+ patient: string;
198
+ condition: null;
199
+ diagnosis: {
200
+ coded: string;
201
+ };
202
+ certainty: string;
203
+ rank: number;
204
+ formFieldNamespace?: string;
205
+ formFieldPath?: string;
206
+ uuid?: string;
207
+ encounter?: string;
208
+ }
209
+
210
+ export interface Diagnosis {
211
+ encounter: string;
212
+ patient: string;
213
+ diagnosis: {
214
+ coded: {
215
+ uuid: string;
216
+ };
217
+ };
218
+ certainty: string;
219
+ rank: number;
220
+ display: string;
221
+ voided: boolean;
222
+ uuid: string;
223
+ formFieldNamespace?: string;
224
+ formFieldPath?: string;
225
+ }
@@ -192,6 +192,12 @@ export interface FormQuestionOptions {
192
192
  comment?: string;
193
193
  orientation?: 'vertical' | 'horizontal';
194
194
  shownCommentOptions?: { validators?: Array<Record<string, any>>; hide?: { hideWhenExpression: string } };
195
+ diagnosis?: {
196
+ rank?: number;
197
+ isConfirmed?: boolean;
198
+ conceptClasses?: Array<string>;
199
+ conceptSet?: string;
200
+ };
195
201
  }
196
202
 
197
203
  export interface QuestionAnswerOption {