@openmrs/esm-form-builder-app 2.0.2-pre.574 → 2.0.2-pre.586

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 (85) hide show
  1. package/README.md +43 -17
  2. package/dist/127.js +1 -1
  3. package/dist/127.js.map +1 -1
  4. package/dist/150.js +1 -1
  5. package/dist/150.js.map +1 -1
  6. package/dist/153.js +1 -1
  7. package/dist/153.js.map +1 -1
  8. package/dist/164.js +1 -1
  9. package/dist/256.js +1 -1
  10. package/dist/319.js +1 -1
  11. package/dist/447.js +1 -1
  12. package/dist/447.js.map +1 -1
  13. package/dist/515.js +2 -0
  14. package/dist/{773.js.LICENSE.txt → 515.js.LICENSE.txt} +9 -0
  15. package/dist/515.js.map +1 -0
  16. package/dist/527.js +1 -0
  17. package/dist/527.js.map +1 -0
  18. package/dist/574.js +1 -1
  19. package/dist/757.js +1 -1
  20. package/dist/788.js +1 -1
  21. package/dist/800.js +1 -1
  22. package/dist/800.js.map +1 -1
  23. package/dist/807.js +1 -1
  24. package/dist/833.js +1 -1
  25. package/dist/878.js +2 -0
  26. package/dist/{208.js.LICENSE.txt → 878.js.LICENSE.txt} +2 -1
  27. package/dist/878.js.map +1 -0
  28. package/dist/main.js +1 -1
  29. package/dist/main.js.map +1 -1
  30. package/dist/openmrs-esm-form-builder-app.js +1 -1
  31. package/dist/openmrs-esm-form-builder-app.js.buildmanifest.json +154 -175
  32. package/dist/openmrs-esm-form-builder-app.js.map +1 -1
  33. package/dist/routes.json +1 -1
  34. package/package.json +35 -32
  35. package/src/components/action-buttons/action-buttons.component.tsx +65 -101
  36. package/src/components/dashboard/dashboard.component.tsx +98 -174
  37. package/src/components/dashboard/dashboard.test.tsx +51 -81
  38. package/src/components/empty-state/empty-data-illustration.component.tsx +4 -16
  39. package/src/components/empty-state/empty-state.component.tsx +11 -15
  40. package/src/components/error-state/error-state.component.tsx +11 -13
  41. package/src/components/form-editor/form-editor.component.tsx +97 -128
  42. package/src/components/form-renderer/form-renderer.component.tsx +30 -41
  43. package/src/components/interactive-builder/add-question-modal.component.tsx +129 -167
  44. package/src/components/interactive-builder/delete-page-modal.component.tsx +24 -37
  45. package/src/components/interactive-builder/delete-question-modal.component.tsx +25 -47
  46. package/src/components/interactive-builder/delete-section-modal.component.tsx +24 -37
  47. package/src/components/interactive-builder/draggable-question.component.tsx +21 -34
  48. package/src/components/interactive-builder/droppable-container.component.tsx +5 -5
  49. package/src/components/interactive-builder/edit-question-modal.component.tsx +191 -233
  50. package/src/components/interactive-builder/editable-value.component.tsx +12 -17
  51. package/src/components/interactive-builder/interactive-builder.component.tsx +134 -184
  52. package/src/components/interactive-builder/new-form-modal.component.tsx +35 -49
  53. package/src/components/interactive-builder/page-modal.component.tsx +29 -45
  54. package/src/components/interactive-builder/question-modal.scss +7 -0
  55. package/src/components/interactive-builder/section-modal.component.tsx +29 -40
  56. package/src/components/interactive-builder/value-editor.component.tsx +11 -16
  57. package/src/components/modals/save-form-modal.component.tsx +112 -165
  58. package/src/components/pagination/index.ts +2 -2
  59. package/src/components/pagination/pagination.component.tsx +8 -13
  60. package/src/components/pagination/usePaginationInfo.ts +4 -9
  61. package/src/components/schema-editor/schema-editor.component.tsx +11 -17
  62. package/src/config-schema.ts +28 -30
  63. package/src/declarations.d.ts +4 -3
  64. package/src/form-builder-admin-card-link.component.tsx +7 -11
  65. package/src/forms.resource.ts +66 -87
  66. package/src/hooks/useClobdata.ts +10 -12
  67. package/src/hooks/useConceptLookup.ts +5 -8
  68. package/src/hooks/useConceptName.ts +6 -9
  69. package/src/hooks/useEncounterTypes.ts +8 -8
  70. package/src/hooks/useForm.ts +7 -7
  71. package/src/hooks/useForms.ts +5 -8
  72. package/src/index.ts +11 -23
  73. package/src/root.component.tsx +4 -4
  74. package/src/setup-tests.ts +1 -9
  75. package/src/test-helpers.tsx +8 -15
  76. package/src/types.ts +16 -8
  77. package/dist/208.js +0 -2
  78. package/dist/208.js.map +0 -1
  79. package/dist/536.js +0 -1
  80. package/dist/536.js.map +0 -1
  81. package/dist/62.js +0 -1
  82. package/dist/62.js.map +0 -1
  83. package/dist/773.js +0 -2
  84. package/dist/773.js.map +0 -1
  85. package/src/constants.ts +0 -3
@@ -1,43 +1,43 @@
1
- import React from "react";
2
- import { screen, waitFor } from "@testing-library/react";
3
- import userEvent from "@testing-library/user-event";
4
- import { navigate, openmrsFetch, usePagination } from "@openmrs/esm-framework";
5
- import { renderWithSwr, waitForLoadingToFinish } from "../../test-helpers";
6
- import { deleteForm } from "../../forms.resource";
7
- import Dashboard from "./dashboard.component";
1
+ import React from 'react';
2
+ import { screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { navigate, openmrsFetch, usePagination } from '@openmrs/esm-framework';
5
+ import { renderWithSwr, waitForLoadingToFinish } from '../../test-helpers';
6
+ import { deleteForm } from '../../forms.resource';
7
+ import Dashboard from './dashboard.component';
8
8
 
9
9
  const mockedOpenmrsFetch = openmrsFetch as jest.Mock;
10
10
  const mockedDeleteForm = deleteForm as jest.Mock;
11
11
 
12
- jest.mock("../../forms.resource", () => ({
12
+ jest.mock('../../forms.resource', () => ({
13
13
  deleteForm: jest.fn(),
14
14
  }));
15
15
  const mockUsePagination = usePagination as jest.Mock;
16
16
 
17
17
  const formsResponse = [
18
18
  {
19
- uuid: "2ddde996-b1c3-37f1-a53e-378dd1a4f6b5",
20
- name: "Test Form 1",
19
+ uuid: '2ddde996-b1c3-37f1-a53e-378dd1a4f6b5',
20
+ name: 'Test Form 1',
21
21
  encounterType: {
22
- uuid: "dd528487-82a5-4082-9c72-ed246bd49591",
23
- name: "Consultation",
22
+ uuid: 'dd528487-82a5-4082-9c72-ed246bd49591',
23
+ name: 'Consultation',
24
24
  },
25
- version: "1",
25
+ version: '1',
26
26
  published: true,
27
27
  retired: false,
28
28
  resources: [
29
29
  {
30
- dataType: "AmpathJsonSchema",
31
- name: "JSON schema",
32
- uuid: "26e45c1a-a46d-4f69-af0a-c29baaed5b3e",
33
- valueReference: "9c35c3d7-1366-45ef-b4d7-ae635b22b6a7",
30
+ dataType: 'AmpathJsonSchema',
31
+ name: 'JSON schema',
32
+ uuid: '26e45c1a-a46d-4f69-af0a-c29baaed5b3e',
33
+ valueReference: '9c35c3d7-1366-45ef-b4d7-ae635b22b6a7',
34
34
  },
35
35
  ],
36
36
  },
37
37
  ];
38
38
 
39
- jest.mock("@openmrs/esm-framework", () => {
40
- const originalModule = jest.requireActual("@openmrs/esm-framework");
39
+ jest.mock('@openmrs/esm-framework', () => {
40
+ const originalModule = jest.requireActual('@openmrs/esm-framework');
41
41
 
42
42
  return {
43
43
  ...originalModule,
@@ -50,26 +50,22 @@ jest.mock("@openmrs/esm-framework", () => {
50
50
  };
51
51
  });
52
52
 
53
- describe("Dashboard", () => {
54
- it("renders an empty state view if no forms are available", async () => {
53
+ describe('Dashboard', () => {
54
+ it('renders an empty state view if no forms are available', async () => {
55
55
  mockedOpenmrsFetch.mockReturnValueOnce({ data: { results: [] } });
56
56
 
57
57
  renderDashboard();
58
58
 
59
59
  await waitForLoadingToFinish();
60
60
 
61
- expect(
62
- screen.getByRole("heading", { name: /form builder/i })
63
- ).toBeInTheDocument();
64
- expect(screen.getByRole("heading", { name: /forms/i })).toBeInTheDocument();
61
+ expect(screen.getByRole('heading', { name: /form builder/i })).toBeInTheDocument();
62
+ expect(screen.getByRole('heading', { name: /forms/i })).toBeInTheDocument();
65
63
  expect(screen.getByTitle(/empty data illustration/i)).toBeInTheDocument();
66
- expect(
67
- screen.getByText(/there are no forms to display/i)
68
- ).toBeInTheDocument();
64
+ expect(screen.getByText(/there are no forms to display/i)).toBeInTheDocument();
69
65
  expect(screen.getByText(/create a new form/i)).toBeInTheDocument();
70
66
  });
71
67
 
72
- it("searches for a form by name and filters the list of forms", async () => {
68
+ it('searches for a form by name and filters the list of forms', async () => {
73
69
  const user = userEvent.setup();
74
70
 
75
71
  mockedOpenmrsFetch.mockReturnValueOnce({
@@ -82,11 +78,11 @@ describe("Dashboard", () => {
82
78
 
83
79
  await waitForLoadingToFinish();
84
80
 
85
- const searchbox = screen.getByRole("searchbox") as HTMLInputElement;
81
+ const searchbox = screen.getByRole('searchbox') as HTMLInputElement;
86
82
 
87
- await waitFor(() => user.type(searchbox, "COVID"));
83
+ await waitFor(() => user.type(searchbox, 'COVID'));
88
84
 
89
- expect(searchbox.value).toBe("COVID");
85
+ expect(searchbox.value).toBe('COVID');
90
86
 
91
87
  mockUsePagination.mockImplementation(() => ({
92
88
  currentPage: 1,
@@ -94,12 +90,8 @@ describe("Dashboard", () => {
94
90
  results: formsResponse.filter((form) => form.name === searchbox.value),
95
91
  }));
96
92
 
97
- await waitFor(() =>
98
- expect(screen.queryByText(/Test Form 1/i)).not.toBeInTheDocument()
99
- );
100
- expect(
101
- screen.getByText(/no matching forms to display/i)
102
- ).toBeInTheDocument();
93
+ await waitFor(() => expect(screen.queryByText(/Test Form 1/i)).not.toBeInTheDocument());
94
+ expect(screen.getByText(/no matching forms to display/i)).toBeInTheDocument();
103
95
  });
104
96
 
105
97
  it('filters the list of forms by "published" status', async () => {
@@ -115,14 +107,12 @@ describe("Dashboard", () => {
115
107
 
116
108
  await waitForLoadingToFinish();
117
109
 
118
- const publishStatusFilter = screen.getByRole("combobox", {
110
+ const publishStatusFilter = screen.getByRole('combobox', {
119
111
  name: /filter by publish status/i,
120
112
  });
121
113
 
122
114
  await waitFor(() => user.click(publishStatusFilter));
123
- await waitFor(() =>
124
- user.click(screen.getByRole("option", { name: /unpublished/i }))
125
- );
115
+ await waitFor(() => user.click(screen.getByRole('option', { name: /unpublished/i })));
126
116
 
127
117
  mockUsePagination.mockImplementation(() => ({
128
118
  currentPage: 1,
@@ -131,12 +121,10 @@ describe("Dashboard", () => {
131
121
  }));
132
122
 
133
123
  expect(screen.queryByText(/Test Form 1/i)).not.toBeInTheDocument();
134
- expect(
135
- screen.getByText(/no matching forms to display/i)
136
- ).toBeInTheDocument();
124
+ expect(screen.getByText(/no matching forms to display/i)).toBeInTheDocument();
137
125
  });
138
126
 
139
- it("renders a list of forms fetched from the server", async () => {
127
+ it('renders a list of forms fetched from the server', async () => {
140
128
  mockedOpenmrsFetch.mockReturnValueOnce({
141
129
  data: {
142
130
  results: formsResponse,
@@ -153,25 +141,13 @@ describe("Dashboard", () => {
153
141
 
154
142
  await waitForLoadingToFinish();
155
143
 
156
- expect(
157
- screen.getByRole("heading", { name: /form builder/i })
158
- ).toBeInTheDocument();
159
- expect(
160
- screen.getByRole("combobox", { name: /filter by publish status/i })
161
- ).toBeInTheDocument();
162
- expect(
163
- screen.getByRole("button", { name: /create a new form/i })
164
- ).toBeInTheDocument();
165
- expect(
166
- screen.getByRole("button", { name: /edit schema/i })
167
- ).toBeInTheDocument();
168
- expect(
169
- screen.getByRole("button", { name: /download schema/i })
170
- ).toBeInTheDocument();
171
- expect(
172
- screen.getByRole("searchbox", { name: /filter table/i })
173
- ).toBeInTheDocument();
174
- expect(screen.queryByRole("table")).toBeInTheDocument();
144
+ expect(screen.getByRole('heading', { name: /form builder/i })).toBeInTheDocument();
145
+ expect(screen.getByRole('combobox', { name: /filter by publish status/i })).toBeInTheDocument();
146
+ expect(screen.getByRole('button', { name: /create a new form/i })).toBeInTheDocument();
147
+ expect(screen.getByRole('button', { name: /edit schema/i })).toBeInTheDocument();
148
+ expect(screen.getByRole('button', { name: /download schema/i })).toBeInTheDocument();
149
+ expect(screen.getByRole('searchbox', { name: /filter table/i })).toBeInTheDocument();
150
+ expect(screen.queryByRole('table')).toBeInTheDocument();
175
151
  expect(screen.getByText(/Test Form 1/i)).toBeInTheDocument();
176
152
  });
177
153
 
@@ -194,7 +170,7 @@ describe("Dashboard", () => {
194
170
 
195
171
  await waitForLoadingToFinish();
196
172
 
197
- const createFormButton = screen.getByRole("button", {
173
+ const createFormButton = screen.getByRole('button', {
198
174
  name: /create a new form/i,
199
175
  });
200
176
 
@@ -224,7 +200,7 @@ describe("Dashboard", () => {
224
200
 
225
201
  await waitForLoadingToFinish();
226
202
 
227
- const editSchemaButton = screen.getByRole("button", {
203
+ const editSchemaButton = screen.getByRole('button', {
228
204
  name: /edit schema/i,
229
205
  });
230
206
 
@@ -253,7 +229,7 @@ describe("Dashboard", () => {
253
229
 
254
230
  await waitForLoadingToFinish();
255
231
 
256
- const downloadSchemaButton = screen.getByRole("button", {
232
+ const downloadSchemaButton = screen.getByRole('button', {
257
233
  name: /download schema/i,
258
234
  });
259
235
 
@@ -282,25 +258,19 @@ describe("Dashboard", () => {
282
258
 
283
259
  await waitForLoadingToFinish();
284
260
 
285
- const deleteButton = screen.getByRole("button", { name: /delete schema/i });
261
+ const deleteButton = screen.getByRole('button', { name: /delete schema/i });
286
262
  expect(deleteButton).toBeInTheDocument();
287
263
 
288
264
  await waitFor(() => user.click(deleteButton));
289
265
 
290
- const modal = screen.getByRole("presentation");
266
+ const modal = screen.getByRole('presentation');
291
267
  expect(modal).toBeInTheDocument();
292
268
  expect(modal).toHaveTextContent(/delete form/i);
293
- expect(modal).toHaveTextContent(
294
- /are you sure you want to delete this form?/i
295
- );
296
- expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
297
- expect(
298
- screen.getByRole("button", { name: /danger delete/i })
299
- ).toBeInTheDocument();
300
-
301
- await waitFor(() =>
302
- user.click(screen.getByRole("button", { name: /danger delete/i }))
303
- );
269
+ expect(modal).toHaveTextContent(/are you sure you want to delete this form?/i);
270
+ expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
271
+ expect(screen.getByRole('button', { name: /danger delete/i })).toBeInTheDocument();
272
+
273
+ await waitFor(() => user.click(screen.getByRole('button', { name: /danger delete/i })));
304
274
  });
305
275
  });
306
276
 
@@ -1,6 +1,6 @@
1
- import React from "react";
1
+ import React from 'react';
2
2
 
3
- export const EmptyDataIllustration = ({ width = "64", height = "64" }) => {
3
+ export const EmptyDataIllustration = ({ width = '64', height = '64' }) => {
4
4
  return (
5
5
  <svg width={width} height={height} viewBox="0 0 64 64">
6
6
  <title>Empty data illustration</title>
@@ -18,13 +18,7 @@ export const EmptyDataIllustration = ({ width = "64", height = "64" }) => {
18
18
  fill="#C6C6C6"
19
19
  />
20
20
  <circle fill="#C6C6C6" cx={17.636} cy={2.314} r={1.855} />
21
- <circle
22
- fill="#FFF"
23
- fillRule="nonzero"
24
- cx={17.636}
25
- cy={2.314}
26
- r={1.175}
27
- />
21
+ <circle fill="#FFF" fillRule="nonzero" cx={17.636} cy={2.314} r={1.175} />
28
22
  <path
29
23
  d="M55.893 53.995H24.544a.79.79 0 01-.788-.789V15.644a.79.79 0 01.788-.788h31.349a.79.79 0 01.788.788v37.562a.79.79 0 01-.788.789z"
30
24
  fill="#F4F4F4"
@@ -38,13 +32,7 @@ export const EmptyDataIllustration = ({ width = "64", height = "64" }) => {
38
32
  fill="#C6C6C6"
39
33
  />
40
34
  <circle fill="#C6C6C6" cx={40.218} cy={9.755} r={1.855} />
41
- <circle
42
- fill="#FFF"
43
- fillRule="nonzero"
44
- cx={40.218}
45
- cy={9.755}
46
- r={1.13}
47
- />
35
+ <circle fill="#FFF" fillRule="nonzero" cx={40.218} cy={9.755} r={1.13} />
48
36
  </g>
49
37
  </svg>
50
38
  );
@@ -1,27 +1,23 @@
1
- import React from "react";
2
- import { Layer, Link, Tile } from "@carbon/react";
3
- import { useTranslation } from "react-i18next";
4
- import { navigate, useLayoutType } from "@openmrs/esm-framework";
1
+ import React from 'react';
2
+ import { Layer, Link, Tile } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { navigate, useLayoutType } from '@openmrs/esm-framework';
5
5
 
6
- import { EmptyDataIllustration } from "./empty-data-illustration.component";
7
- import styles from "./empty-state.scss";
6
+ import { EmptyDataIllustration } from './empty-data-illustration.component';
7
+ import styles from './empty-state.scss';
8
8
 
9
9
  function EmptyState() {
10
10
  const { t } = useTranslation();
11
- const isTablet = useLayoutType() === "tablet";
11
+ const isTablet = useLayoutType() === 'tablet';
12
12
 
13
13
  return (
14
14
  <Layer>
15
15
  <Tile className={styles.tile}>
16
- <div
17
- className={isTablet ? styles.tabletHeading : styles.desktopHeading}
18
- >
19
- <h4>{t("forms", "Forms")}</h4>
16
+ <div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
17
+ <h4>{t('forms', 'Forms')}</h4>
20
18
  </div>
21
19
  <EmptyDataIllustration />
22
- <p className={styles.content}>
23
- {t("noFormsToDisplay", "There are no forms to display.")}
24
- </p>
20
+ <p className={styles.content}>{t('noFormsToDisplay', 'There are no forms to display.')}</p>
25
21
  <p className={styles.action}>
26
22
  <Link
27
23
  onClick={() =>
@@ -30,7 +26,7 @@ function EmptyState() {
30
26
  })
31
27
  }
32
28
  >
33
- {t("createNewForm", "Create a new form")}
29
+ {t('createNewForm', 'Create a new form')}
34
30
  </Link>
35
31
  </p>
36
32
  </Tile>
@@ -1,8 +1,8 @@
1
- import React from "react";
2
- import { Layer, Tile } from "@carbon/react";
3
- import { useTranslation } from "react-i18next";
4
- import { useLayoutType } from "@openmrs/esm-framework";
5
- import styles from "./error-state.scss";
1
+ import React from 'react';
2
+ import { Layer, Tile } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useLayoutType } from '@openmrs/esm-framework';
5
+ import styles from './error-state.scss';
6
6
 
7
7
  interface ErrorStateProps {
8
8
  error: Error;
@@ -10,23 +10,21 @@ interface ErrorStateProps {
10
10
 
11
11
  const ErrorState: React.FC<ErrorStateProps> = ({ error }) => {
12
12
  const { t } = useTranslation();
13
- const isTablet = useLayoutType() === "tablet";
13
+ const isTablet = useLayoutType() === 'tablet';
14
14
 
15
15
  return (
16
16
  <Layer>
17
17
  <Tile className={styles.tile}>
18
- <div
19
- className={isTablet ? styles.tabletHeading : styles.desktopHeading}
20
- >
21
- <h4>{t("forms", "Forms")}</h4>
18
+ <div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
19
+ <h4>{t('forms', 'Forms')}</h4>
22
20
  </div>
23
21
  <p className={styles.errorMessage}>
24
- {t("error", "Error")}: {error?.message}
22
+ {t('error', 'Error')}: {error?.message}
25
23
  </p>
26
24
  <p className={styles.errorCopy}>
27
25
  {t(
28
- "errorCopy",
29
- "Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above."
26
+ 'errorCopy',
27
+ 'Sorry, there was a problem displaying this information. You can try to reload this page, or contact the site administrator and quote the error code above.',
30
28
  )}
31
29
  </p>
32
30
  </Tile>