@tsed/react-formio 2.3.1 → 2.3.3

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 (37) hide show
  1. package/coverage.json +4 -4
  2. package/dist/components/actions-table/actionsTable.stories.d.ts +8 -53
  3. package/dist/components/form-access/formAccess.component.d.ts +2 -13
  4. package/dist/components/form-access/formAccess.stories.d.ts +3 -44
  5. package/dist/components/form-control/formControl.component.d.ts +3 -11
  6. package/dist/components/react-component/reactComponent.component.d.ts +1 -1
  7. package/dist/components/select/select.component.d.ts +5 -18
  8. package/dist/components/table/components/defaultCellOperations.component.d.ts +12 -1
  9. package/dist/components/table/components/defaultOperationButton.component.d.ts +4 -4
  10. package/dist/components/table/hooks/useOperations.hook.d.ts +2 -2
  11. package/dist/index.js +1184 -1334
  12. package/dist/index.js.map +1 -1
  13. package/dist/index.modern.js +300 -316
  14. package/dist/index.modern.js.map +1 -1
  15. package/package.json +13 -9
  16. package/src/components/__fixtures__/form-actions.json +240 -0
  17. package/src/components/actions-table/__fixtures__/data.json +12 -0
  18. package/src/components/actions-table/actionsTable.component.spec.tsx +44 -13
  19. package/src/components/actions-table/actionsTable.component.tsx +2 -1
  20. package/src/components/actions-table/actionsTable.stories.tsx +71 -289
  21. package/src/components/form/form.stories.tsx +1 -2
  22. package/src/components/form-access/formAccess.component.tsx +2 -13
  23. package/src/components/form-access/formAccess.stories.tsx +55 -49
  24. package/src/components/form-action/formAction.component.tsx +1 -0
  25. package/src/components/form-control/formControl.component.tsx +3 -10
  26. package/src/components/form-edit/formEdit.reducer.ts +0 -1
  27. package/src/components/form-settings/formSettings.component.spec.tsx +4 -4
  28. package/src/components/pagination/pagination.component.spec.tsx +0 -2
  29. package/src/components/react-component/reactComponent.component.tsx +5 -5
  30. package/src/components/select/select.component.tsx +10 -23
  31. package/src/components/table/components/defaultCellOperations.component.tsx +17 -4
  32. package/src/components/table/components/defaultOperationButton.component.tsx +11 -4
  33. package/src/components/table/components/defaultRow.component.tsx +1 -0
  34. package/src/components/table/filters/defaultColumnFilter.component.tsx +1 -0
  35. package/src/components/table/hooks/useOperations.hook.tsx +3 -3
  36. package/src/react-table.d.ts +2 -0
  37. package/dist/package.json +0 -3
@@ -1,5 +1,8 @@
1
- import React from "react";
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { expect, fn, userEvent, within } from "@storybook/test";
2
3
 
4
+ import availableActions from "../__fixtures__/form-actions.json";
5
+ import data from "./__fixtures__/data.json";
3
6
  import { ActionsTable } from "./actionsTable.component";
4
7
 
5
8
  export default {
@@ -21,11 +24,6 @@ export default {
21
24
  type: "boolean"
22
25
  }
23
26
  },
24
- isEmpty: {
25
- control: {
26
- type: "boolean"
27
- }
28
- },
29
27
  disableFilters: {
30
28
  control: {
31
29
  type: "boolean"
@@ -36,296 +34,80 @@ export default {
36
34
  type: "boolean"
37
35
  }
38
36
  },
39
- tags: {
40
- control: {
41
- type: "object"
42
- }
43
- },
44
37
  onAddAction: {
45
38
  action: "onAddAction"
46
39
  }
47
40
  },
48
41
  parameters: {}
49
- };
42
+ } satisfies Meta<typeof ActionsTable>;
50
43
 
51
- export const Sandbox = (args: any) => {
52
- return <ActionsTable {...args} data={args.isEmpty ? [] : args.data} />;
53
- };
44
+ type Story = StoryObj<typeof ActionsTable>;
54
45
 
55
- Sandbox.args = {
56
- icon: "server",
57
- availableActions: [
58
- {
59
- name: "email",
60
- title: "Email",
61
- description: "Allows you to email people on submission.",
62
- priority: 0,
63
- defaults: {
64
- handler: ["after"],
65
- method: ["create"],
66
- priority: 0,
67
- name: "email",
68
- title: "Email"
69
- }
70
- },
71
- {
72
- name: "webhook",
73
- title: "Webhook (Premium)",
74
- description: "Allows you to trigger an external interface.",
75
- priority: 0,
76
- defaults: {
77
- handler: ["after"],
78
- method: ["create", "update", "delete"],
79
- priority: 0,
80
- name: "webhook",
81
- title: "Webhook (Premium)"
82
- },
83
- premium: true
84
- },
85
- {
86
- name: "sql",
87
- title: "SQL Query",
88
- description: "Allows you to execute a remote SQL Query.",
89
- priority: 0,
90
- defaults: {
91
- handler: ["after"],
92
- method: ["create"],
93
- priority: 0,
94
- name: "sql",
95
- title: "SQL Query"
96
- }
97
- },
98
- {
99
- name: "role",
100
- title: "Role Assignment",
101
- description: "Provides the Role Assignment capabilities.",
102
- priority: 1,
103
- defaults: {
104
- handler: ["after"],
105
- method: ["create"],
106
- priority: 1,
107
- name: "role",
108
- title: "Role Assignment"
109
- },
110
- access: { handler: false, method: false }
111
- },
112
- {
113
- name: "resetpass",
114
- title: "Reset Password",
115
- description: "Provides a way to reset a password field.",
116
- defaults: {
117
- handler: ["after", "before"],
118
- method: ["form", "create"],
119
- priority: 0,
120
- name: "resetpass",
121
- title: "Reset Password"
122
- },
123
- access: { handler: false, method: false }
124
- },
125
- {
126
- name: "save",
127
- title: "Save Submission",
128
- description: "Saves the submission into the database.",
129
- priority: 10,
130
- defaults: {
131
- handler: ["before"],
132
- method: ["create", "update"],
133
- priority: 10,
134
- name: "save",
135
- title: "Save Submission"
136
- },
137
- access: { handler: false, method: false }
138
- },
139
- {
140
- name: "login",
141
- title: "Login",
142
- description: "Provides a way to login to the application.",
143
- priority: 2,
144
- defaults: {
145
- handler: ["before"],
146
- method: ["create"],
147
- priority: 2,
148
- name: "login",
149
- title: "Login"
150
- },
151
- access: { handler: false, method: false }
152
- },
153
- {
154
- name: "office365contact",
155
- title: "Office 365 Contacts (Premium)",
156
- description: "Allows you to integrate into your Office 365 Contacts.",
157
- priority: 0,
158
- defaults: {
159
- handler: ["after"],
160
- method: ["create", "update", "delete"],
161
- priority: 0,
162
- name: "office365contact",
163
- title: "Office 365 Contacts (Premium)"
164
- },
165
- premium: true
166
- },
167
- {
168
- name: "office365calendar",
169
- title: "Office 365 Calendar (Premium)",
170
- description: "Allows you to integrate into your Office 365 Calendar.",
171
- premium: true,
172
- priority: 0,
173
- defaults: {
174
- handler: ["after"],
175
- method: ["create", "update", "delete"],
176
- priority: 0,
177
- name: "office365calendar",
178
- title: "Office 365 Calendar (Premium)"
179
- }
180
- },
181
- {
182
- name: "hubspotContact",
183
- title: "Hubspot Contact (Premium)",
184
- description: "Allows you to change contact fields in hubspot.",
185
- priority: 0,
186
- defaults: {
187
- handler: ["after"],
188
- method: ["create"],
189
- priority: 0,
190
- name: "hubspotContact",
191
- title: "Hubspot Contact (Premium)"
192
- },
193
- premium: true
194
- },
195
- {
196
- name: "oauth",
197
- title: "OAuth (Premium)",
198
- description: "Provides OAuth authentication behavior to this form.",
199
- priority: 20,
200
- defaults: {
201
- handler: ["after"],
202
- method: ["form", "create"],
203
- priority: 20,
204
- name: "oauth",
205
- title: "OAuth (Premium)"
206
- },
207
- premium: true
208
- },
209
- {
210
- name: "ldap",
211
- title: "LDAP Login (Premium)",
212
- description: "Provides ldap login.",
213
- priority: 3,
214
- defaults: {
215
- handler: ["before"],
216
- method: ["create"],
217
- priority: 3,
218
- name: "ldap",
219
- title: "LDAP Login (Premium)"
220
- },
221
- premium: true
222
- },
223
- {
224
- name: "googlesheet",
225
- title: "Google Sheets (Premium)",
226
- description: "Allows you to integrate data into Google sheets.",
227
- priority: 0,
228
- defaults: {
229
- handler: ["after"],
230
- method: ["create", "update", "delete"],
231
- priority: 0,
232
- name: "googlesheet",
233
- title: "Google Sheets (Premium)"
234
- },
235
- premium: true
236
- },
237
- {
238
- name: "sqlconnector",
239
- title: "SQL Connector (Premium)",
240
- description: "Allows you to execute a remote SQL Query via Resquel.",
241
- priority: 0,
242
- defaults: {
243
- handler: ["after"],
244
- method: ["create", "update", "delete"],
245
- priority: 0,
246
- name: "sqlconnector",
247
- title: "SQL Connector (Premium)"
248
- },
249
- premium: true
250
- },
251
- {
252
- name: "jira",
253
- title: "Jira (Premium)",
254
- description: "Allows you to create issues within Jira.",
255
- priority: 0,
256
- defaults: {
257
- handler: ["after"],
258
- method: ["create", "update", "delete"],
259
- priority: 0,
260
- name: "jira",
261
- title: "Jira (Premium)"
262
- },
263
- premium: true
264
- },
265
- {
266
- name: "group",
267
- title: "Group Assignment (Premium)",
268
- premium: true,
269
- description: "Provides the Group Assignment capabilities.",
270
- priority: 5,
271
- defaults: {
272
- handler: ["after"],
273
- method: ["create", "update", "delete"],
274
- priority: 5,
275
- name: "group",
276
- title: "Group Assignment (Premium)"
46
+ export const Sandbox: Story = {
47
+ async play({ canvasElement, args }) {
48
+ const canvas = within(canvasElement);
49
+
50
+ const select = canvas.getByTestId("action-table-select");
51
+ const addButton = canvas.getByTestId("action-table-add");
52
+
53
+ expect(addButton).toHaveAttribute("disabled");
54
+
55
+ await userEvent.selectOptions(select, "save", {
56
+ delay: 100
57
+ });
58
+
59
+ await userEvent.click(addButton);
60
+
61
+ expect(args.onAddAction).toHaveBeenCalledWith("save");
62
+
63
+ const editButton = await canvas.getByRole("button", { name: /Operation button: Edit/i });
64
+ const deleteButton = await canvas.getByRole("button", { name: /Operation button: delete/i });
65
+
66
+ expect(editButton).toBeInTheDocument();
67
+ expect(deleteButton).toBeInTheDocument();
68
+
69
+ await userEvent.click(editButton);
70
+
71
+ expect(args.onClick).toHaveBeenCalledWith(
72
+ args.data[0],
73
+ args.operations!.find(({ action }) => action === "edit")
74
+ );
75
+
76
+ await userEvent.click(deleteButton);
77
+
78
+ expect(args.onClick).toHaveBeenCalledWith(
79
+ args.data[0],
80
+ args.operations!.find(({ action }) => action === "delete")
81
+ );
82
+ },
83
+ args: {
84
+ onAddAction: fn(),
85
+ onClick: fn(),
86
+ availableActions: availableActions.map(({ name, title }) => ({
87
+ label: title,
88
+ value: name
89
+ })),
90
+ data: data as never,
91
+ operations: [
92
+ {
93
+ title: "Edit",
94
+ action: "edit",
95
+ alias: "row",
96
+ path: "/resources/:resourceId/submissions/:submissionId",
97
+ icon: "edit",
98
+ permissionsResolver() {
99
+ return true;
100
+ }
277
101
  },
278
- access: { handler: false, method: false }
279
- },
280
- {
281
- name: "twilioSMS",
282
- title: "Twilio SMS (Premium)",
283
- premium: true,
284
- description: "Allows you to send SMS to phone numbers.",
285
- priority: 0,
286
- defaults: {
287
- handler: ["after"],
288
- method: ["create"],
289
- priority: 0,
290
- name: "twilioSMS",
291
- title: "Twilio SMS (Premium)"
292
- }
293
- }
294
- ].map(({ name, title }) => ({
295
- label: title,
296
- value: name
297
- })),
298
- data: [
299
- {
300
- _id: "602967600685b2158b24e99a",
301
- handler: ["before"],
302
- method: ["create", "update"],
303
- priority: 10,
304
- name: "save",
305
- title: "Save Submission",
306
- form: "602967600685b24dbe24e999",
307
- machineName: "tcspjwhsevrzpcd:testForm:save"
308
- }
309
- ],
310
- operations: [
311
- {
312
- title: "Edit",
313
- action: "edit",
314
- alias: "row",
315
- path: "/resources/:resourceId/submissions/:submissionId",
316
- icon: "edit",
317
- permissionsResolver() {
318
- return true;
102
+ {
103
+ action: "delete",
104
+ path: "/resources/:resourceId/submissions/:submissionId/delete",
105
+ icon: "trash",
106
+ buttonType: "danger",
107
+ permissionsResolver() {
108
+ return true;
109
+ }
319
110
  }
320
- },
321
- {
322
- action: "delete",
323
- path: "/resources/:resourceId/submissions/:submissionId/delete",
324
- icon: "trash",
325
- buttonType: "danger",
326
- permissionsResolver() {
327
- return true;
328
- }
329
- }
330
- ]
111
+ ]
112
+ }
331
113
  };
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from "react";
2
2
 
3
- import { Submission } from "../../interfaces";
4
3
  import form from "../__fixtures__/form.fixture.json";
5
4
  import { Form } from "./form.component";
6
5
 
@@ -123,7 +122,7 @@ export const Sandbox = {
123
122
 
124
123
  export const TriggerError = {
125
124
  render: (args: any) => {
126
- const onAsyncSubmit = (submission: Submission) => {
125
+ const onAsyncSubmit = () => {
127
126
  return new Promise((resolve, reject) => {
128
127
  setTimeout(() => {
129
128
  reject(new Error("server error"));
@@ -1,5 +1,4 @@
1
- import PropTypes from "prop-types";
2
- import React, { PropsWithChildren, ReactElement, useCallback, useEffect, useMemo, useState } from "react";
1
+ import React, { PropsWithChildren, useCallback, useEffect, useMemo, useState } from "react";
3
2
 
4
3
  import type { FormOptions, FormSchema, Submission } from "../../interfaces";
5
4
  import { Card } from "../card/card.component";
@@ -24,7 +23,6 @@ export interface FormAccessProps {
24
23
  }
25
24
 
26
25
  function useFormAccess({ form: formDefinition, roles, onSubmit, options }: FormAccessProps) {
27
- // eslint-disable-next-line no-undef
28
26
  const form = useMemo(() => getFormAccess(roles), [roles]);
29
27
 
30
28
  const [submissions, setSubmissions] = useState(() => dataAccessToSubmissions(formDefinition, form));
@@ -96,7 +94,7 @@ function NamedFormAccess({ name, form, submissions, options, onChange, onSubmit,
96
94
  );
97
95
  }
98
96
 
99
- export function FormAccess(props: PropsWithChildren<FormAccessProps>): ReactElement {
97
+ export function FormAccess(props: PropsWithChildren<FormAccessProps>) {
100
98
  const { type, form, submissions, options, onChange, onSubmit } = useFormAccess(props);
101
99
 
102
100
  return (
@@ -155,12 +153,3 @@ export function FormAccess(props: PropsWithChildren<FormAccessProps>): ReactElem
155
153
  </div>
156
154
  );
157
155
  }
158
-
159
- FormAccess.propTypes = {
160
- type: PropTypes.string.isRequired,
161
- form: PropTypes.object,
162
- roles: PropTypes.any,
163
- children: PropTypes.any,
164
- options: PropTypes.any,
165
- onSubmit: PropTypes.func
166
- };
@@ -1,4 +1,5 @@
1
- import React from "react";
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { expect, fn, userEvent, within } from "@storybook/test";
2
3
 
3
4
  import { FormAccess } from "./formAccess.component";
4
5
 
@@ -6,17 +7,7 @@ export default {
6
7
  title: "ReactFormio/FormAccess",
7
8
  component: FormAccess,
8
9
  argTypes: {
9
- onSubmit: { action: "onSubmit" },
10
- actionInfo: {
11
- control: {
12
- type: "object"
13
- }
14
- },
15
- options: {
16
- control: {
17
- type: "object"
18
- }
19
- }
10
+ onSubmit: { action: "onSubmit" }
20
11
  },
21
12
  parameters: {
22
13
  docs: {
@@ -25,45 +16,60 @@ export default {
25
16
  }
26
17
  }
27
18
  }
28
- };
19
+ } satisfies Meta<typeof FormAccess>;
29
20
 
30
- export const Sandbox = (args: any) => {
31
- // @ts-ignore
32
- return <FormAccess {...args} options={{ template: "tailwind", iconset: "bx" }} />;
33
- };
21
+ type Story = StoryObj<typeof FormAccess>;
34
22
 
35
- Sandbox.args = {
36
- form: {
37
- _id: "6023f8fe4b1a2ab9a3aae096",
38
- type: "form",
39
- tags: [],
40
- owner: "5d0797a382461b6656d2c790",
41
- access: [
42
- {
43
- roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
44
- type: "read_all"
45
- }
46
- ],
47
- submissionAccess: [
48
- {
49
- roles: ["5d0797bc872fc747da559858"],
50
- type: "read_all"
51
- }
52
- ],
53
- controller: "",
54
- properties: {},
55
- settings: {},
56
- name: "textField",
57
- path: "textfield",
58
- machineName: "tcspjwhsevrzpcd:textField"
23
+ export const Sandbox: Story = {
24
+ play: async ({ canvasElement, args }) => {
25
+ const canvas = within(canvasElement);
26
+
27
+ // Vérifiez que le bouton "Save access" est présent
28
+ const saveButtons = await canvas.getAllByRole("button", { name: /Save access/i });
29
+ const saveButton = saveButtons[0];
30
+
31
+ expect(saveButton).toBeInTheDocument();
32
+
33
+ // Simulez un clic sur le bouton "Save access"
34
+ await userEvent.click(saveButton);
35
+
36
+ // Vérifiez que l'action onSubmit a été appelée
37
+ expect(args.onSubmit).toHaveBeenCalled();
59
38
  },
60
- roles: [
61
- {
62
- title: "Administrator",
63
- _id: "5d0797bc872fc747da559858"
39
+ args: {
40
+ onSubmit: fn(),
41
+ form: {
42
+ _id: "6023f8fe4b1a2ab9a3aae096",
43
+ type: "form",
44
+ tags: [],
45
+ owner: "5d0797a382461b6656d2c790",
46
+ access: [
47
+ {
48
+ roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
49
+ type: "read_all"
50
+ }
51
+ ],
52
+ submissionAccess: [
53
+ {
54
+ roles: ["5d0797bc872fc747da559858"],
55
+ type: "read_all"
56
+ }
57
+ ],
58
+ controller: "",
59
+ properties: {},
60
+ settings: {},
61
+ name: "textField",
62
+ path: "textfield",
63
+ machineName: "tcspjwhsevrzpcd:textField"
64
64
  },
65
- { title: "Authenticated", _id: "5d0797bc872fc71d05559859" },
66
- { title: "Anonymous", _id: "5d0797bc872fc7da3b55985a" }
67
- ],
68
- options: { template: "tailwind", iconset: "bx" }
65
+ roles: [
66
+ {
67
+ title: "Administrator",
68
+ _id: "5d0797bc872fc747da559858"
69
+ },
70
+ { title: "Authenticated", _id: "5d0797bc872fc71d05559859" },
71
+ { title: "Anonymous", _id: "5d0797bc872fc7da3b55985a" }
72
+ ],
73
+ options: { template: "tailwind", iconset: "bx" }
74
+ }
69
75
  };
@@ -11,6 +11,7 @@ function mapData(options: any, defaults: ActionDefaultsSchema): any {
11
11
  };
12
12
  }
13
13
 
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
15
  function mapSettingsForm({ action, ...settingsForm }: any): any {
15
16
  FormioUtils.eachComponent(settingsForm.components, (component: any) => {
16
17
  const resourceExclude = "";
@@ -1,12 +1,13 @@
1
1
  import classnames from "classnames";
2
- import PropTypes from "prop-types";
3
2
  import React from "react";
4
3
 
5
- export interface FormControlProps {
4
+ export interface FormControlProps<Data = any> {
6
5
  name: string;
6
+ value?: Data;
7
7
  required?: boolean;
8
8
  label?: string;
9
9
  className?: string;
10
+ onChange?: (name: string, value: any) => void;
10
11
  description?: string | React.ComponentType | any;
11
12
  prefix?: JSX.Element | React.ComponentType | any;
12
13
  suffix?: JSX.Element | React.ComponentType | any;
@@ -55,11 +56,3 @@ export function FormControl({
55
56
  </div>
56
57
  );
57
58
  }
58
-
59
- FormControl.propTypes = {
60
- label: PropTypes.string,
61
- name: PropTypes.string.isRequired,
62
- children: PropTypes.any,
63
- required: PropTypes.bool,
64
- description: PropTypes.any
65
- };
@@ -71,7 +71,6 @@ export const reducer = (state: FormEditState, { type, value }: any): FormEditSta
71
71
  return update(cloneDeep(state.original));
72
72
 
73
73
  case "formChange":
74
- // eslint-disable-next-line no-case-declarations
75
74
  const newValue = { ...state.current, ...value };
76
75
 
77
76
  if (hasChanged(state.current, newValue)) {
@@ -5,7 +5,7 @@ import { FormSettings } from "./formSettings.component";
5
5
  import { Sandbox } from "./formSettings.stories";
6
6
 
7
7
  describe("FormSettings", () => {
8
- it("should render form settings", async () => {
8
+ it("should render form settings", () => {
9
9
  const onSubmit = jest.fn();
10
10
 
11
11
  // @ts-ignore
@@ -23,7 +23,7 @@ describe("FormSettings", () => {
23
23
 
24
24
  const btn = screen.getByTestId("submit");
25
25
 
26
- await fireEvent.click(btn);
26
+ fireEvent.click(btn);
27
27
 
28
28
  expect(btn).toHaveTextContent("Save settings");
29
29
  expect(onSubmit).toHaveBeenCalledWith({
@@ -47,7 +47,7 @@ describe("FormSettings", () => {
47
47
  type: "form"
48
48
  });
49
49
  });
50
- it("should render form settings with i18n options", async () => {
50
+ it("should render form settings with i18n options", () => {
51
51
  render(
52
52
  <FormSettings
53
53
  {...Sandbox.args}
@@ -59,7 +59,7 @@ describe("FormSettings", () => {
59
59
 
60
60
  const btn = screen.getByTestId("submit");
61
61
 
62
- await fireEvent.click(btn);
62
+ fireEvent.click(btn);
63
63
 
64
64
  expect(btn).toHaveTextContent("Save settings i18N");
65
65
  });
@@ -50,9 +50,7 @@ describe("Pagination", () => {
50
50
  if (btn.textContent !== "...") {
51
51
  page = +btn.textContent!;
52
52
  fireEvent.click(btn);
53
- // eslint-disable-next-line jest/no-conditional-expect
54
53
  expect(gotoPageSpy).toHaveBeenCalled();
55
- // eslint-disable-next-line jest/no-conditional-expect
56
54
  expect(gotoPageSpy).toHaveBeenCalledWith(page - 1);
57
55
  }
58
56
  });