@openmrs/esm-cohort-builder-app 3.0.0
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/LICENSE +401 -0
- package/README.md +16 -0
- package/dist/130.js +2 -0
- package/dist/130.js.LICENSE.txt +9 -0
- package/dist/139.js +1 -0
- package/dist/247.js +1 -0
- package/dist/294.js +2 -0
- package/dist/294.js.LICENSE.txt +9 -0
- package/dist/434.js +2 -0
- package/dist/434.js.LICENSE.txt +12 -0
- package/dist/480.js +2 -0
- package/dist/480.js.LICENSE.txt +12 -0
- package/dist/484.js +1 -0
- package/dist/574.js +1 -0
- package/dist/595.js +2 -0
- package/dist/595.js.LICENSE.txt +3 -0
- package/dist/690.js +1 -0
- package/dist/873.js +1 -0
- package/dist/935.js +2 -0
- package/dist/935.js.LICENSE.txt +19 -0
- package/dist/964.js +2 -0
- package/dist/964.js.LICENSE.txt +14 -0
- package/dist/main.js +1 -0
- package/dist/openmrs-esm-cohort-builder-app.js +1 -0
- package/dist/openmrs-esm-cohort-builder-app.js.buildmanifest.json +426 -0
- package/dist/openmrs-esm-cohort-builder-app.old +1 -0
- package/package.json +99 -0
- package/src/cohort-builder-app-menu-link.tsx +14 -0
- package/src/cohort-builder.resources.ts +84 -0
- package/src/cohort-builder.scss +126 -0
- package/src/cohort-builder.test.tsx +12 -0
- package/src/cohort-builder.tsx +213 -0
- package/src/cohort-builder.utils.ts +197 -0
- package/src/components/composition/composition.component.tsx +109 -0
- package/src/components/composition/composition.style.css +3 -0
- package/src/components/composition/composition.test.tsx +112 -0
- package/src/components/composition/composition.utils.ts +53 -0
- package/src/components/empty-data/empty-data.component.tsx +25 -0
- package/src/components/empty-data/empty-data.style.scss +19 -0
- package/src/components/saved-cohorts/saved-cohorts-options/saved-cohort-options.test.tsx +49 -0
- package/src/components/saved-cohorts/saved-cohorts-options/saved-cohorts-options.component.tsx +112 -0
- package/src/components/saved-cohorts/saved-cohorts.component.tsx +139 -0
- package/src/components/saved-cohorts/saved-cohorts.resources.ts +39 -0
- package/src/components/saved-cohorts/saved-cohorts.scss +15 -0
- package/src/components/saved-cohorts/saved-cohorts.test.tsx +51 -0
- package/src/components/saved-queries/saved-queries-options/saved-queries-options.component.tsx +112 -0
- package/src/components/saved-queries/saved-queries-options/saved-queries-options.test.tsx +47 -0
- package/src/components/saved-queries/saved-queries.component.tsx +139 -0
- package/src/components/saved-queries/saved-queries.resources.ts +39 -0
- package/src/components/saved-queries/saved-queries.scss +23 -0
- package/src/components/saved-queries/saved-queries.test.tsx +50 -0
- package/src/components/search-button-set/search-button-set.css +9 -0
- package/src/components/search-button-set/search-button-set.test.tsx +26 -0
- package/src/components/search-button-set/search-button-set.tsx +47 -0
- package/src/components/search-by-concepts/search-by-concepts.component.tsx +344 -0
- package/src/components/search-by-concepts/search-by-concepts.style.scss +48 -0
- package/src/components/search-by-concepts/search-by-concepts.test.tsx +129 -0
- package/src/components/search-by-concepts/search-concept/search-concept.component.tsx +130 -0
- package/src/components/search-by-concepts/search-concept/search-concept.resource.ts +53 -0
- package/src/components/search-by-concepts/search-concept/search-concept.style.css +25 -0
- package/src/components/search-by-concepts/search-concept/search-concept.test.tsx +89 -0
- package/src/components/search-by-demographics/search-by-demographics.component.tsx +209 -0
- package/src/components/search-by-demographics/search-by-demographics.style.scss +41 -0
- package/src/components/search-by-demographics/search-by-demographics.test.tsx +92 -0
- package/src/components/search-by-demographics/search-by-demographics.utils.ts +129 -0
- package/src/components/search-by-drug-orders/search-by-drug-orders.component.tsx +185 -0
- package/src/components/search-by-drug-orders/search-by-drug-orders.resources.ts +60 -0
- package/src/components/search-by-drug-orders/search-by-drug-orders.style.scss +4 -0
- package/src/components/search-by-drug-orders/search-by-drug-orders.test.tsx +159 -0
- package/src/components/search-by-drug-orders/search-by-drug-orders.utils.ts +118 -0
- package/src/components/search-by-encounters/search-by-encounters.component.tsx +188 -0
- package/src/components/search-by-encounters/search-by-encounters.resources.ts +51 -0
- package/src/components/search-by-encounters/search-by-encounters.style.scss +12 -0
- package/src/components/search-by-encounters/search-by-encounters.test.tsx +202 -0
- package/src/components/search-by-encounters/search-by-encounters.utils.ts +113 -0
- package/src/components/search-by-enrollments/search-by-enrollments.component.tsx +183 -0
- package/src/components/search-by-enrollments/search-by-enrollments.resources.ts +31 -0
- package/src/components/search-by-enrollments/search-by-enrollments.style.scss +4 -0
- package/src/components/search-by-enrollments/search-by-enrollments.test.tsx +158 -0
- package/src/components/search-by-enrollments/search-by-enrollments.utils.ts +69 -0
- package/src/components/search-by-location/search-by-location.component.tsx +97 -0
- package/src/components/search-by-location/search-by-location.style.scss +4 -0
- package/src/components/search-by-location/search-by-location.test.tsx +110 -0
- package/src/components/search-by-location/search-by-location.utils.ts +40 -0
- package/src/components/search-by-person-attributes/search-by-person-attributes.component.tsx +90 -0
- package/src/components/search-by-person-attributes/search-by-person-attributes.resource.ts +27 -0
- package/src/components/search-by-person-attributes/search-by-person-attributes.style.scss +4 -0
- package/src/components/search-by-person-attributes/search-by-person-attributes.test.tsx +133 -0
- package/src/components/search-by-person-attributes/search-by-person-attributes.utils.ts +42 -0
- package/src/components/search-history/search-history-options/search-history-options.component.tsx +290 -0
- package/src/components/search-history/search-history-options/search-history-options.resources.ts +29 -0
- package/src/components/search-history/search-history-options/search-history-options.test.tsx +144 -0
- package/src/components/search-history/search-history.component.tsx +174 -0
- package/src/components/search-history/search-history.style.scss +12 -0
- package/src/components/search-history/search-history.test.tsx +106 -0
- package/src/components/search-history/search-history.utils.ts +14 -0
- package/src/components/search-results-table/search-results-table.component.tsx +105 -0
- package/src/components/search-results-table/search-results-table.scss +4 -0
- package/src/components/search-results-table/search-results-table.test.tsx +47 -0
- package/src/declarations.d.tsx +2 -0
- package/src/index.ts +47 -0
- package/src/setup-tests.ts +1 -0
- package/src/types/index.ts +120 -0
package/src/components/saved-queries/saved-queries-options/saved-queries-options.component.tsx
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ComposedModal,
|
|
5
|
+
ModalFooter,
|
|
6
|
+
ModalHeader,
|
|
7
|
+
OverflowMenu,
|
|
8
|
+
OverflowMenuItem,
|
|
9
|
+
} from "@carbon/react";
|
|
10
|
+
import { showToast } from "@openmrs/esm-framework";
|
|
11
|
+
import { useTranslation } from "react-i18next";
|
|
12
|
+
|
|
13
|
+
import { DefinitionDataRow } from "../../../types";
|
|
14
|
+
|
|
15
|
+
enum Options {
|
|
16
|
+
VIEW,
|
|
17
|
+
DELETE,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface SavedQueriesOptionsProps {
|
|
21
|
+
query: DefinitionDataRow;
|
|
22
|
+
onViewQuery: (queryId: string) => Promise<void>;
|
|
23
|
+
deleteQuery: (queryId: string) => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SavedQueriesOptions: React.FC<SavedQueriesOptionsProps> = ({
|
|
27
|
+
query,
|
|
28
|
+
onViewQuery,
|
|
29
|
+
deleteQuery,
|
|
30
|
+
}) => {
|
|
31
|
+
const { t } = useTranslation();
|
|
32
|
+
const [isDeleteQueryModalVisible, setIsDeleteQueryModalVisible] =
|
|
33
|
+
useState(false);
|
|
34
|
+
|
|
35
|
+
const handleOption = async (option: Options) => {
|
|
36
|
+
switch (option) {
|
|
37
|
+
case Options.VIEW:
|
|
38
|
+
handleViewQuery();
|
|
39
|
+
break;
|
|
40
|
+
case Options.DELETE:
|
|
41
|
+
setIsDeleteQueryModalVisible(true);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleViewQuery = async () => {
|
|
47
|
+
try {
|
|
48
|
+
await onViewQuery(query.id);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
showToast({
|
|
51
|
+
title: t("QueryDeleteError", "Something went wrong"),
|
|
52
|
+
kind: "error",
|
|
53
|
+
critical: true,
|
|
54
|
+
description: error?.message,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleDeleteQuery = async () => {
|
|
60
|
+
await deleteQuery(query.id);
|
|
61
|
+
setIsDeleteQueryModalVisible(false);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<>
|
|
66
|
+
<OverflowMenu
|
|
67
|
+
ariaLabel="overflow-menu"
|
|
68
|
+
size="md"
|
|
69
|
+
flipped
|
|
70
|
+
direction="bottom"
|
|
71
|
+
data-testid="options"
|
|
72
|
+
>
|
|
73
|
+
<OverflowMenuItem
|
|
74
|
+
data-testid="view"
|
|
75
|
+
itemText={t("view", "View")}
|
|
76
|
+
onClick={() => handleOption(Options.VIEW)}
|
|
77
|
+
/>
|
|
78
|
+
<OverflowMenuItem
|
|
79
|
+
data-testid="delete"
|
|
80
|
+
itemText={t("delete", "Delete")}
|
|
81
|
+
onClick={() => handleOption(Options.DELETE)}
|
|
82
|
+
/>
|
|
83
|
+
</OverflowMenu>
|
|
84
|
+
|
|
85
|
+
<ComposedModal
|
|
86
|
+
size={"sm"}
|
|
87
|
+
open={isDeleteQueryModalVisible}
|
|
88
|
+
onClose={() => setIsDeleteQueryModalVisible(false)}
|
|
89
|
+
>
|
|
90
|
+
<ModalHeader>
|
|
91
|
+
<p>
|
|
92
|
+
{t(
|
|
93
|
+
"deleteItem",
|
|
94
|
+
`Are you sure you want to delete ${query?.name}?`,
|
|
95
|
+
{
|
|
96
|
+
item: query?.name,
|
|
97
|
+
}
|
|
98
|
+
)}
|
|
99
|
+
</p>
|
|
100
|
+
</ModalHeader>
|
|
101
|
+
<ModalFooter
|
|
102
|
+
danger
|
|
103
|
+
onRequestSubmit={handleDeleteQuery}
|
|
104
|
+
primaryButtonText={t("delete", "Delete")}
|
|
105
|
+
secondaryButtonText={t("cancel", "Cancel")}
|
|
106
|
+
/>
|
|
107
|
+
</ComposedModal>
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default SavedQueriesOptions;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { screen, render, cleanup, waitFor } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
|
|
6
|
+
import { DefinitionDataRow } from "../../../types";
|
|
7
|
+
import SavedQueriesOptions from "./saved-queries-options.component";
|
|
8
|
+
|
|
9
|
+
const query: DefinitionDataRow = {
|
|
10
|
+
id: "1",
|
|
11
|
+
name: "Female Patients",
|
|
12
|
+
description: "Female Patients that are alive",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const testProps = {
|
|
16
|
+
query: query,
|
|
17
|
+
onViewQuery: jest.fn(),
|
|
18
|
+
deleteQuery: jest.fn(),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const renderSavedQueriesOptions = (props = testProps) => {
|
|
22
|
+
render(<SavedQueriesOptions {...props} />);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe("Test the saved queries options", () => {
|
|
26
|
+
afterEach(cleanup);
|
|
27
|
+
it("should be able to view the saved query", async () => {
|
|
28
|
+
const user = userEvent.setup();
|
|
29
|
+
const onViewQuery = jest.fn();
|
|
30
|
+
renderSavedQueriesOptions({ ...testProps, onViewQuery });
|
|
31
|
+
|
|
32
|
+
await waitFor(() => user.click(screen.getByTestId("options")));
|
|
33
|
+
await waitFor(() => user.click(screen.getByTestId("view")));
|
|
34
|
+
expect(onViewQuery).toBeCalledWith(query.id);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should be able delete a query", async () => {
|
|
38
|
+
const user = userEvent.setup();
|
|
39
|
+
const deleteQuery = jest.fn();
|
|
40
|
+
renderSavedQueriesOptions({ ...testProps, deleteQuery });
|
|
41
|
+
|
|
42
|
+
await waitFor(() => user.click(screen.getByTestId("options")));
|
|
43
|
+
await waitFor(() => user.click(screen.getByTestId("delete")));
|
|
44
|
+
await waitFor(() => user.click(screen.getByText("Delete")));
|
|
45
|
+
expect(deleteQuery).toBeCalledWith(query.id);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DataTable,
|
|
5
|
+
Table,
|
|
6
|
+
TableHead,
|
|
7
|
+
TableRow,
|
|
8
|
+
TableHeader,
|
|
9
|
+
TableBody,
|
|
10
|
+
TableCell,
|
|
11
|
+
Pagination,
|
|
12
|
+
} from "@carbon/react";
|
|
13
|
+
import { showToast } from "@openmrs/esm-framework";
|
|
14
|
+
import { useTranslation } from "react-i18next";
|
|
15
|
+
|
|
16
|
+
import mainStyles from "../../cohort-builder.scss";
|
|
17
|
+
import { DefinitionDataRow, PaginationData } from "../../types";
|
|
18
|
+
import EmptyData from "../empty-data/empty-data.component";
|
|
19
|
+
import SavedQueriesOptions from "./saved-queries-options/saved-queries-options.component";
|
|
20
|
+
import { deleteDataSet, getQueries } from "./saved-queries.resources";
|
|
21
|
+
import styles from "./saved-queries.scss";
|
|
22
|
+
|
|
23
|
+
interface SavedQueriesProps {
|
|
24
|
+
onViewQuery: (queryId: string) => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const SavedQueries: React.FC<SavedQueriesProps> = ({ onViewQuery }) => {
|
|
28
|
+
const [page, setPage] = useState(1);
|
|
29
|
+
const [pageSize, setPageSize] = useState(10);
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const [queries, setQueries] = useState<DefinitionDataRow[]>([]);
|
|
32
|
+
|
|
33
|
+
const getTableData = async () => {
|
|
34
|
+
const queries = await getQueries();
|
|
35
|
+
setQueries(queries);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const deleteQuery = async (queryId: string) => {
|
|
39
|
+
try {
|
|
40
|
+
await deleteDataSet(queryId);
|
|
41
|
+
showToast({
|
|
42
|
+
title: t("success", "Success"),
|
|
43
|
+
kind: "success",
|
|
44
|
+
critical: true,
|
|
45
|
+
description: t("queryIsDeleted", "the query is deleted"),
|
|
46
|
+
});
|
|
47
|
+
getTableData();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
showToast({
|
|
50
|
+
title: t("queryDeleteError", "Error saving the query"),
|
|
51
|
+
kind: "error",
|
|
52
|
+
critical: true,
|
|
53
|
+
description: error?.message,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
getTableData();
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const headers = [
|
|
63
|
+
{
|
|
64
|
+
key: "name",
|
|
65
|
+
header: t("name", "Name"),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: "description",
|
|
69
|
+
header: t("description", "Description"),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
const handlePagination = ({ page, pageSize }: PaginationData) => {
|
|
74
|
+
setPage(page);
|
|
75
|
+
setPageSize(pageSize);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div className={styles.container}>
|
|
80
|
+
<p className={mainStyles.text}>
|
|
81
|
+
{t(
|
|
82
|
+
"savedQueryDescription",
|
|
83
|
+
"You can only search for Query Definitions that you have saved using a Name."
|
|
84
|
+
)}
|
|
85
|
+
</p>
|
|
86
|
+
<DataTable rows={queries} headers={headers} useZebraStyles>
|
|
87
|
+
{({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => (
|
|
88
|
+
<Table {...getTableProps()}>
|
|
89
|
+
<TableHead>
|
|
90
|
+
<TableRow>
|
|
91
|
+
{headers.map((header) => (
|
|
92
|
+
<TableHeader {...getHeaderProps({ header })}>
|
|
93
|
+
{header.header}
|
|
94
|
+
</TableHeader>
|
|
95
|
+
))}
|
|
96
|
+
<TableHeader className={mainStyles.optionHeader}></TableHeader>
|
|
97
|
+
</TableRow>
|
|
98
|
+
</TableHead>
|
|
99
|
+
<TableBody>
|
|
100
|
+
{rows
|
|
101
|
+
.slice((page - 1) * pageSize)
|
|
102
|
+
.slice(0, pageSize)
|
|
103
|
+
.map((row, index: number) => (
|
|
104
|
+
<TableRow {...getRowProps({ row })} key={index}>
|
|
105
|
+
{row.cells.map((cell, index) => (
|
|
106
|
+
<TableCell key={index}>{cell.value}</TableCell>
|
|
107
|
+
))}
|
|
108
|
+
<TableCell className={mainStyles.optionCell}>
|
|
109
|
+
<SavedQueriesOptions
|
|
110
|
+
query={queries[index]}
|
|
111
|
+
onViewQuery={onViewQuery}
|
|
112
|
+
deleteQuery={deleteQuery}
|
|
113
|
+
/>
|
|
114
|
+
</TableCell>
|
|
115
|
+
</TableRow>
|
|
116
|
+
))}
|
|
117
|
+
</TableBody>
|
|
118
|
+
</Table>
|
|
119
|
+
)}
|
|
120
|
+
</DataTable>
|
|
121
|
+
{queries.length > 10 && (
|
|
122
|
+
<Pagination
|
|
123
|
+
backwardText={t("previousPage", "Previous page")}
|
|
124
|
+
forwardText={t("nextPage", "Next page")}
|
|
125
|
+
itemsPerPageText={t("itemsPerPage:", "Items per page:")}
|
|
126
|
+
onChange={handlePagination}
|
|
127
|
+
page={1}
|
|
128
|
+
pageSize={10}
|
|
129
|
+
pageSizes={[10, 20, 30, 40, 50]}
|
|
130
|
+
size="md"
|
|
131
|
+
totalItems={queries.length}
|
|
132
|
+
/>
|
|
133
|
+
)}
|
|
134
|
+
{!queries.length && <EmptyData displayText={t("queries", "queries")} />}
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default SavedQueries;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FetchResponse, openmrsFetch } from "@openmrs/esm-framework";
|
|
2
|
+
|
|
3
|
+
import { Response, DefinitionDataRow } from "../../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @returns Queries
|
|
7
|
+
*/
|
|
8
|
+
export async function getQueries(): Promise<DefinitionDataRow[]> {
|
|
9
|
+
const response: FetchResponse<{ results: Response[] }> = await openmrsFetch(
|
|
10
|
+
"/ws/rest/v1/reportingrest/dataSetDefinition?v=full",
|
|
11
|
+
{
|
|
12
|
+
method: "GET",
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
let queries: DefinitionDataRow[] = [];
|
|
17
|
+
if (response.data.results.length > 0) {
|
|
18
|
+
response.data.results.map((query: Response) => {
|
|
19
|
+
const queryData: DefinitionDataRow = {
|
|
20
|
+
id: query.uuid,
|
|
21
|
+
name: query.name.replace("[AdHocDataExport]", ""),
|
|
22
|
+
description: query.description,
|
|
23
|
+
};
|
|
24
|
+
queries.push(queryData);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return queries;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const deleteDataSet = async (queryID: string) => {
|
|
32
|
+
const dataset: FetchResponse = await openmrsFetch(
|
|
33
|
+
`/ws/rest/v1/reportingrest/adhocdataset/${queryID}?purge=true`,
|
|
34
|
+
{
|
|
35
|
+
method: "DELETE",
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
return dataset;
|
|
39
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
background: white;
|
|
3
|
+
padding: 1rem;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.searchContainer {
|
|
7
|
+
display: flex;
|
|
8
|
+
margin-bottom: 2rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.searchBtn{
|
|
12
|
+
:global(.cds--btn) {
|
|
13
|
+
min-height: 1rem;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.optionCell {
|
|
18
|
+
padding: 0 !important;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.optionHeader {
|
|
22
|
+
width: 1.5rem !important;
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { openmrsFetch } from "@openmrs/esm-framework";
|
|
4
|
+
import { render, cleanup, screen, waitFor } from "@testing-library/react";
|
|
5
|
+
|
|
6
|
+
import { DefinitionDataRow } from "../../types";
|
|
7
|
+
import SavedQueries from "./saved-queries.component";
|
|
8
|
+
import { getQueries } from "./saved-queries.resources";
|
|
9
|
+
|
|
10
|
+
const mockQueries: DefinitionDataRow[] = [
|
|
11
|
+
{
|
|
12
|
+
id: "1",
|
|
13
|
+
name: "male alive",
|
|
14
|
+
description: "male Patients that are alive",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "2",
|
|
18
|
+
name: "Female ages between 10 and 30",
|
|
19
|
+
description:
|
|
20
|
+
"male Patients with ages between 10 and 30 years that are alive",
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const mockOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
25
|
+
|
|
26
|
+
jest.mock("./saved-queries.resources", () => {
|
|
27
|
+
const original = jest.requireActual("./saved-queries.resources");
|
|
28
|
+
return {
|
|
29
|
+
...original,
|
|
30
|
+
getQueries: jest.fn(),
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("Test the saved queries component", () => {
|
|
35
|
+
afterEach(cleanup);
|
|
36
|
+
it("should be able to search for a query", async () => {
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
getQueries.mockImplementation(() => mockQueries);
|
|
39
|
+
mockOpenmrsFetch.mockReturnValueOnce({
|
|
40
|
+
data: { results: mockQueries },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
render(<SavedQueries onViewQuery={jest.fn()} />);
|
|
44
|
+
|
|
45
|
+
await waitFor(() =>
|
|
46
|
+
expect(screen.getByText(mockQueries[0].name)).toBeInTheDocument()
|
|
47
|
+
);
|
|
48
|
+
expect(screen.getByText(mockQueries[1].name)).toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { screen, render, waitFor } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
|
|
6
|
+
import SearchButtonSet from "./search-button-set";
|
|
7
|
+
|
|
8
|
+
describe("Test the search button set component", () => {
|
|
9
|
+
it("should be able search and reset", async () => {
|
|
10
|
+
const user = userEvent.setup();
|
|
11
|
+
const handleSubmit = jest.fn();
|
|
12
|
+
const handleReset = jest.fn();
|
|
13
|
+
render(
|
|
14
|
+
<SearchButtonSet
|
|
15
|
+
onHandleReset={handleReset}
|
|
16
|
+
onHandleSubmit={handleSubmit}
|
|
17
|
+
isLoading={false}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
await user.click(screen.getByTestId("reset-btn"));
|
|
22
|
+
await waitFor(() => expect(handleReset).toBeCalled());
|
|
23
|
+
await user.click(screen.getByTestId("search-btn"));
|
|
24
|
+
await waitFor(() => expect(handleSubmit).toBeCalled());
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { Button, ButtonSet, Column, InlineLoading } from "@carbon/react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
|
|
6
|
+
import styles from "./search-button-set.css";
|
|
7
|
+
|
|
8
|
+
interface SearchButtonSet {
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
onHandleSubmit: () => void;
|
|
11
|
+
onHandleReset: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const SearchButtonSet: React.FC<SearchButtonSet> = ({
|
|
15
|
+
isLoading,
|
|
16
|
+
onHandleSubmit,
|
|
17
|
+
onHandleReset,
|
|
18
|
+
}) => {
|
|
19
|
+
const { t } = useTranslation();
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Column sm={2} md={{ offset: 4 }} className={styles.container}>
|
|
23
|
+
<ButtonSet className={styles.buttonSet}>
|
|
24
|
+
<Button
|
|
25
|
+
kind="secondary"
|
|
26
|
+
onClick={onHandleReset}
|
|
27
|
+
data-testid="reset-btn"
|
|
28
|
+
>
|
|
29
|
+
{t("reset", "Reset")}
|
|
30
|
+
</Button>
|
|
31
|
+
<Button
|
|
32
|
+
kind="primary"
|
|
33
|
+
onClick={onHandleSubmit}
|
|
34
|
+
data-testid="search-btn"
|
|
35
|
+
>
|
|
36
|
+
{isLoading ? (
|
|
37
|
+
<InlineLoading description={t("loading", "Loading")} />
|
|
38
|
+
) : (
|
|
39
|
+
t("search", "Search")
|
|
40
|
+
)}
|
|
41
|
+
</Button>
|
|
42
|
+
</ButtonSet>
|
|
43
|
+
</Column>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default SearchButtonSet;
|