@openmrs/esm-patient-tests-app 11.3.1-patch.9064 → 11.3.1-patch.9508
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +22 -22
- package/dist/1119.js +1 -1
- package/dist/1197.js +1 -1
- package/dist/{6231.js → 1477.js} +1 -1
- package/dist/1477.js.map +1 -0
- package/dist/1638.js +1 -1
- package/dist/1638.js.map +1 -1
- package/dist/1935.js +1 -1
- package/dist/1935.js.map +1 -1
- package/dist/2146.js +1 -1
- package/dist/2690.js +1 -1
- package/dist/3099.js +1 -1
- package/dist/34.js +1 -1
- package/dist/34.js.map +1 -1
- package/dist/3509.js +1 -1
- package/dist/3509.js.map +1 -1
- package/dist/3584.js +1 -1
- package/dist/4055.js +1 -1
- package/dist/4132.js +1 -1
- package/dist/4300.js +1 -1
- package/dist/4335.js +1 -1
- package/dist/439.js +1 -0
- package/dist/4618.js +1 -1
- package/dist/4652.js +1 -1
- package/dist/4944.js +1 -1
- package/dist/5173.js +1 -1
- package/dist/5241.js +1 -1
- package/dist/5442.js +1 -1
- package/dist/5661.js +1 -1
- package/dist/5670.js +1 -1
- package/dist/5670.js.map +1 -1
- package/dist/6022.js +1 -1
- package/dist/6113.js +1 -0
- package/dist/6113.js.map +1 -0
- package/dist/6301.js +1 -1
- package/dist/6301.js.map +1 -1
- package/dist/6336.js +1 -0
- package/dist/6336.js.map +1 -0
- package/dist/6468.js +1 -1
- package/dist/6589.js +1 -0
- package/dist/6679.js +1 -1
- package/dist/6840.js +1 -1
- package/dist/6859.js +1 -1
- package/dist/7097.js +1 -1
- package/dist/7159.js +1 -1
- package/dist/7202.js +1 -0
- package/dist/7202.js.map +1 -0
- package/dist/723.js +1 -1
- package/dist/7617.js +1 -1
- package/dist/790.js +1 -1
- package/dist/790.js.map +1 -1
- package/dist/795.js +1 -1
- package/dist/8163.js +1 -1
- package/dist/8307.js +2 -0
- package/dist/8307.js.map +1 -0
- package/dist/8349.js +1 -1
- package/dist/8371.js +1 -0
- package/dist/8555.js +2 -0
- package/dist/8555.js.map +1 -0
- package/dist/8618.js +1 -1
- package/dist/890.js +1 -1
- package/dist/9214.js +1 -1
- package/dist/9538.js +1 -1
- package/dist/9569.js +1 -1
- package/dist/986.js +1 -1
- package/dist/9879.js +1 -1
- package/dist/9895.js +1 -1
- package/dist/9900.js +1 -1
- package/dist/9913.js +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-patient-tests-app.js +1 -1
- package/dist/openmrs-esm-patient-tests-app.js.buildmanifest.json +319 -249
- package/dist/openmrs-esm-patient-tests-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +3 -3
- package/src/edit-test-results/modal/edit-lab-results.modal.tsx +6 -2
- package/src/index.ts +1 -1
- package/src/routes.json +2 -2
- package/src/test-orders/add-test-order/add-test-order.test.tsx +13 -10
- package/src/test-orders/add-test-order/add-test-order.workspace.tsx +43 -7
- package/src/test-orders/add-test-order/test-order-form.component.tsx +41 -7
- package/src/test-orders/add-test-order/test-type-search.component.tsx +56 -8
- package/src/test-orders/lab-order-basket-panel/lab-icon.component.tsx +27 -0
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.extension.tsx +62 -15
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.scss +26 -11
- package/src/test-orders/lab-order-basket-panel/lab-order-basket-panel.test.tsx +18 -5
- package/src/test-results/filter/filter-context.test.tsx +556 -0
- package/src/test-results/filter/filter-context.tsx +1 -1
- package/src/test-results/filter/filter-reducer.test.ts +540 -0
- package/src/test-results/filter/filter-reducer.ts +1 -1
- package/src/test-results/filter/filter-set.component.tsx +75 -48
- package/src/test-results/filter/filter-set.test.tsx +694 -0
- package/src/test-results/filter/filter-types.ts +24 -1
- package/src/test-results/grouped-timeline/grid.component.tsx +4 -2
- package/src/test-results/grouped-timeline/grouped-timeline.component.tsx +20 -22
- package/src/test-results/grouped-timeline/grouped-timeline.test.tsx +52 -2
- package/src/test-results/grouped-timeline/reference-range-helpers.test.ts +308 -0
- package/src/test-results/grouped-timeline/reference-range-helpers.ts +161 -0
- package/src/test-results/grouped-timeline/timeline-data-group.component.tsx +13 -6
- package/src/test-results/grouped-timeline/useObstreeData.test.ts +471 -0
- package/src/test-results/grouped-timeline/useObstreeData.ts +108 -13
- package/src/test-results/individual-results-table/individual-results-table.component.tsx +18 -6
- package/src/test-results/individual-results-table/individual-results-table.test.tsx +65 -3
- package/src/test-results/individual-results-table-tablet/helper.tsx +8 -2
- package/src/test-results/individual-results-table-tablet/individual-results-table-tablet.component.tsx +5 -5
- package/src/test-results/individual-results-table-tablet/lab-set-panel.component.tsx +2 -1
- package/src/test-results/individual-results-table-tablet/usePanelData.tsx +40 -26
- package/src/test-results/loadPatientTestData/helpers.test.ts +834 -0
- package/src/test-results/loadPatientTestData/helpers.ts +143 -12
- package/src/test-results/loadPatientTestData/loadPatientData.ts +66 -11
- package/src/test-results/loadPatientTestData/usePatientResultsData.ts +20 -9
- package/src/test-results/overview/common-datatable.component.tsx +1 -1
- package/src/test-results/overview/external-overview.extension.tsx +1 -2
- package/src/test-results/overview/useOverviewData.ts +22 -10
- package/src/test-results/print-modal/print-modal.extension.tsx +1 -1
- package/src/test-results/results-viewer/results-viewer.extension.tsx +12 -7
- package/src/test-results/tree-view/tree-view.component.tsx +31 -8
- package/src/test-results/tree-view/tree-view.test.tsx +119 -2
- package/src/test-results/trendline/trendline-resource.tsx +48 -5
- package/src/test-results/trendline/trendline.component.tsx +88 -52
- package/src/test-results/ui-elements/{resetFiltersEmptyState → reset-filters-empty-state}/filter-empty-data-illustration.tsx +2 -2
- package/src/test-results/ui-elements/{resetFiltersEmptyState → reset-filters-empty-state}/filter-empty-state.component.tsx +5 -6
- package/src/types.ts +20 -1
- package/translations/am.json +3 -4
- package/translations/ar.json +3 -4
- package/translations/ar_SY.json +3 -4
- package/translations/bn.json +3 -4
- package/translations/cs.json +119 -0
- package/translations/de.json +3 -4
- package/translations/en.json +3 -2
- package/translations/en_US.json +3 -4
- package/translations/es.json +3 -4
- package/translations/es_MX.json +3 -4
- package/translations/fr.json +5 -6
- package/translations/he.json +3 -4
- package/translations/hi.json +3 -4
- package/translations/hi_IN.json +3 -4
- package/translations/id.json +3 -4
- package/translations/it.json +3 -4
- package/translations/ka.json +3 -4
- package/translations/km.json +3 -4
- package/translations/ku.json +3 -4
- package/translations/ky.json +3 -4
- package/translations/lg.json +3 -4
- package/translations/ne.json +3 -4
- package/translations/pl.json +3 -4
- package/translations/pt.json +3 -4
- package/translations/pt_BR.json +3 -4
- package/translations/qu.json +3 -4
- package/translations/ro_RO.json +3 -4
- package/translations/ru_RU.json +3 -4
- package/translations/si.json +3 -4
- package/translations/sq.json +119 -0
- package/translations/sw.json +3 -4
- package/translations/sw_KE.json +3 -4
- package/translations/tr.json +3 -4
- package/translations/tr_TR.json +3 -4
- package/translations/uk.json +3 -4
- package/translations/uz.json +3 -4
- package/translations/uz@Latn.json +3 -4
- package/translations/uz_UZ.json +3 -4
- package/translations/vi.json +3 -4
- package/translations/zh.json +3 -4
- package/translations/zh_CN.json +3 -4
- package/translations/zh_TW.json +119 -0
- package/dist/1479.js +0 -1
- package/dist/1479.js.map +0 -1
- package/dist/2537.js +0 -1
- package/dist/2537.js.map +0 -1
- package/dist/4918.js +0 -1
- package/dist/4918.js.map +0 -1
- package/dist/5836.js +0 -2
- package/dist/5836.js.map +0 -1
- package/dist/6231.js.map +0 -1
- package/dist/7053.js +0 -2
- package/dist/7053.js.map +0 -1
- /package/dist/{7053.js.LICENSE.txt → 8307.js.LICENSE.txt} +0 -0
- /package/dist/{5836.js.LICENSE.txt → 8555.js.LICENSE.txt} +0 -0
- /package/src/test-results/ui-elements/{resetFiltersEmptyState/index.scss → reset-filters-empty-state/filter-empty-state.scss} +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import React, { useContext,
|
|
2
|
-
import { useTranslation } from 'react-i18next';
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react';
|
|
3
2
|
import classNames from 'classnames';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Accordion, AccordionItem, Button, Checkbox } from '@carbon/react';
|
|
5
5
|
import { useConfig, useLayoutType } from '@openmrs/esm-framework';
|
|
6
6
|
import { type ConfigObject } from '../../config-schema';
|
|
7
7
|
import type { FilterNodeProps, FilterLeafProps } from './filter-types';
|
|
8
|
-
import
|
|
8
|
+
import FilterEmptyState from '../ui-elements/reset-filters-empty-state/filter-empty-state.component';
|
|
9
9
|
import FilterContext from './filter-context';
|
|
10
10
|
import styles from './filter-set.scss';
|
|
11
11
|
|
|
12
|
-
const isIndeterminate = (kids,
|
|
12
|
+
const isIndeterminate = (kids: Array<string>, checkboxes: Record<string, boolean>) => {
|
|
13
13
|
return kids && !kids?.every((kid) => checkboxes[kid]) && !kids?.every((kid) => !checkboxes[kid]);
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -17,65 +17,87 @@ interface FilterSetProps {
|
|
|
17
17
|
hideFilterSetHeader?: boolean;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
interface
|
|
20
|
+
interface FilterNodeParentProps extends Pick<FilterNodeProps, 'root'> {
|
|
21
21
|
itemNumber: number;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function filterTreeNode(inputValue, treeNode) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
treeNode &&
|
|
28
|
-
(treeNode.display.toLowerCase().includes(inputValue.toLowerCase()) ||
|
|
29
|
-
(treeNode.subSets && treeNode.subSets.some((child) => filterTreeNode(inputValue, child))))
|
|
30
|
-
) {
|
|
31
|
-
return true;
|
|
24
|
+
function filterTreeNode(inputValue: string, treeNode: any): boolean {
|
|
25
|
+
if (!treeNode) {
|
|
26
|
+
return false;
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
const matchesSearch = treeNode.display.toLowerCase().includes(inputValue.toLowerCase());
|
|
30
|
+
const childMatches = treeNode.subSets?.some((child) => filterTreeNode(inputValue, child)) ?? false;
|
|
31
|
+
|
|
32
|
+
return matchesSearch || childMatches;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
const FilterSet: React.FC<FilterSetProps> = () => {
|
|
39
36
|
const { roots } = useContext(FilterContext);
|
|
37
|
+
const config = useConfig<ConfigObject>();
|
|
40
38
|
const [searchTerm, setSearchTerm] = useState('');
|
|
41
39
|
const [treeDataFiltered, setTreeDataFiltered] = useState(roots);
|
|
42
40
|
|
|
43
41
|
useEffect(() => {
|
|
44
|
-
|
|
42
|
+
const configuredConceptUuids = config?.resultsViewerConcepts?.map((c) => c.conceptUuid) ?? [];
|
|
43
|
+
|
|
44
|
+
// Helper to check if a node or its children match configured concepts
|
|
45
|
+
const isConfiguredNode = (node: any): boolean => {
|
|
46
|
+
// Check if the node itself has a matching conceptUuid
|
|
47
|
+
if (node.conceptUuid && configuredConceptUuids.includes(node.conceptUuid)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// Check if any direct child has a matching conceptUuid
|
|
51
|
+
return (
|
|
52
|
+
node.subSets?.some((child: any) => child.conceptUuid && configuredConceptUuids.includes(child.conceptUuid)) ??
|
|
53
|
+
false
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Filter the tree data, ensuring only parent categories (with subSets) are at root level
|
|
45
58
|
const filteredData = (roots as any[]).filter((node) => {
|
|
46
|
-
// Only include nodes that are parent categories
|
|
47
|
-
if (!node.subSets || !Array.isArray(node.subSets)
|
|
48
|
-
return false;
|
|
59
|
+
// Only include nodes that have subSets (are parent categories)
|
|
60
|
+
if (!node.subSets || !Array.isArray(node.subSets)) {
|
|
61
|
+
return false;
|
|
49
62
|
}
|
|
63
|
+
|
|
64
|
+
// Keep configured concepts even if they have no children after filtering
|
|
65
|
+
const isConfiguredConcept = isConfiguredNode(node);
|
|
66
|
+
if (node.subSets.length === 0 && !isConfiguredConcept) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Apply search filter
|
|
50
71
|
return filterTreeNode(searchTerm, node);
|
|
51
72
|
});
|
|
73
|
+
|
|
52
74
|
setTreeDataFiltered(filteredData);
|
|
53
|
-
}, [searchTerm, roots]);
|
|
75
|
+
}, [searchTerm, roots, config]);
|
|
54
76
|
|
|
55
77
|
return (
|
|
56
|
-
<div>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
)}
|
|
67
|
-
</div>
|
|
78
|
+
<div className={styles.filterSetContent}>
|
|
79
|
+
{treeDataFiltered?.length > 0 ? (
|
|
80
|
+
treeDataFiltered?.map((root, index) => (
|
|
81
|
+
<div className={`${styles.nestedAccordion} ${styles.nestedAccordionTablet}`} key={`filter-node-${index}`}>
|
|
82
|
+
<FilterNodeParent root={root} itemNumber={index} />
|
|
83
|
+
</div>
|
|
84
|
+
))
|
|
85
|
+
) : (
|
|
86
|
+
<FilterEmptyState clearFilter={() => setSearchTerm('')} />
|
|
87
|
+
)}
|
|
68
88
|
</div>
|
|
69
89
|
);
|
|
70
90
|
};
|
|
71
91
|
|
|
72
|
-
const FilterNodeParent = ({ root, itemNumber }:
|
|
92
|
+
const FilterNodeParent = ({ root, itemNumber }: FilterNodeParentProps) => {
|
|
73
93
|
const config = useConfig<ConfigObject>();
|
|
74
94
|
const { t } = useTranslation();
|
|
75
95
|
const tablet = useLayoutType() === 'tablet';
|
|
76
96
|
const [expandAll, setExpandAll] = useState<boolean | undefined>(undefined);
|
|
77
97
|
|
|
78
|
-
if (!root.subSets)
|
|
98
|
+
if (!root.subSets) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
79
101
|
|
|
80
102
|
const filterParent = root.subSets.map((node, key) => {
|
|
81
103
|
// If node has obs data, it's a leaf - render as FilterLeaf
|
|
@@ -88,7 +110,7 @@ const FilterNodeParent = ({ root, itemNumber }: filterNodeParentProps) => {
|
|
|
88
110
|
}
|
|
89
111
|
|
|
90
112
|
// If node has subSets, it's a parent - render as FilterNode
|
|
91
|
-
if (node?.subSets && Array.isArray(node.subSets)
|
|
113
|
+
if (node?.subSets && Array.isArray(node.subSets)) {
|
|
92
114
|
return (
|
|
93
115
|
<div key={key}>
|
|
94
116
|
<FilterNode
|
|
@@ -108,18 +130,22 @@ const FilterNodeParent = ({ root, itemNumber }: filterNodeParentProps) => {
|
|
|
108
130
|
);
|
|
109
131
|
});
|
|
110
132
|
|
|
133
|
+
const hasChildren = root.subSets && root.subSets.length > 0;
|
|
134
|
+
|
|
111
135
|
return (
|
|
112
136
|
<div>
|
|
113
137
|
<div className={classNames(styles.treeNodeHeader, { [styles.treeNodeHeaderTablet]: tablet })}>
|
|
114
138
|
<h5>{t(root.display)}</h5>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
139
|
+
{hasChildren && (
|
|
140
|
+
<Button
|
|
141
|
+
className={styles.button}
|
|
142
|
+
kind="ghost"
|
|
143
|
+
size={tablet ? 'md' : 'sm'}
|
|
144
|
+
onClick={() => setExpandAll((prevValue) => !prevValue)}
|
|
145
|
+
>
|
|
146
|
+
<span>{expandAll ? t('collapseAll', 'Collapse all') : t('expandAll', 'Expand all')}</span>
|
|
147
|
+
</Button>
|
|
148
|
+
)}
|
|
123
149
|
</div>
|
|
124
150
|
{filterParent}
|
|
125
151
|
</div>
|
|
@@ -134,11 +160,11 @@ const FilterNode = ({ root, level, open }: FilterNodeProps) => {
|
|
|
134
160
|
|
|
135
161
|
// Determine if this is a parent (has children) or leaf (individual test)
|
|
136
162
|
const isParent = parents[root.flatName] && parents[root.flatName].length > 0;
|
|
137
|
-
const isLeaf = !isParent;
|
|
138
163
|
|
|
139
164
|
return (
|
|
140
165
|
<Accordion align="start" size={tablet ? 'md' : 'sm'}>
|
|
141
166
|
<AccordionItem
|
|
167
|
+
disabled={!root.hasData}
|
|
142
168
|
title={
|
|
143
169
|
<Checkbox
|
|
144
170
|
id={root?.flatName}
|
|
@@ -156,11 +182,8 @@ const FilterNode = ({ root, level, open }: FilterNodeProps) => {
|
|
|
156
182
|
{/* If this node has obs data, it's a leaf - render as FilterLeaf */}
|
|
157
183
|
{root?.obs && Array.isArray(root.obs) && root.obs.length > 0 ? (
|
|
158
184
|
<FilterLeaf leaf={root} />
|
|
159
|
-
) : (
|
|
185
|
+
) : root?.subSets && Array.isArray(root.subSets) && root.subSets.length > 0 ? (
|
|
160
186
|
/* If this node has subSets, it's a parent - recursively render children */
|
|
161
|
-
root?.subSets &&
|
|
162
|
-
Array.isArray(root.subSets) &&
|
|
163
|
-
root.subSets.length > 0 &&
|
|
164
187
|
root.subSets.map((child, index) => {
|
|
165
188
|
/* Check if child is a leaf (has obs) or parent (has subSets) */
|
|
166
189
|
if (child?.obs && Array.isArray(child.obs) && child.obs.length > 0) {
|
|
@@ -174,6 +197,9 @@ const FilterNode = ({ root, level, open }: FilterNodeProps) => {
|
|
|
174
197
|
return <FilterLeaf leaf={child} key={index} />;
|
|
175
198
|
}
|
|
176
199
|
})
|
|
200
|
+
) : (
|
|
201
|
+
/* Parent node with empty subSets - render empty div to maintain accordion structure */
|
|
202
|
+
<div />
|
|
177
203
|
)}
|
|
178
204
|
</AccordionItem>
|
|
179
205
|
</Accordion>
|
|
@@ -182,6 +208,7 @@ const FilterNode = ({ root, level, open }: FilterNodeProps) => {
|
|
|
182
208
|
|
|
183
209
|
const FilterLeaf = ({ leaf }: FilterLeafProps) => {
|
|
184
210
|
const { checkboxes, toggleVal } = useContext(FilterContext);
|
|
211
|
+
|
|
185
212
|
return (
|
|
186
213
|
<div className={styles.filterItem}>
|
|
187
214
|
<Checkbox
|