@epcare/esm-report-builder 0.1.1-pre.15

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.
Files changed (586) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc.js +19 -0
  3. package/.github/workflows/main.yml +162 -0
  4. package/.prettierrc +8 -0
  5. package/LICENSE +401 -0
  6. package/README.md +317 -0
  7. package/dist/0081d5d3d536cb23.js +1 -0
  8. package/dist/02acc4469a2fe2e4.woff2 +0 -0
  9. package/dist/081587ca0db8e63f.woff2 +0 -0
  10. package/dist/08cf53c4e5e71cf1.woff2 +0 -0
  11. package/dist/090b2bc014d24ea4.woff2 +0 -0
  12. package/dist/09de5db63ef7b579.js +1 -0
  13. package/dist/0ae92bcea615e948.woff2 +0 -0
  14. package/dist/0be8520d8945b3b7.woff2 +0 -0
  15. package/dist/0e7dd073cd8bb0ad.woff2 +0 -0
  16. package/dist/0edb77cd19e43550.js +1 -0
  17. package/dist/14869ac5d1830304.woff2 +0 -0
  18. package/dist/14aaceff85fc8b28.woff2 +0 -0
  19. package/dist/14c3abea79fc1389.js +1 -0
  20. package/dist/155a4ac079785bfd.js +1 -0
  21. package/dist/155a4ac079785bfd.js.map +1 -0
  22. package/dist/16f443eed01776ca.woff2 +0 -0
  23. package/dist/183bae0e53a22182.woff2 +0 -0
  24. package/dist/19c8f94ccd6289f5.woff2 +0 -0
  25. package/dist/1ae86565eab7451c.woff2 +0 -0
  26. package/dist/1c7bf8797e0a9be6.woff2 +0 -0
  27. package/dist/1f266d3619b30f16.woff2 +0 -0
  28. package/dist/1f8c5a4087a524fd.woff2 +0 -0
  29. package/dist/20ba2b23c5c0cd0b.woff2 +0 -0
  30. package/dist/22a32bd51591301b.js +1 -0
  31. package/dist/273c72d90e432a3d.js +1 -0
  32. package/dist/295dd01a1fbfee6d.woff2 +0 -0
  33. package/dist/29cbe6827c3f03ef.js +1 -0
  34. package/dist/2f686985e26e7107.woff2 +0 -0
  35. package/dist/315eff729e4ccbd9.woff2 +0 -0
  36. package/dist/368d16e3259bf207.woff2 +0 -0
  37. package/dist/36c49aa341a7079a.woff2 +0 -0
  38. package/dist/36e1e0430475edee.woff2 +0 -0
  39. package/dist/374c3ee36d9e040a.js +1 -0
  40. package/dist/377971e519bf3f4a.js +2 -0
  41. package/dist/377971e519bf3f4a.js.LICENSE.txt +39 -0
  42. package/dist/377971e519bf3f4a.js.map +1 -0
  43. package/dist/3b0ea8395009dcf3.js +2 -0
  44. package/dist/3b0ea8395009dcf3.js.LICENSE.txt +9 -0
  45. package/dist/3b0ea8395009dcf3.js.map +1 -0
  46. package/dist/3bc19662b8630ee9.woff2 +0 -0
  47. package/dist/3f645f473b3f8fba.woff2 +0 -0
  48. package/dist/41320d8930d23b36.js +1 -0
  49. package/dist/4218ac9901b9d36d.woff2 +0 -0
  50. package/dist/4659f3ca46d928b5.js +1 -0
  51. package/dist/4659f3ca46d928b5.js.map +1 -0
  52. package/dist/4680ba68412e4da9.woff2 +0 -0
  53. package/dist/48e37bd7ebf85a1f.woff2 +0 -0
  54. package/dist/4aabceefe5a2494a.js +1 -0
  55. package/dist/4c188cbaefba58cd.js +1 -0
  56. package/dist/4e11b8a7c445255f.woff2 +0 -0
  57. package/dist/537ddd61c5c1fce2.woff2 +0 -0
  58. package/dist/54f5eee3a7989556.js +1 -0
  59. package/dist/55c9107b50dd747c.js +1 -0
  60. package/dist/56c4118c0907f151.woff2 +0 -0
  61. package/dist/5938bc2ae7ec60c0.woff2 +0 -0
  62. package/dist/5c6586155f0d278a.woff2 +0 -0
  63. package/dist/5e50c92017029ca3.js +1 -0
  64. package/dist/5e50c92017029ca3.js.map +1 -0
  65. package/dist/600aca7295d8bcb7.js +2 -0
  66. package/dist/600aca7295d8bcb7.js.LICENSE.txt +9 -0
  67. package/dist/600aca7295d8bcb7.js.map +1 -0
  68. package/dist/60ec587649ba812a.woff2 +0 -0
  69. package/dist/64cf08a5ac3266d8.js +1 -0
  70. package/dist/652f476a8a1603d3.js +2 -0
  71. package/dist/652f476a8a1603d3.js.LICENSE.txt +9 -0
  72. package/dist/652f476a8a1603d3.js.map +1 -0
  73. package/dist/65e6511e035870e1.woff2 +0 -0
  74. package/dist/661425f6798cd16a.woff2 +0 -0
  75. package/dist/66b864fe213caf46.woff2 +0 -0
  76. package/dist/680eb791e6266590.js +2 -0
  77. package/dist/680eb791e6266590.js.LICENSE.txt +19 -0
  78. package/dist/680eb791e6266590.js.map +1 -0
  79. package/dist/69d087d970ee9455.woff2 +0 -0
  80. package/dist/69e3aa4276b4cb4b.js +1 -0
  81. package/dist/6a88f03fc4e7c3da.js +1 -0
  82. package/dist/6c6c45e66ff54281.woff2 +0 -0
  83. package/dist/6d9009857c6df878.js +1 -0
  84. package/dist/6ebe7cea59ed2853.js +1 -0
  85. package/dist/6f3181849e740935.js +1 -0
  86. package/dist/6f3181849e740935.js.map +1 -0
  87. package/dist/7073a7323e92bd11.woff2 +0 -0
  88. package/dist/70ac433ae2a89a89.js +1 -0
  89. package/dist/70ee4ee625ac0ec1.js +1 -0
  90. package/dist/718c6cc31274ab1a.woff2 +0 -0
  91. package/dist/727696c3934d0966.js +1 -0
  92. package/dist/727763c0f0df59dc.js +1 -0
  93. package/dist/727763c0f0df59dc.js.map +1 -0
  94. package/dist/72cdbedfe04be9f9.woff2 +0 -0
  95. package/dist/7509c9f56fe9e532.woff2 +0 -0
  96. package/dist/75dc5c5b04adc8bf.woff2 +0 -0
  97. package/dist/77b48bc05299ecca.woff2 +0 -0
  98. package/dist/7a0a0215c248c73d.woff2 +0 -0
  99. package/dist/7c0d0c5180de8729.js +1 -0
  100. package/dist/7f00bebb24e40167.woff2 +0 -0
  101. package/dist/802c6176541eeed7.woff2 +0 -0
  102. package/dist/8080081b3379c637.woff2 +0 -0
  103. package/dist/81cfdaeaa0bbca1f.js +1 -0
  104. package/dist/8605507b7a8487c4.woff2 +0 -0
  105. package/dist/893a160d06428365.js +1 -0
  106. package/dist/893a160d06428365.js.map +1 -0
  107. package/dist/8a83d654702f6534.woff2 +0 -0
  108. package/dist/8fe71173a13fe571.woff2 +0 -0
  109. package/dist/94aa912dcac90114.js +1 -0
  110. package/dist/9624cec0f9bdd81e.woff2 +0 -0
  111. package/dist/98a3af55a1698171.woff2 +0 -0
  112. package/dist/99823aaebba56f46.js +1 -0
  113. package/dist/9ba85996af74c5ce.woff2 +0 -0
  114. package/dist/9ddb22faa35006e7.woff2 +0 -0
  115. package/dist/a167fb2799dd741b.woff2 +0 -0
  116. package/dist/a2045a5cc4fdf94f.woff2 +0 -0
  117. package/dist/a246c73905a31c93.woff2 +0 -0
  118. package/dist/a325099b0a580ce2.js +2 -0
  119. package/dist/a325099b0a580ce2.js.LICENSE.txt +14 -0
  120. package/dist/a325099b0a580ce2.js.map +1 -0
  121. package/dist/a401aa7939cb6e6f.woff2 +0 -0
  122. package/dist/a40fef67997d3b2c.js +1 -0
  123. package/dist/a62897b000a24b86.js +1 -0
  124. package/dist/a6ed036f17a1ea29.woff2 +0 -0
  125. package/dist/a77bac4877483a0a.js +1 -0
  126. package/dist/a9f25ca430709a1a.woff2 +0 -0
  127. package/dist/aa0dfbdd569b1c24.js +2 -0
  128. package/dist/aa0dfbdd569b1c24.js.LICENSE.txt +5 -0
  129. package/dist/aa0dfbdd569b1c24.js.map +1 -0
  130. package/dist/ab0f637d6cff12e4.js +1 -0
  131. package/dist/afa9121a49e95351.woff2 +0 -0
  132. package/dist/afcda12d9f805543.woff2 +0 -0
  133. package/dist/b09ded85a7da77f1.woff2 +0 -0
  134. package/dist/b10dbe5318a91a12.js +1 -0
  135. package/dist/b2f4e9d1e821b71c.woff2 +0 -0
  136. package/dist/b4a074bf828bb757.woff2 +0 -0
  137. package/dist/b7f447da43f6e596.woff2 +0 -0
  138. package/dist/bcca84a524572d10.woff2 +0 -0
  139. package/dist/be093e052a6d50eb.js +1 -0
  140. package/dist/be4d1f97b11d087c.woff2 +0 -0
  141. package/dist/bec14780d81164de.woff2 +0 -0
  142. package/dist/c31657fe213c1b5e.js +1 -0
  143. package/dist/c49ef726d3f0420b.js +1 -0
  144. package/dist/c553f7e0199c5084.woff2 +0 -0
  145. package/dist/c94ac2fdc1ff1418.js +1 -0
  146. package/dist/c9d9ce9f465df4fe.woff2 +0 -0
  147. package/dist/cbbb57b397433964.js +2 -0
  148. package/dist/cbbb57b397433964.js.LICENSE.txt +14 -0
  149. package/dist/cbbb57b397433964.js.map +1 -0
  150. package/dist/d188f7f036ac5779.woff2 +0 -0
  151. package/dist/d1aa59bd9c702dc4.js +2 -0
  152. package/dist/d1aa59bd9c702dc4.js.LICENSE.txt +32 -0
  153. package/dist/d1aa59bd9c702dc4.js.map +1 -0
  154. package/dist/d265d81c58525ae4.woff2 +0 -0
  155. package/dist/d5942cd81663e136.woff2 +0 -0
  156. package/dist/d66b8ff73d95cabb.woff2 +0 -0
  157. package/dist/d84bac6d07672dd2.js +1 -0
  158. package/dist/d84bac6d07672dd2.js.map +1 -0
  159. package/dist/d88899ef0fd16719.woff2 +0 -0
  160. package/dist/d92b5ecf31fc187b.js +1 -0
  161. package/dist/d9a5d958e69e058d.woff2 +0 -0
  162. package/dist/dac90d495be353a0.woff2 +0 -0
  163. package/dist/db0550511978dc47.js +1 -0
  164. package/dist/dd8ce598529c3fab.woff2 +0 -0
  165. package/dist/de013f1be25103fa.woff2 +0 -0
  166. package/dist/df222fceeffca849.woff2 +0 -0
  167. package/dist/df22bda08ec7964c.js +1 -0
  168. package/dist/e05b7f902b02a251.js +1 -0
  169. package/dist/e05b7f902b02a251.js.map +1 -0
  170. package/dist/e465f1481f0d2e1c.js +1 -0
  171. package/dist/e62b00b9199c1ac9.woff2 +0 -0
  172. package/dist/e696cef1407b2610.woff2 +0 -0
  173. package/dist/eb42de5422d9af00.js +1 -0
  174. package/dist/eed48feba743e21c.woff2 +0 -0
  175. package/dist/f135ef54213f8975.js +1 -0
  176. package/dist/f260e50923d4283b.js +1 -0
  177. package/dist/f543c88feb236d11.woff2 +0 -0
  178. package/dist/f591b0079faa93fe.woff2 +0 -0
  179. package/dist/f6ed27923769ad1d.woff2 +0 -0
  180. package/dist/f8d066e92ea157c6.js +1 -0
  181. package/dist/fae042506530c1e6.js +1 -0
  182. package/dist/favicon.ico +0 -0
  183. package/dist/fbebeb4336e67012.woff2 +0 -0
  184. package/dist/fd574df77d31a5eb.js +1 -0
  185. package/dist/icon_128x128.3dde25c6e69b1c010a6a5d6b27b3f436.png +0 -0
  186. package/dist/icon_144x144.e263e02b838d229b02ff9133e6e0f2ba.png +0 -0
  187. package/dist/icon_192x192.d3d318638bbe8a10a3c687d3d302d01a.png +0 -0
  188. package/dist/icon_256x256.c729f6e7e914b58fcea5ce91d7aa9bad.png +0 -0
  189. package/dist/icon_384x384.c8923df6b6bd08eba5c79b78d7fcecc0.png +0 -0
  190. package/dist/icon_512x512.7163efb26df832de513bc58d925ea22e.png +0 -0
  191. package/dist/icon_96x96.682ee334ae19d49894217370b8596f61.png +0 -0
  192. package/dist/index.html +9 -0
  193. package/dist/logo-512.png +0 -0
  194. package/dist/logo.svg +30 -0
  195. package/dist/manifest.266df36f2271d27ae9bcaa196a2976ae.json +47 -0
  196. package/dist/openmrs.39723c21cec4b1fc.css +1 -0
  197. package/dist/openmrs.39723c21cec4b1fc.css.map +1 -0
  198. package/dist/openmrs.44bac4c8520ee42f.css +2 -0
  199. package/dist/openmrs.44bac4c8520ee42f.css.map +1 -0
  200. package/dist/openmrs.936e8cf6a4b1599d.css +2 -0
  201. package/dist/openmrs.936e8cf6a4b1599d.css.map +1 -0
  202. package/dist/openmrs.c3adea28ef850516.js +1 -0
  203. package/dist/openmrs.c3adea28ef850516.js.map +1 -0
  204. package/dist/openmrs.e4daba1e3b840e70.css +25 -0
  205. package/dist/openmrs.e4daba1e3b840e70.css.map +1 -0
  206. package/dist/service-worker.js +1 -0
  207. package/dist/service-worker.js.map +1 -0
  208. package/dist-build-23687264126/0081d5d3d536cb23.js +1 -0
  209. package/dist-build-23687264126/02acc4469a2fe2e4.woff2 +0 -0
  210. package/dist-build-23687264126/081587ca0db8e63f.woff2 +0 -0
  211. package/dist-build-23687264126/08cf53c4e5e71cf1.woff2 +0 -0
  212. package/dist-build-23687264126/090b2bc014d24ea4.woff2 +0 -0
  213. package/dist-build-23687264126/09de5db63ef7b579.js +1 -0
  214. package/dist-build-23687264126/0ae92bcea615e948.woff2 +0 -0
  215. package/dist-build-23687264126/0be8520d8945b3b7.woff2 +0 -0
  216. package/dist-build-23687264126/0e7dd073cd8bb0ad.woff2 +0 -0
  217. package/dist-build-23687264126/0edb77cd19e43550.js +1 -0
  218. package/dist-build-23687264126/14869ac5d1830304.woff2 +0 -0
  219. package/dist-build-23687264126/14aaceff85fc8b28.woff2 +0 -0
  220. package/dist-build-23687264126/14c3abea79fc1389.js +1 -0
  221. package/dist-build-23687264126/155a4ac079785bfd.js +1 -0
  222. package/dist-build-23687264126/155a4ac079785bfd.js.map +1 -0
  223. package/dist-build-23687264126/16f443eed01776ca.woff2 +0 -0
  224. package/dist-build-23687264126/183bae0e53a22182.woff2 +0 -0
  225. package/dist-build-23687264126/19c8f94ccd6289f5.woff2 +0 -0
  226. package/dist-build-23687264126/1ae86565eab7451c.woff2 +0 -0
  227. package/dist-build-23687264126/1c7bf8797e0a9be6.woff2 +0 -0
  228. package/dist-build-23687264126/1f266d3619b30f16.woff2 +0 -0
  229. package/dist-build-23687264126/1f8c5a4087a524fd.woff2 +0 -0
  230. package/dist-build-23687264126/20ba2b23c5c0cd0b.woff2 +0 -0
  231. package/dist-build-23687264126/22a32bd51591301b.js +1 -0
  232. package/dist-build-23687264126/273c72d90e432a3d.js +1 -0
  233. package/dist-build-23687264126/295dd01a1fbfee6d.woff2 +0 -0
  234. package/dist-build-23687264126/29cbe6827c3f03ef.js +1 -0
  235. package/dist-build-23687264126/2f686985e26e7107.woff2 +0 -0
  236. package/dist-build-23687264126/315eff729e4ccbd9.woff2 +0 -0
  237. package/dist-build-23687264126/368d16e3259bf207.woff2 +0 -0
  238. package/dist-build-23687264126/36c49aa341a7079a.woff2 +0 -0
  239. package/dist-build-23687264126/36e1e0430475edee.woff2 +0 -0
  240. package/dist-build-23687264126/374c3ee36d9e040a.js +1 -0
  241. package/dist-build-23687264126/377971e519bf3f4a.js +2 -0
  242. package/dist-build-23687264126/377971e519bf3f4a.js.LICENSE.txt +39 -0
  243. package/dist-build-23687264126/377971e519bf3f4a.js.map +1 -0
  244. package/dist-build-23687264126/3b0ea8395009dcf3.js +2 -0
  245. package/dist-build-23687264126/3b0ea8395009dcf3.js.LICENSE.txt +9 -0
  246. package/dist-build-23687264126/3b0ea8395009dcf3.js.map +1 -0
  247. package/dist-build-23687264126/3bc19662b8630ee9.woff2 +0 -0
  248. package/dist-build-23687264126/3f645f473b3f8fba.woff2 +0 -0
  249. package/dist-build-23687264126/41320d8930d23b36.js +1 -0
  250. package/dist-build-23687264126/4218ac9901b9d36d.woff2 +0 -0
  251. package/dist-build-23687264126/4659f3ca46d928b5.js +1 -0
  252. package/dist-build-23687264126/4659f3ca46d928b5.js.map +1 -0
  253. package/dist-build-23687264126/4680ba68412e4da9.woff2 +0 -0
  254. package/dist-build-23687264126/48e37bd7ebf85a1f.woff2 +0 -0
  255. package/dist-build-23687264126/4aabceefe5a2494a.js +1 -0
  256. package/dist-build-23687264126/4c188cbaefba58cd.js +1 -0
  257. package/dist-build-23687264126/4e11b8a7c445255f.woff2 +0 -0
  258. package/dist-build-23687264126/537ddd61c5c1fce2.woff2 +0 -0
  259. package/dist-build-23687264126/54f5eee3a7989556.js +1 -0
  260. package/dist-build-23687264126/55c9107b50dd747c.js +1 -0
  261. package/dist-build-23687264126/56c4118c0907f151.woff2 +0 -0
  262. package/dist-build-23687264126/5938bc2ae7ec60c0.woff2 +0 -0
  263. package/dist-build-23687264126/5c6586155f0d278a.woff2 +0 -0
  264. package/dist-build-23687264126/5e50c92017029ca3.js +1 -0
  265. package/dist-build-23687264126/5e50c92017029ca3.js.map +1 -0
  266. package/dist-build-23687264126/600aca7295d8bcb7.js +2 -0
  267. package/dist-build-23687264126/600aca7295d8bcb7.js.LICENSE.txt +9 -0
  268. package/dist-build-23687264126/600aca7295d8bcb7.js.map +1 -0
  269. package/dist-build-23687264126/60ec587649ba812a.woff2 +0 -0
  270. package/dist-build-23687264126/64cf08a5ac3266d8.js +1 -0
  271. package/dist-build-23687264126/652f476a8a1603d3.js +2 -0
  272. package/dist-build-23687264126/652f476a8a1603d3.js.LICENSE.txt +9 -0
  273. package/dist-build-23687264126/652f476a8a1603d3.js.map +1 -0
  274. package/dist-build-23687264126/65e6511e035870e1.woff2 +0 -0
  275. package/dist-build-23687264126/661425f6798cd16a.woff2 +0 -0
  276. package/dist-build-23687264126/66b864fe213caf46.woff2 +0 -0
  277. package/dist-build-23687264126/680eb791e6266590.js +2 -0
  278. package/dist-build-23687264126/680eb791e6266590.js.LICENSE.txt +19 -0
  279. package/dist-build-23687264126/680eb791e6266590.js.map +1 -0
  280. package/dist-build-23687264126/69d087d970ee9455.woff2 +0 -0
  281. package/dist-build-23687264126/69e3aa4276b4cb4b.js +1 -0
  282. package/dist-build-23687264126/6a88f03fc4e7c3da.js +1 -0
  283. package/dist-build-23687264126/6c6c45e66ff54281.woff2 +0 -0
  284. package/dist-build-23687264126/6d9009857c6df878.js +1 -0
  285. package/dist-build-23687264126/6ebe7cea59ed2853.js +1 -0
  286. package/dist-build-23687264126/6f3181849e740935.js +1 -0
  287. package/dist-build-23687264126/6f3181849e740935.js.map +1 -0
  288. package/dist-build-23687264126/7073a7323e92bd11.woff2 +0 -0
  289. package/dist-build-23687264126/70ac433ae2a89a89.js +1 -0
  290. package/dist-build-23687264126/70ee4ee625ac0ec1.js +1 -0
  291. package/dist-build-23687264126/718c6cc31274ab1a.woff2 +0 -0
  292. package/dist-build-23687264126/727696c3934d0966.js +1 -0
  293. package/dist-build-23687264126/727763c0f0df59dc.js +1 -0
  294. package/dist-build-23687264126/727763c0f0df59dc.js.map +1 -0
  295. package/dist-build-23687264126/72cdbedfe04be9f9.woff2 +0 -0
  296. package/dist-build-23687264126/7509c9f56fe9e532.woff2 +0 -0
  297. package/dist-build-23687264126/75dc5c5b04adc8bf.woff2 +0 -0
  298. package/dist-build-23687264126/77b48bc05299ecca.woff2 +0 -0
  299. package/dist-build-23687264126/7a0a0215c248c73d.woff2 +0 -0
  300. package/dist-build-23687264126/7c0d0c5180de8729.js +1 -0
  301. package/dist-build-23687264126/7f00bebb24e40167.woff2 +0 -0
  302. package/dist-build-23687264126/802c6176541eeed7.woff2 +0 -0
  303. package/dist-build-23687264126/8080081b3379c637.woff2 +0 -0
  304. package/dist-build-23687264126/81cfdaeaa0bbca1f.js +1 -0
  305. package/dist-build-23687264126/8605507b7a8487c4.woff2 +0 -0
  306. package/dist-build-23687264126/893a160d06428365.js +1 -0
  307. package/dist-build-23687264126/893a160d06428365.js.map +1 -0
  308. package/dist-build-23687264126/8a83d654702f6534.woff2 +0 -0
  309. package/dist-build-23687264126/8fe71173a13fe571.woff2 +0 -0
  310. package/dist-build-23687264126/94aa912dcac90114.js +1 -0
  311. package/dist-build-23687264126/9624cec0f9bdd81e.woff2 +0 -0
  312. package/dist-build-23687264126/98a3af55a1698171.woff2 +0 -0
  313. package/dist-build-23687264126/99823aaebba56f46.js +1 -0
  314. package/dist-build-23687264126/9ba85996af74c5ce.woff2 +0 -0
  315. package/dist-build-23687264126/9ddb22faa35006e7.woff2 +0 -0
  316. package/dist-build-23687264126/a167fb2799dd741b.woff2 +0 -0
  317. package/dist-build-23687264126/a2045a5cc4fdf94f.woff2 +0 -0
  318. package/dist-build-23687264126/a246c73905a31c93.woff2 +0 -0
  319. package/dist-build-23687264126/a325099b0a580ce2.js +2 -0
  320. package/dist-build-23687264126/a325099b0a580ce2.js.LICENSE.txt +14 -0
  321. package/dist-build-23687264126/a325099b0a580ce2.js.map +1 -0
  322. package/dist-build-23687264126/a401aa7939cb6e6f.woff2 +0 -0
  323. package/dist-build-23687264126/a40fef67997d3b2c.js +1 -0
  324. package/dist-build-23687264126/a62897b000a24b86.js +1 -0
  325. package/dist-build-23687264126/a6ed036f17a1ea29.woff2 +0 -0
  326. package/dist-build-23687264126/a77bac4877483a0a.js +1 -0
  327. package/dist-build-23687264126/a9f25ca430709a1a.woff2 +0 -0
  328. package/dist-build-23687264126/aa0dfbdd569b1c24.js +2 -0
  329. package/dist-build-23687264126/aa0dfbdd569b1c24.js.LICENSE.txt +5 -0
  330. package/dist-build-23687264126/aa0dfbdd569b1c24.js.map +1 -0
  331. package/dist-build-23687264126/ab0f637d6cff12e4.js +1 -0
  332. package/dist-build-23687264126/afa9121a49e95351.woff2 +0 -0
  333. package/dist-build-23687264126/afcda12d9f805543.woff2 +0 -0
  334. package/dist-build-23687264126/b09ded85a7da77f1.woff2 +0 -0
  335. package/dist-build-23687264126/b10dbe5318a91a12.js +1 -0
  336. package/dist-build-23687264126/b2f4e9d1e821b71c.woff2 +0 -0
  337. package/dist-build-23687264126/b4a074bf828bb757.woff2 +0 -0
  338. package/dist-build-23687264126/b7f447da43f6e596.woff2 +0 -0
  339. package/dist-build-23687264126/bcca84a524572d10.woff2 +0 -0
  340. package/dist-build-23687264126/be093e052a6d50eb.js +1 -0
  341. package/dist-build-23687264126/be4d1f97b11d087c.woff2 +0 -0
  342. package/dist-build-23687264126/bec14780d81164de.woff2 +0 -0
  343. package/dist-build-23687264126/c31657fe213c1b5e.js +1 -0
  344. package/dist-build-23687264126/c49ef726d3f0420b.js +1 -0
  345. package/dist-build-23687264126/c553f7e0199c5084.woff2 +0 -0
  346. package/dist-build-23687264126/c94ac2fdc1ff1418.js +1 -0
  347. package/dist-build-23687264126/c9d9ce9f465df4fe.woff2 +0 -0
  348. package/dist-build-23687264126/cbbb57b397433964.js +2 -0
  349. package/dist-build-23687264126/cbbb57b397433964.js.LICENSE.txt +14 -0
  350. package/dist-build-23687264126/cbbb57b397433964.js.map +1 -0
  351. package/dist-build-23687264126/d188f7f036ac5779.woff2 +0 -0
  352. package/dist-build-23687264126/d1aa59bd9c702dc4.js +2 -0
  353. package/dist-build-23687264126/d1aa59bd9c702dc4.js.LICENSE.txt +32 -0
  354. package/dist-build-23687264126/d1aa59bd9c702dc4.js.map +1 -0
  355. package/dist-build-23687264126/d265d81c58525ae4.woff2 +0 -0
  356. package/dist-build-23687264126/d5942cd81663e136.woff2 +0 -0
  357. package/dist-build-23687264126/d66b8ff73d95cabb.woff2 +0 -0
  358. package/dist-build-23687264126/d84bac6d07672dd2.js +1 -0
  359. package/dist-build-23687264126/d84bac6d07672dd2.js.map +1 -0
  360. package/dist-build-23687264126/d88899ef0fd16719.woff2 +0 -0
  361. package/dist-build-23687264126/d92b5ecf31fc187b.js +1 -0
  362. package/dist-build-23687264126/d9a5d958e69e058d.woff2 +0 -0
  363. package/dist-build-23687264126/dac90d495be353a0.woff2 +0 -0
  364. package/dist-build-23687264126/db0550511978dc47.js +1 -0
  365. package/dist-build-23687264126/dd8ce598529c3fab.woff2 +0 -0
  366. package/dist-build-23687264126/de013f1be25103fa.woff2 +0 -0
  367. package/dist-build-23687264126/df222fceeffca849.woff2 +0 -0
  368. package/dist-build-23687264126/df22bda08ec7964c.js +1 -0
  369. package/dist-build-23687264126/e05b7f902b02a251.js +1 -0
  370. package/dist-build-23687264126/e05b7f902b02a251.js.map +1 -0
  371. package/dist-build-23687264126/e465f1481f0d2e1c.js +1 -0
  372. package/dist-build-23687264126/e62b00b9199c1ac9.woff2 +0 -0
  373. package/dist-build-23687264126/e696cef1407b2610.woff2 +0 -0
  374. package/dist-build-23687264126/eb42de5422d9af00.js +1 -0
  375. package/dist-build-23687264126/eed48feba743e21c.woff2 +0 -0
  376. package/dist-build-23687264126/f135ef54213f8975.js +1 -0
  377. package/dist-build-23687264126/f260e50923d4283b.js +1 -0
  378. package/dist-build-23687264126/f543c88feb236d11.woff2 +0 -0
  379. package/dist-build-23687264126/f591b0079faa93fe.woff2 +0 -0
  380. package/dist-build-23687264126/f6ed27923769ad1d.woff2 +0 -0
  381. package/dist-build-23687264126/f8d066e92ea157c6.js +1 -0
  382. package/dist-build-23687264126/fae042506530c1e6.js +1 -0
  383. package/dist-build-23687264126/favicon.ico +0 -0
  384. package/dist-build-23687264126/fbebeb4336e67012.woff2 +0 -0
  385. package/dist-build-23687264126/fd574df77d31a5eb.js +1 -0
  386. package/dist-build-23687264126/icon_128x128.3dde25c6e69b1c010a6a5d6b27b3f436.png +0 -0
  387. package/dist-build-23687264126/icon_144x144.e263e02b838d229b02ff9133e6e0f2ba.png +0 -0
  388. package/dist-build-23687264126/icon_192x192.d3d318638bbe8a10a3c687d3d302d01a.png +0 -0
  389. package/dist-build-23687264126/icon_256x256.c729f6e7e914b58fcea5ce91d7aa9bad.png +0 -0
  390. package/dist-build-23687264126/icon_384x384.c8923df6b6bd08eba5c79b78d7fcecc0.png +0 -0
  391. package/dist-build-23687264126/icon_512x512.7163efb26df832de513bc58d925ea22e.png +0 -0
  392. package/dist-build-23687264126/icon_96x96.682ee334ae19d49894217370b8596f61.png +0 -0
  393. package/dist-build-23687264126/index.html +9 -0
  394. package/dist-build-23687264126/logo-512.png +0 -0
  395. package/dist-build-23687264126/logo.svg +30 -0
  396. package/dist-build-23687264126/manifest.266df36f2271d27ae9bcaa196a2976ae.json +47 -0
  397. package/dist-build-23687264126/openmrs.39723c21cec4b1fc.css +1 -0
  398. package/dist-build-23687264126/openmrs.39723c21cec4b1fc.css.map +1 -0
  399. package/dist-build-23687264126/openmrs.44bac4c8520ee42f.css +2 -0
  400. package/dist-build-23687264126/openmrs.44bac4c8520ee42f.css.map +1 -0
  401. package/dist-build-23687264126/openmrs.936e8cf6a4b1599d.css +2 -0
  402. package/dist-build-23687264126/openmrs.936e8cf6a4b1599d.css.map +1 -0
  403. package/dist-build-23687264126/openmrs.c3adea28ef850516.js +1 -0
  404. package/dist-build-23687264126/openmrs.c3adea28ef850516.js.map +1 -0
  405. package/dist-build-23687264126/openmrs.e4daba1e3b840e70.css +25 -0
  406. package/dist-build-23687264126/openmrs.e4daba1e3b840e70.css.map +1 -0
  407. package/dist-build-23687264126/service-worker.js +1 -0
  408. package/dist-build-23687264126/service-worker.js.map +1 -0
  409. package/e2e/core/env.ts +5 -0
  410. package/e2e/core/global-setup.ts +34 -0
  411. package/e2e/core/test.ts +21 -0
  412. package/e2e/pages/app-shell.page.ts +34 -0
  413. package/e2e/pages/etl-sources.page.ts +35 -0
  414. package/e2e/pages/report-sections.page.ts +20 -0
  415. package/e2e/pages/section-preview.modal.ts +29 -0
  416. package/e2e/specs/etl-sources.spec.ts +51 -0
  417. package/e2e/specs/navigation.spec.ts +13 -0
  418. package/e2e/specs/section-preview-validation.spec.ts +38 -0
  419. package/e2e/specs/section-preview.spec.ts +94 -0
  420. package/e2e/tsconfig.json +11 -0
  421. package/example.env +5 -0
  422. package/jest.config.js +28 -0
  423. package/package.json +82 -0
  424. package/playwright.config.ts +28 -0
  425. package/src/admin-card-link.extension.module.scss +55 -0
  426. package/src/admin-card-link.extension.tsx +24 -0
  427. package/src/components/admin/admin-page.component.tsx +31 -0
  428. package/src/components/admin/age-categories-page.component.tsx +109 -0
  429. package/src/components/admin/age-groups-page.component.tsx +146 -0
  430. package/src/components/admin/etl-sources-page.component.tsx +344 -0
  431. package/src/components/admin/report-categories-page.component.tsx +256 -0
  432. package/src/components/admin/report-library-page.component.tsx +540 -0
  433. package/src/components/ai-support/ai-assist-button.component.tsx +30 -0
  434. package/src/components/ai-support/ai-assist-modal.component.tsx +81 -0
  435. package/src/components/ai-support/ai.service.ts +21 -0
  436. package/src/components/ai-support/ai.types.ts +12 -0
  437. package/src/components/app-shell/report-builder-shell.component.tsx +120 -0
  438. package/src/components/app-shell/report-builder-shell.scss +15 -0
  439. package/src/components/data-themes/data-theme-form.component.tsx +59 -0
  440. package/src/components/data-themes/data-theme-modal.component.tsx +349 -0
  441. package/src/components/data-themes/data-themes-page.component.tsx +132 -0
  442. package/src/components/data-themes/data-themes-table.component.tsx +91 -0
  443. package/src/components/data-themes/icon-registry.ts +35 -0
  444. package/src/components/data-themes/sections/data-theme-basics.section.tsx +63 -0
  445. package/src/components/data-themes/sections/data-theme-condition-columns.section.tsx +397 -0
  446. package/src/components/data-themes/sections/data-theme-fields-editor.section.tsx +125 -0
  447. package/src/components/data-themes/sections/data-theme-metadata.section.tsx +245 -0
  448. package/src/components/data-themes/sections/data-theme-preview.section.tsx +115 -0
  449. package/src/components/data-themes/sections/data-theme-source.section.tsx +184 -0
  450. package/src/components/indicators/README.md +24 -0
  451. package/src/components/indicators/base-indicator-basic-fields.component.tsx +18 -0
  452. package/src/components/indicators/base-indicator-basics.section.tsx +54 -0
  453. package/src/components/indicators/base-indicator-countby.section.tsx +25 -0
  454. package/src/components/indicators/base-indicator-criteria.section.tsx +83 -0
  455. package/src/components/indicators/base-indicator-details-form.component.tsx +80 -0
  456. package/src/components/indicators/base-indicator-theme-unit-fields.component.tsx +39 -0
  457. package/src/components/indicators/create-base-indicator-modal.component.tsx +501 -0
  458. package/src/components/indicators/create-composite-base-indicator-modal.component.tsx +297 -0
  459. package/src/components/indicators/create-final-indicator-modal.component.tsx +260 -0
  460. package/src/components/indicators/diagnosis-filters-form.component.tsx +101 -0
  461. package/src/components/indicators/disaggregation-panel.component.tsx +93 -0
  462. package/src/components/indicators/handler/concept-search-multiselect.component.tsx +153 -0
  463. package/src/components/indicators/handler/question-answer-concept-search.component.tsx +336 -0
  464. package/src/components/indicators/indicator-status-tag.component.tsx +9 -0
  465. package/src/components/indicators/indicators-page.component.tsx +481 -0
  466. package/src/components/indicators/indicators-page.scss +121 -0
  467. package/src/components/indicators/indicators-table.component.tsx +166 -0
  468. package/src/components/indicators/preview-table.component.tsx +31 -0
  469. package/src/components/indicators/sections/composite-indicator-basics.section.tsx +36 -0
  470. package/src/components/indicators/sections/composite-indicator-picker.section.tsx +161 -0
  471. package/src/components/indicators/sections/composite-indicator-sql-preview.section.tsx +31 -0
  472. package/src/components/indicators/sections/final-indicator-basics.section.tsx +46 -0
  473. package/src/components/indicators/sections/final-indicator-disaggregation.section.tsx +47 -0
  474. package/src/components/indicators/sections/final-indicator-picker.section.tsx +92 -0
  475. package/src/components/indicators/sections/final-indicator-preview.section.tsx +20 -0
  476. package/src/components/indicators/sections/final-indicator-results-preview.section.tsx +65 -0
  477. package/src/components/indicators/sections/indicator-basics.section.tsx +40 -0
  478. package/src/components/indicators/sections/indicator-conditions.section.tsx +194 -0
  479. package/src/components/indicators/sections/indicator-sql-preview.section.tsx +26 -0
  480. package/src/components/indicators/sections/indicator-theme.section.tsx +48 -0
  481. package/src/components/indicators/sql-preview.component.tsx +19 -0
  482. package/src/components/indicators/types/base-indicator-form.types.ts +17 -0
  483. package/src/components/indicators/types/base-indicator-theme.constants.ts +8 -0
  484. package/src/components/indicators/types/composite-indicator.types.ts +21 -0
  485. package/src/components/indicators/types/condition-ui.types.ts +11 -0
  486. package/src/components/indicators/types/data-theme-config.types.ts +88 -0
  487. package/src/components/indicators/types/indicator-types.ts +56 -0
  488. package/src/components/indicators/types/sql-builders.ts +43 -0
  489. package/src/components/indicators/utils/composite-indicator-sql.utils.ts +206 -0
  490. package/src/components/indicators/utils/concept-preload.utils.ts +21 -0
  491. package/src/components/indicators/utils/final-indicator-sql.utils.ts +124 -0
  492. package/src/components/indicators/utils/indicator-conditions-hydration.utils.ts +254 -0
  493. package/src/components/indicators/utils/indicator-sql.utils.ts +185 -0
  494. package/src/components/landing/landing-action-item.component.tsx +50 -0
  495. package/src/components/landing/landing-action-list.component.tsx +12 -0
  496. package/src/components/landing/landing-activity-list.component.tsx +47 -0
  497. package/src/components/landing/landing-footer-grid.component.tsx +45 -0
  498. package/src/components/landing/landing-hero.component.tsx +18 -0
  499. package/src/components/landing/landing-section-card.component.tsx +33 -0
  500. package/src/components/landing/report-builder-landing-page.component.tsx +103 -0
  501. package/src/components/landing/report-builder-landing-page.scss +131 -0
  502. package/src/components/report/dashboard/reports-table.component.tsx +145 -0
  503. package/src/components/report/definition/panels/properties-panel.component.tsx +38 -0
  504. package/src/components/report/definition/panels/report-structure-panel.component.tsx +61 -0
  505. package/src/components/report/definition/panels/selection-panel.component.tsx +58 -0
  506. package/src/components/report/definition/report-definition-editor.component.tsx +99 -0
  507. package/src/components/report/definition/report-definition.types.ts +66 -0
  508. package/src/components/report/design/panels/IndicatorPropertiesPanel.scss +33 -0
  509. package/src/components/report/design/panels/IndicatorPropertiesPanel.tsx +389 -0
  510. package/src/components/report/design/panels/JsonPreviewPanel.scss +32 -0
  511. package/src/components/report/design/panels/JsonPreviewPanel.tsx +104 -0
  512. package/src/components/report/design/panels/mapping-preview-panel.component.tsx +82 -0
  513. package/src/components/report/design/panels/mapping-preview-panel.scss +55 -0
  514. package/src/components/report/design/panels/template-structure-panel.component.tsx +296 -0
  515. package/src/components/report/design/panels/template-structure-panel.scss +81 -0
  516. package/src/components/report/design/report-design-editor.component.tsx +894 -0
  517. package/src/components/report/design/report-design.types.ts +43 -0
  518. package/src/components/report/design/report-design.utils.ts +86 -0
  519. package/src/components/report/panels/report-detail.component.tsx +71 -0
  520. package/src/components/report/panels/report-panel-shell.component.tsx +60 -0
  521. package/src/components/report/report-dashboard.page.component.tsx +75 -0
  522. package/src/components/report/report-editor.page.component.tsx +466 -0
  523. package/src/components/report/report.routes.tsx +30 -0
  524. package/src/components/report-sections/create-report-section-modal.component.tsx +278 -0
  525. package/src/components/report-sections/hooks/useAgeCategories.ts +25 -0
  526. package/src/components/report-sections/hooks/useSectionEditorState.ts +306 -0
  527. package/src/components/report-sections/panels/Dhis2MappingPanel.tsx +157 -0
  528. package/src/components/report-sections/panels/DisaggregationPanel.tsx +97 -0
  529. package/src/components/report-sections/panels/IndicatorPickerPanel.tsx +143 -0
  530. package/src/components/report-sections/panels/SectionBasicsPanel.tsx +27 -0
  531. package/src/components/report-sections/report-section-preview-modal.component.tsx +418 -0
  532. package/src/components/report-sections/report-sections-page.component.tsx +313 -0
  533. package/src/components/report-sections/section-types.ts +55 -0
  534. package/src/components/report-sections/section-utils.ts +46 -0
  535. package/src/components/report-sections/sections-page.scss +79 -0
  536. package/src/components/run-reports/run-reports-page.component.tsx +23 -0
  537. package/src/components/shared/header/builder-header-actions.component.tsx +38 -0
  538. package/src/components/shared/header/header.component.tsx +85 -0
  539. package/src/components/shared/header/header.scss +150 -0
  540. package/src/components/shared/header/illustration.component.tsx +34 -0
  541. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.scss +33 -0
  542. package/src/components/shared/indicator-properties-panel/IndicatorPropertiesPanel.tsx +389 -0
  543. package/src/components/shared/json-preview-panel/JsonPreviewPanel.scss +32 -0
  544. package/src/components/shared/json-preview-panel/JsonPreviewPanel.tsx +104 -0
  545. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.component.tsx +82 -0
  546. package/src/components/shared/mapping-preview-panel/mapping-preview-panel.scss +55 -0
  547. package/src/components/shared/preview/query-results-preview.component.tsx +204 -0
  548. package/src/components/shared/template-structure-panel/template-structure-panel.component.tsx +296 -0
  549. package/src/components/shared/template-structure-panel/template-structure-panel.scss +81 -0
  550. package/src/config-schema.ts +23 -0
  551. package/src/globals.d.ts +14 -0
  552. package/src/hooks/theme/useDataThemes.ts +28 -0
  553. package/src/hooks/theme/useMambaTableMeta.ts +34 -0
  554. package/src/hooks/theme/useMambaTables.ts +63 -0
  555. package/src/index.ts +23 -0
  556. package/src/resources/agegroup/agegroups.api.ts +58 -0
  557. package/src/resources/concepts/concept-mapper.ts +21 -0
  558. package/src/resources/concepts/concept-types.ts +31 -0
  559. package/src/resources/concepts/concepts.resource.ts +44 -0
  560. package/src/resources/concepts/useConceptSearch.ts +41 -0
  561. package/src/resources/etl-source/etl-source.api.ts +65 -0
  562. package/src/resources/indicator/indicators.api.ts +125 -0
  563. package/src/resources/openmrs-api.ts +24 -0
  564. package/src/resources/preview/sql-preview.api.ts +54 -0
  565. package/src/resources/report/reports.api.ts +117 -0
  566. package/src/resources/report-category/report-category.api.ts +41 -0
  567. package/src/resources/report-library/report-library.api.ts +63 -0
  568. package/src/resources/report-section/report-sections.api.ts +73 -0
  569. package/src/resources/report-section/section-preview.api.ts +21 -0
  570. package/src/resources/theme/data-theme.api.ts +88 -0
  571. package/src/resources/theme/mamba-schema.api.ts +31 -0
  572. package/src/resources/theme/mamba-table-meta.api.ts +45 -0
  573. package/src/root.component.tsx +20 -0
  574. package/src/routes/report-builder.routes.tsx +66 -0
  575. package/src/routes/report-builder.scss +56 -0
  576. package/src/routes.json +21 -0
  577. package/src/sample-template.ts +121 -0
  578. package/src/template-utils.ts +110 -0
  579. package/src/types/carbon-react-inert.d.ts +13 -0
  580. package/src/types/condition-operators.ts +49 -0
  581. package/src/types/theme/data-theme.types.ts +88 -0
  582. package/src/utils/html-entities.utils.ts +23 -0
  583. package/tools/setup-tests.ts +1 -0
  584. package/translations/en.json +4 -0
  585. package/tsconfig.json +43 -0
  586. package/webpack.config.js +14 -0
@@ -0,0 +1,894 @@
1
+ import React from 'react';
2
+ import {
3
+ Button,
4
+ InlineNotification,
5
+ Tabs,
6
+ TabList,
7
+ Tab,
8
+ TextInput,
9
+ NumberInput,
10
+ Select,
11
+ SelectItem,
12
+ Checkbox,
13
+ Tag,
14
+ } from '@carbon/react';
15
+ import {
16
+ Add,
17
+ ArrowUp,
18
+ ArrowDown,
19
+ TrashCan,
20
+ Draggable,
21
+ ArrowRight,
22
+ ArrowLeft,
23
+ Renew,
24
+ View,
25
+ Download,
26
+ Copy,
27
+ Launch,
28
+ } from '@carbon/icons-react';
29
+ import { useTranslation } from 'react-i18next';
30
+
31
+ import styles from '../../../routes/report-builder.scss';
32
+
33
+ import type { ReportDefinitionDraft } from '../definition/report-definition.types';
34
+ import type { DesignGroup, DesignRow, ReportDesignDraft } from './report-design.types';
35
+ import {
36
+ createEmptyDesignRow,
37
+ createEmptyReportDesignDraft,
38
+ } from './report-design.utils';
39
+
40
+ export type DesignSectionSource = {
41
+ sectionUuid: string;
42
+ title: string;
43
+ indicators: Array<{
44
+ id: string;
45
+ code: string;
46
+ name: string;
47
+ type: string;
48
+ }>;
49
+ };
50
+
51
+ type Props = {
52
+ value?: ReportDesignDraft | null;
53
+ onChange?: (next: ReportDesignDraft) => void;
54
+ definitionDraft?: ReportDefinitionDraft | null;
55
+ sectionSources?: DesignSectionSource[];
56
+ sectionNameLookup?: Record<string, string>;
57
+ };
58
+
59
+ type DragState = {
60
+ rowId: string;
61
+ fromGroupId: string;
62
+ } | null;
63
+
64
+ type StructureItem =
65
+ | { kind: 'group'; group: DesignGroup }
66
+ | { kind: 'row'; group: DesignGroup; row: DesignRow; rowIndex: number };
67
+
68
+ const MAX_INDENT = 10;
69
+
70
+ function getMinIndentForRowType(type?: string | null) {
71
+ return type === 'section-label' ? 0 : 1;
72
+ }
73
+
74
+ function clampIndentForRowType(indent: number | undefined, type?: string | null) {
75
+ const min = getMinIndentForRowType(type);
76
+ const safe = Number.isNaN(Number(indent)) ? min : Number(indent ?? min);
77
+ return Math.max(min, Math.min(MAX_INDENT, safe));
78
+ }
79
+
80
+ function applyRowTypeDefaults(row: DesignRow, nextType: string): DesignRow {
81
+ if (nextType === 'section-label') {
82
+ return {
83
+ ...row,
84
+ type: nextType as any,
85
+ indent: 0,
86
+ span: 'all' as any,
87
+ emphasis: 'section' as any,
88
+ showTotal: false,
89
+ showDisaggregation: false,
90
+ };
91
+ }
92
+
93
+ if (nextType === 'group-label') {
94
+ return {
95
+ ...row,
96
+ type: nextType as any,
97
+ indent: clampIndentForRowType(row.indent, nextType),
98
+ span: 'label-only' as any,
99
+ emphasis: 'group' as any,
100
+ showTotal: false,
101
+ showDisaggregation: false,
102
+ };
103
+ }
104
+
105
+ if (nextType === 'indicator') {
106
+ return {
107
+ ...row,
108
+ type: nextType as any,
109
+ indent: clampIndentForRowType(row.indent, nextType),
110
+ span: 'label-only' as any,
111
+ emphasis: 'normal' as any,
112
+ showTotal: true,
113
+ showDisaggregation: true,
114
+ };
115
+ }
116
+
117
+ return {
118
+ ...row,
119
+ type: nextType as any,
120
+ indent: clampIndentForRowType(row.indent, nextType),
121
+ span: 'label-only' as any,
122
+ emphasis: 'normal' as any,
123
+ };
124
+ }
125
+
126
+ function buildDesignFromSectionSources(
127
+ sectionSources: DesignSectionSource[] = [],
128
+ previous?: ReportDesignDraft | null,
129
+ ): ReportDesignDraft {
130
+ return {
131
+ version: 1,
132
+ template: 'section-tabular',
133
+ arrayName: previous?.arrayName ?? 'results',
134
+ defaultValue: previous?.defaultValue ?? 0,
135
+ dimensions: previous?.dimensions ?? {},
136
+ groups: sectionSources.map((section) => ({
137
+ id: section.sectionUuid,
138
+ title: section.title,
139
+ rows: [
140
+ {
141
+ id: `${section.sectionUuid}__section_label`,
142
+ type: 'section-label' as any,
143
+ label: section.title,
144
+ indent: 0,
145
+ span: 'all' as any,
146
+ emphasis: 'section' as any,
147
+ showTotal: false,
148
+ showDisaggregation: false,
149
+ },
150
+ ...section.indicators.map((i) => ({
151
+ id: i.id,
152
+ type: 'indicator' as const,
153
+ code: i.code,
154
+ label: `${i.code}. ${i.name}`,
155
+ indent: 1,
156
+ keyPattern: '{code}_{age}_{sex}',
157
+ dims: {},
158
+ showTotal: true,
159
+ showDisaggregation: true,
160
+ span: 'label-only' as any,
161
+ emphasis: 'normal' as any,
162
+ })),
163
+ ],
164
+ })),
165
+ };
166
+ }
167
+
168
+ function buildMappingPreview(groups: DesignGroup[]) {
169
+ const columns = ['Age <5 | Male', 'Age <5 | Female', '5-14 | Male', '5-14 | Female'];
170
+
171
+ const rows = groups.flatMap((group) =>
172
+ group.rows.map((r) => ({
173
+ id: r.id,
174
+ type: r.type,
175
+ code: (r as any).code,
176
+ label: r.label || r.code || 'Untitled row',
177
+ values:
178
+ r.type === ('section-label' as any) || r.type === ('group-label' as any)
179
+ ? []
180
+ : columns.map(() => 0),
181
+ indent: r.indent ?? 0,
182
+ groupId: group.id,
183
+ })),
184
+ );
185
+
186
+ return { columns, rows };
187
+ }
188
+
189
+ const ReportDesignEditor: React.FC<Props> = ({
190
+ value,
191
+ onChange,
192
+ definitionDraft,
193
+ sectionSources = [],
194
+ }) => {
195
+ const { t } = useTranslation();
196
+
197
+ const [selectedGroupId, setSelectedGroupId] = React.useState<string | null>(null);
198
+ const [selectedRowId, setSelectedRowId] = React.useState<string | null>(null);
199
+ const [dragState, setDragState] = React.useState<DragState>(null);
200
+ const [dragOverRowId, setDragOverRowId] = React.useState<string | null>(null);
201
+ const [propTab, setPropTab] = React.useState<'details' | 'disaggregation' | 'mapping' | 'api'>('details');
202
+
203
+ const draft = React.useMemo<ReportDesignDraft>(
204
+ () => value ?? createEmptyReportDesignDraft(),
205
+ [value],
206
+ );
207
+
208
+ const setDraft = React.useCallback(
209
+ (next: ReportDesignDraft) => {
210
+ onChange?.(next);
211
+ },
212
+ [onChange],
213
+ );
214
+
215
+ const groups = draft.groups ?? [];
216
+
217
+ React.useEffect(() => {
218
+ if (!selectedGroupId && groups.length > 0) {
219
+ setSelectedGroupId(groups[0].id);
220
+ }
221
+ }, [groups, selectedGroupId]);
222
+
223
+ const selectedRow = React.useMemo(
224
+ () =>
225
+ groups
226
+ .flatMap((g) => g.rows)
227
+ .find((r) => r.id === selectedRowId) ?? null,
228
+ [groups, selectedRowId],
229
+ );
230
+
231
+ const updateGroups = React.useCallback(
232
+ (nextGroups: DesignGroup[]) => {
233
+ setDraft({
234
+ ...draft,
235
+ groups: nextGroups,
236
+ });
237
+ },
238
+ [draft, setDraft],
239
+ );
240
+
241
+ const updateRow = React.useCallback(
242
+ (groupId: string, rowId: string, patch: Partial<DesignRow>) => {
243
+ updateGroups(
244
+ groups.map((g) =>
245
+ g.id === groupId
246
+ ? {
247
+ ...g,
248
+ rows: g.rows.map((r) => {
249
+ if (r.id !== rowId) return r;
250
+ const next = { ...r, ...patch };
251
+ return {
252
+ ...next,
253
+ indent: clampIndentForRowType(next.indent, next.type),
254
+ };
255
+ }),
256
+ }
257
+ : g,
258
+ ),
259
+ );
260
+ },
261
+ [groups, updateGroups],
262
+ );
263
+
264
+ const addRowToGroup = React.useCallback(
265
+ (groupId: string) => {
266
+ const row = createEmptyDesignRow();
267
+ row.indent = 1;
268
+
269
+ updateGroups(
270
+ groups.map((g) =>
271
+ g.id === groupId
272
+ ? { ...g, rows: [...g.rows, row] }
273
+ : g,
274
+ ),
275
+ );
276
+ setSelectedGroupId(groupId);
277
+ setSelectedRowId(row.id);
278
+ },
279
+ [groups, updateGroups],
280
+ );
281
+
282
+ const removeRow = React.useCallback(
283
+ (groupId: string, rowId: string) => {
284
+ updateGroups(
285
+ groups.map((g) =>
286
+ g.id === groupId
287
+ ? { ...g, rows: g.rows.filter((r) => r.id !== rowId) }
288
+ : g,
289
+ ),
290
+ );
291
+
292
+ if (selectedRowId === rowId) {
293
+ setSelectedRowId(null);
294
+ }
295
+ },
296
+ [groups, selectedRowId, updateGroups],
297
+ );
298
+
299
+ const moveRow = React.useCallback(
300
+ (groupId: string, rowId: string, dir: -1 | 1) => {
301
+ const group = groups.find((g) => g.id === groupId);
302
+ if (!group) return;
303
+
304
+ const rows = group.rows.slice();
305
+ const idx = rows.findIndex((r) => r.id === rowId);
306
+ if (idx < 0) return;
307
+
308
+ const j = idx + dir;
309
+ if (j < 0 || j >= rows.length) return;
310
+
311
+ const tmp = rows[idx];
312
+ rows[idx] = rows[j];
313
+ rows[j] = tmp;
314
+
315
+ updateGroups(
316
+ groups.map((g) =>
317
+ g.id === groupId ? { ...g, rows } : g,
318
+ ),
319
+ );
320
+ },
321
+ [groups, updateGroups],
322
+ );
323
+
324
+ const indentRow = React.useCallback(
325
+ (groupId: string, rowId: string, dir: -1 | 1) => {
326
+ const group = groups.find((g) => g.id === groupId);
327
+ const row = group?.rows.find((r) => r.id === rowId);
328
+ if (!group || !row) return;
329
+
330
+ const minIndent = getMinIndentForRowType(row.type);
331
+ const nextIndent = Math.max(minIndent, Math.min(MAX_INDENT, (row.indent ?? minIndent) + dir));
332
+ updateRow(groupId, rowId, { indent: nextIndent });
333
+ },
334
+ [groups, updateRow],
335
+ );
336
+
337
+ const generateFromDefinition = React.useCallback(() => {
338
+ const next = buildDesignFromSectionSources(sectionSources, draft);
339
+ setDraft(next);
340
+ setSelectedGroupId(next.groups[0]?.id ?? null);
341
+ setSelectedRowId(next.groups[0]?.rows[0]?.id ?? null);
342
+ }, [draft, sectionSources, setDraft]);
343
+
344
+ const handleDragStart = React.useCallback((rowId: string, fromGroupId: string) => {
345
+ setDragState({ rowId, fromGroupId });
346
+ }, []);
347
+
348
+ const handleDropOnRow = React.useCallback(
349
+ (targetGroupId: string, targetRowId: string) => {
350
+ if (!dragState) return;
351
+ if (dragState.fromGroupId !== targetGroupId) return;
352
+ if (dragState.rowId === targetRowId) return;
353
+
354
+ const group = groups.find((g) => g.id === targetGroupId);
355
+ if (!group) return;
356
+
357
+ const rows = group.rows.slice();
358
+ const fromIdx = rows.findIndex((r) => r.id === dragState.rowId);
359
+ const toIdx = rows.findIndex((r) => r.id === targetRowId);
360
+
361
+ if (fromIdx < 0 || toIdx < 0) return;
362
+
363
+ const moving = rows[fromIdx];
364
+ rows.splice(fromIdx, 1);
365
+ rows.splice(toIdx, 0, moving);
366
+
367
+ updateGroups(
368
+ groups.map((g) =>
369
+ g.id === targetGroupId ? { ...g, rows } : g,
370
+ ),
371
+ );
372
+
373
+ setDragState(null);
374
+ setDragOverRowId(null);
375
+ },
376
+ [dragState, groups, updateGroups],
377
+ );
378
+
379
+ const structureItems = React.useMemo<StructureItem[]>(() => {
380
+ return groups.flatMap((group) => [
381
+ { kind: 'group' as const, group },
382
+ ...group.rows.map((row, rowIndex) => ({
383
+ kind: 'row' as const,
384
+ group,
385
+ row,
386
+ rowIndex,
387
+ })),
388
+ ]);
389
+ }, [groups]);
390
+
391
+ const mappingPreview = React.useMemo(() => buildMappingPreview(groups), [groups]);
392
+
393
+ return (
394
+ <div className={styles.designWorkspace}>
395
+ <div style={{ marginBottom: '1rem' }}>
396
+ <h3 className={styles.workspaceTitle}>{t('reportDesign', 'Report Design')}</h3>
397
+ <p className={styles.workspaceHint}>
398
+ {t(
399
+ 'reportDesignHint',
400
+ 'Design the report structure, indicator presentation, JSON template, and mapping preview.',
401
+ )}
402
+ </p>
403
+ </div>
404
+
405
+ {!definitionDraft ? (
406
+ <InlineNotification
407
+ kind="warning"
408
+ lowContrast
409
+ title="Definition required"
410
+ subtitle="Build the report definition first so the design can align to it."
411
+ />
412
+ ) : null}
413
+
414
+ <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
415
+ <Button
416
+ size="sm"
417
+ kind="primary"
418
+ onClick={generateFromDefinition}
419
+ disabled={!sectionSources.length}
420
+ >
421
+ Generate From Definition
422
+ </Button>
423
+ </div>
424
+
425
+ <div
426
+ style={{
427
+ border: '1px solid var(--cds-border-subtle, #d0d0d0)',
428
+ borderRadius: 12,
429
+ padding: '1rem',
430
+ background: '#fff',
431
+ }}
432
+ >
433
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
434
+ <div style={{ display: 'grid', gridTemplateRows: 'auto auto', gap: '1rem' }}>
435
+ <div
436
+ style={{
437
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
438
+ borderRadius: 10,
439
+ padding: '1rem',
440
+ background: 'var(--cds-layer, #f4f4f4)',
441
+ }}
442
+ >
443
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
444
+ <div style={{ fontSize: '1.1rem', fontWeight: 600 }}>Template Structure</div>
445
+ <Button kind="ghost" size="sm" renderIcon={Renew} onClick={generateFromDefinition}>
446
+ Refresh JSON
447
+ </Button>
448
+ </div>
449
+
450
+ <div
451
+ style={{
452
+ minHeight: '12rem',
453
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
454
+ borderRadius: 8,
455
+ background: '#fff',
456
+ padding: '0.5rem',
457
+ overflow: 'auto',
458
+ }}
459
+ >
460
+ {structureItems.length === 0 ? (
461
+ <div style={{ opacity: 0.7 }}>No sections/rows yet. Generate from definition.</div>
462
+ ) : (
463
+ structureItems.map((item) => {
464
+ if (item.kind === 'group') {
465
+ return null;
466
+ }
467
+
468
+ const { group, row, rowIndex } = item;
469
+ const isSelected = row.id === selectedRowId;
470
+ const isDragOver = row.id === dragOverRowId;
471
+
472
+ const isSectionLabel = row.type === ('section-label' as any);
473
+ const isGroupLabel = row.type === ('group-label' as any);
474
+
475
+ return (
476
+ <div
477
+ key={row.id}
478
+ draggable
479
+ onDragStart={() => handleDragStart(row.id, group.id)}
480
+ onDragEnd={() => {
481
+ setDragState(null);
482
+ setDragOverRowId(null);
483
+ }}
484
+ onDragOver={(e) => {
485
+ e.preventDefault();
486
+ setDragOverRowId(row.id);
487
+ }}
488
+ onDrop={(e) => {
489
+ e.preventDefault();
490
+ handleDropOnRow(group.id, row.id);
491
+ }}
492
+ onClick={() => {
493
+ setSelectedGroupId(group.id);
494
+ setSelectedRowId(row.id);
495
+ }}
496
+ style={{
497
+ display: 'flex',
498
+ alignItems: 'center',
499
+ gap: '0.5rem',
500
+ padding: '0.65rem 0.75rem',
501
+ marginBottom: '0.35rem',
502
+ marginLeft: `${(row.indent ?? 0) * 18}px`,
503
+ borderRadius: 6,
504
+ border: isSelected
505
+ ? '2px solid var(--cds-border-interactive, #0f62fe)'
506
+ : isDragOver
507
+ ? '2px dashed var(--cds-border-interactive, #0f62fe)'
508
+ : '1px solid transparent',
509
+ background: isSelected ? 'var(--cds-layer-selected, #e8f1ff)' : 'transparent',
510
+ cursor: 'pointer',
511
+ }}
512
+ >
513
+ <Draggable size={16} />
514
+ <span
515
+ style={{
516
+ fontWeight: isSectionLabel ? 700 : isGroupLabel ? 600 : 500,
517
+ }}
518
+ >
519
+ {row.label || row.code || 'Untitled row'}
520
+ </span>
521
+
522
+ <Tag
523
+ size="sm"
524
+ type={
525
+ isSectionLabel
526
+ ? 'purple'
527
+ : isGroupLabel
528
+ ? 'cyan'
529
+ : 'gray'
530
+ }
531
+ >
532
+ {isSectionLabel
533
+ ? 'section'
534
+ : isGroupLabel
535
+ ? 'group'
536
+ : row.code || row.type}
537
+ </Tag>
538
+
539
+ {isSectionLabel ? (
540
+ <Button
541
+ size="sm"
542
+ kind="ghost"
543
+ renderIcon={Add}
544
+ onClick={(e) => {
545
+ e.stopPropagation();
546
+ addRowToGroup(group.id);
547
+ }}
548
+ >
549
+ Add Node
550
+ </Button>
551
+ ) : null}
552
+
553
+ <div style={{ marginLeft: 'auto', display: 'flex', gap: '0.25rem' }}>
554
+ <Button
555
+ kind="ghost"
556
+ size="sm"
557
+ hasIconOnly
558
+ iconDescription="Move up"
559
+ renderIcon={ArrowUp}
560
+ disabled={rowIndex === 0}
561
+ onClick={(e) => {
562
+ e.stopPropagation();
563
+ moveRow(group.id, row.id, -1);
564
+ }}
565
+ />
566
+ <Button
567
+ kind="ghost"
568
+ size="sm"
569
+ hasIconOnly
570
+ iconDescription="Move down"
571
+ renderIcon={ArrowDown}
572
+ disabled={rowIndex === group.rows.length - 1}
573
+ onClick={(e) => {
574
+ e.stopPropagation();
575
+ moveRow(group.id, row.id, 1);
576
+ }}
577
+ />
578
+ <Button
579
+ kind="ghost"
580
+ size="sm"
581
+ hasIconOnly
582
+ iconDescription="Indent"
583
+ renderIcon={ArrowRight}
584
+ disabled={(row.indent ?? getMinIndentForRowType(row.type)) >= MAX_INDENT}
585
+ onClick={(e) => {
586
+ e.stopPropagation();
587
+ indentRow(group.id, row.id, 1);
588
+ }}
589
+ />
590
+ <Button
591
+ kind="ghost"
592
+ size="sm"
593
+ hasIconOnly
594
+ iconDescription="Outdent"
595
+ renderIcon={ArrowLeft}
596
+ disabled={(row.indent ?? getMinIndentForRowType(row.type)) <= getMinIndentForRowType(row.type)}
597
+ onClick={(e) => {
598
+ e.stopPropagation();
599
+ indentRow(group.id, row.id, -1);
600
+ }}
601
+ />
602
+ <Button
603
+ kind="ghost"
604
+ size="sm"
605
+ hasIconOnly
606
+ iconDescription="Remove"
607
+ renderIcon={TrashCan}
608
+ onClick={(e) => {
609
+ e.stopPropagation();
610
+ removeRow(group.id, row.id);
611
+ }}
612
+ />
613
+ </div>
614
+ </div>
615
+ );
616
+ })
617
+ )}
618
+ </div>
619
+ </div>
620
+
621
+ <div
622
+ style={{
623
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
624
+ borderRadius: 10,
625
+ padding: '1rem',
626
+ background: '#fff',
627
+ }}
628
+ >
629
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
630
+ <div style={{ fontSize: '1.1rem', fontWeight: 600 }}>JSON Preview</div>
631
+ <div style={{ display: 'flex', gap: '0.35rem' }}>
632
+ <Button kind="ghost" hasIconOnly size="sm" iconDescription="Refresh" renderIcon={Renew} />
633
+ <Button kind="ghost" hasIconOnly size="sm" iconDescription="Copy" renderIcon={Copy} />
634
+ <Button kind="ghost" hasIconOnly size="sm" iconDescription="Download" renderIcon={Download} />
635
+ <Button kind="ghost" hasIconOnly size="sm" iconDescription="Expand" renderIcon={Launch} />
636
+ </div>
637
+ </div>
638
+
639
+ <pre
640
+ style={{
641
+ margin: 0,
642
+ minHeight: '16rem',
643
+ maxHeight: '22rem',
644
+ overflow: 'auto',
645
+ whiteSpace: 'pre-wrap',
646
+ wordBreak: 'break-word',
647
+ fontSize: '0.85rem',
648
+ background: '#f8f8f8',
649
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
650
+ borderRadius: 8,
651
+ padding: '0.75rem',
652
+ }}
653
+ >
654
+ {JSON.stringify(draft, null, 2)}
655
+ </pre>
656
+ </div>
657
+ </div>
658
+
659
+ <div style={{ display: 'grid', gridTemplateRows: 'auto auto', gap: '1rem' }}>
660
+ <div
661
+ style={{
662
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
663
+ borderRadius: 10,
664
+ padding: '1rem',
665
+ background: 'var(--cds-layer, #f4f4f4)',
666
+ }}
667
+ >
668
+ <div style={{ fontSize: '1.1rem', fontWeight: 600 }}>Indicator Properties</div>
669
+ <div style={{ opacity: 0.8, marginBottom: '0.75rem' }}>
670
+ Select an indicator/row to edit properties
671
+ </div>
672
+
673
+ <Tabs
674
+ selectedIndex={
675
+ propTab === 'details' ? 0 : propTab === 'disaggregation' ? 1 : propTab === 'mapping' ? 2 : 3
676
+ }
677
+ onChange={({ selectedIndex }) =>
678
+ setPropTab(selectedIndex === 0 ? 'details' : selectedIndex === 1 ? 'disaggregation' : selectedIndex === 2 ? 'mapping' : 'api')
679
+ }
680
+ >
681
+ <TabList aria-label="Indicator properties tabs">
682
+ <Tab>Details</Tab>
683
+ <Tab>Disaggregation</Tab>
684
+ <Tab>Mapping</Tab>
685
+ <Tab>API</Tab>
686
+ </TabList>
687
+ </Tabs>
688
+
689
+ <div style={{ marginTop: '1rem' }}>
690
+ {!selectedRow || !selectedGroupId ? (
691
+ <div style={{ opacity: 0.7 }}>Select a node to edit.</div>
692
+ ) : propTab === 'details' ? (
693
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
694
+ <TextInput
695
+ id="design-row-label"
696
+ labelText="Label"
697
+ value={selectedRow.label}
698
+ onChange={(e) =>
699
+ updateRow(selectedGroupId, selectedRow.id, { label: (e.target as HTMLInputElement).value })
700
+ }
701
+ />
702
+ <TextInput
703
+ id="design-row-code"
704
+ labelText="Code"
705
+ value={selectedRow.code ?? ''}
706
+ onChange={(e) =>
707
+ updateRow(selectedGroupId, selectedRow.id, { code: (e.target as HTMLInputElement).value })
708
+ }
709
+ />
710
+ <Select
711
+ id="design-row-type"
712
+ labelText="Row type"
713
+ value={selectedRow.type}
714
+ onChange={(e) => {
715
+ const nextType = (e.target as HTMLSelectElement).value;
716
+ const nextRow = applyRowTypeDefaults(selectedRow, nextType);
717
+ updateRow(selectedGroupId, selectedRow.id, nextRow);
718
+ }}
719
+ >
720
+ <SelectItem value="section-label" text="Section Label" />
721
+ <SelectItem value="group-label" text="Group Label" />
722
+ <SelectItem value="indicator" text="Indicator" />
723
+ <SelectItem value="label" text="Label" />
724
+ <SelectItem value="spacer" text="Spacer" />
725
+ </Select>
726
+ <NumberInput
727
+ id="design-row-indent"
728
+ label="Indent"
729
+ min={getMinIndentForRowType(selectedRow.type)}
730
+ max={MAX_INDENT}
731
+ value={selectedRow.indent ?? getMinIndentForRowType(selectedRow.type)}
732
+ onChange={(e) => {
733
+ const next = Number((e.target as HTMLInputElement).value || getMinIndentForRowType(selectedRow.type));
734
+ updateRow(selectedGroupId, selectedRow.id, {
735
+ indent: clampIndentForRowType(next, selectedRow.type),
736
+ });
737
+ }}
738
+ />
739
+ </div>
740
+ ) : propTab === 'disaggregation' ? (
741
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
742
+ <Checkbox
743
+ id="design-row-total"
744
+ labelText="Show total"
745
+ checked={Boolean(selectedRow.showTotal)}
746
+ onChange={(checked) =>
747
+ updateRow(selectedGroupId, selectedRow.id, { showTotal: Boolean(checked) })
748
+ }
749
+ />
750
+ <Checkbox
751
+ id="design-row-disagg"
752
+ labelText="Show disaggregation"
753
+ checked={Boolean(selectedRow.showDisaggregation)}
754
+ onChange={(checked) =>
755
+ updateRow(selectedGroupId, selectedRow.id, { showDisaggregation: Boolean(checked) })
756
+ }
757
+ />
758
+ </div>
759
+ ) : propTab === 'mapping' ? (
760
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
761
+ <TextInput
762
+ id="design-row-key-pattern"
763
+ labelText="Key pattern"
764
+ value={selectedRow.keyPattern ?? ''}
765
+ onChange={(e) =>
766
+ updateRow(selectedGroupId, selectedRow.id, { keyPattern: (e.target as HTMLInputElement).value })
767
+ }
768
+ />
769
+ <div style={{ opacity: 0.8, fontSize: '0.875rem' }}>
770
+ Example: {'{code}_{age}_{sex}'}
771
+ </div>
772
+ </div>
773
+ ) : (
774
+ <div style={{ opacity: 0.8, fontSize: '0.875rem' }}>
775
+ Node API preview and compile-time bindings will appear here.
776
+ </div>
777
+ )}
778
+ </div>
779
+ </div>
780
+
781
+ <div
782
+ style={{
783
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
784
+ borderRadius: 10,
785
+ padding: '1rem',
786
+ background: 'var(--cds-layer, #f4f4f4)',
787
+ }}
788
+ >
789
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
790
+ <div style={{ fontSize: '1.1rem', fontWeight: 600 }}>Mapping Preview</div>
791
+ <View size={18} />
792
+ </div>
793
+
794
+ <div
795
+ style={{
796
+ border: '1px solid var(--cds-border-subtle, #e0e0e0)',
797
+ borderRadius: 8,
798
+ overflow: 'hidden',
799
+ background: '#fff',
800
+ }}
801
+ >
802
+ <div
803
+ style={{
804
+ display: 'grid',
805
+ gridTemplateColumns: `minmax(220px, 1.3fr) repeat(${mappingPreview.columns.length}, minmax(120px, 1fr))`,
806
+ borderBottom: '1px solid var(--cds-border-subtle, #e0e0e0)',
807
+ fontWeight: 600,
808
+ background: '#fafafa',
809
+ }}
810
+ >
811
+ <div style={{ padding: '0.75rem' }} />
812
+ {mappingPreview.columns.map((c) => (
813
+ <div key={c} style={{ padding: '0.75rem' }}>
814
+ {c}
815
+ </div>
816
+ ))}
817
+ </div>
818
+
819
+ {mappingPreview.rows.length === 0 ? (
820
+ <div style={{ padding: '1rem', opacity: 0.7 }}>No rows to preview.</div>
821
+ ) : (
822
+ mappingPreview.rows.map((row: any) =>
823
+ row.type === 'section-label' ? (
824
+ <div
825
+ key={row.id}
826
+ style={{
827
+ borderTop: '1px solid var(--cds-border-subtle, #f0f0f0)',
828
+ background: 'var(--cds-layer-accent, #f4f4f4)',
829
+ fontWeight: 700,
830
+ padding: '0.85rem 0.75rem',
831
+ }}
832
+ >
833
+ {row.label}
834
+ </div>
835
+ ) : row.type === 'group-label' ? (
836
+ <div
837
+ key={row.id}
838
+ style={{
839
+ display: 'grid',
840
+ gridTemplateColumns: `minmax(220px, 1.3fr) repeat(${mappingPreview.columns.length}, minmax(120px, 1fr))`,
841
+ borderTop: '1px solid var(--cds-border-subtle, #f0f0f0)',
842
+ background: '#fafafa',
843
+ }}
844
+ >
845
+ <div
846
+ style={{
847
+ padding: '0.75rem',
848
+ fontWeight: 600,
849
+ paddingLeft: `${12 + row.indent * 18}px`,
850
+ }}
851
+ >
852
+ {row.code ? `${row.code} ${row.label}` : row.label}
853
+ </div>
854
+ {mappingPreview.columns.map((_: any, idx: number) => (
855
+ <div key={idx} style={{ padding: '0.75rem' }} />
856
+ ))}
857
+ </div>
858
+ ) : (
859
+ <div
860
+ key={row.id}
861
+ style={{
862
+ display: 'grid',
863
+ gridTemplateColumns: `minmax(220px, 1.3fr) repeat(${mappingPreview.columns.length}, minmax(120px, 1fr))`,
864
+ borderTop: '1px solid var(--cds-border-subtle, #f0f0f0)',
865
+ }}
866
+ >
867
+ <div
868
+ style={{
869
+ padding: '0.75rem',
870
+ fontWeight: 600,
871
+ paddingLeft: `${12 + row.indent * 18}px`,
872
+ }}
873
+ >
874
+ {row.label}
875
+ </div>
876
+ {row.values.map((v: any, idx: number) => (
877
+ <div key={idx} style={{ padding: '0.75rem' }}>
878
+ {v}
879
+ </div>
880
+ ))}
881
+ </div>
882
+ ),
883
+ )
884
+ )}
885
+ </div>
886
+ </div>
887
+ </div>
888
+ </div>
889
+ </div>
890
+ </div>
891
+ );
892
+ };
893
+
894
+ export default ReportDesignEditor;