@tsed/react-formio 1.11.2 → 1.13.1

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 (145) hide show
  1. package/.env +2 -1
  2. package/craco.config.js +11 -1
  3. package/dist/components/alert/alert.component.spec.d.ts +1 -0
  4. package/dist/components/alert/alert.stories.d.ts +15 -0
  5. package/dist/components/form/form.component.d.ts +2 -0
  6. package/dist/components/form/form.stories.d.ts +37 -0
  7. package/dist/components/form/useForm.hook.d.ts +1 -0
  8. package/dist/components/form-action/formAction.stories.d.ts +90 -414
  9. package/dist/components/input-text/inputText.component.d.ts +1 -1
  10. package/dist/components/input-text/inputText.component.spec.d.ts +1 -0
  11. package/dist/components/select/select.component.spec.d.ts +1 -0
  12. package/dist/components/tabs/tabs.component.spec.d.ts +1 -0
  13. package/dist/index.js +110 -33
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.modern.js +83 -32
  16. package/dist/index.modern.js.map +1 -1
  17. package/jest.config.js +1 -1
  18. package/package.json +5 -9
  19. package/readme.md +114 -86
  20. package/src/components/__fixtures__/form-schema.json +10 -42
  21. package/src/components/__fixtures__/form.fixture.json +1 -1
  22. package/src/components/actions-table/actionsTable.component.spec.tsx +4 -13
  23. package/src/components/actions-table/actionsTable.component.tsx +3 -11
  24. package/src/components/alert/alert.component.spec.tsx +97 -0
  25. package/src/components/alert/alert.component.tsx +2 -8
  26. package/src/components/alert/alert.stories.tsx +17 -0
  27. package/src/components/card/card.component.tsx +1 -5
  28. package/src/components/form/form.component.tsx +4 -8
  29. package/src/components/form/form.stories.tsx +66 -2
  30. package/src/components/form/useForm.hook.ts +29 -14
  31. package/src/components/form-access/formAccess.component.tsx +19 -82
  32. package/src/components/form-access/formAccess.schema.ts +7 -23
  33. package/src/components/form-access/formAccess.stories.tsx +2 -9
  34. package/src/components/form-access/formAccess.utils.spec.ts +4 -22
  35. package/src/components/form-access/formAccess.utils.ts +7 -29
  36. package/src/components/form-action/formAction.component.tsx +3 -19
  37. package/src/components/form-action/formAction.stories.tsx +251 -672
  38. package/src/components/form-builder/formBuilder.component.tsx +4 -13
  39. package/src/components/form-builder/formBuilder.stories.tsx +12 -24
  40. package/src/components/form-control/formControl.component.tsx +2 -8
  41. package/src/components/form-edit/formCtas.component.tsx +5 -23
  42. package/src/components/form-edit/formEdit.component.tsx +2 -20
  43. package/src/components/form-edit/formEdit.reducer.ts +2 -8
  44. package/src/components/form-edit/formEdit.stories.tsx +3 -15
  45. package/src/components/form-edit/formParameters.component.tsx +3 -20
  46. package/src/components/form-edit/useFormEdit.hook.ts +2 -9
  47. package/src/components/form-settings/formSettings.component.spec.tsx +2 -9
  48. package/src/components/form-settings/formSettings.component.tsx +6 -34
  49. package/src/components/form-settings/formSettings.stories.tsx +1 -6
  50. package/src/components/form-settings/formSettings.utils.spec.ts +1 -4
  51. package/src/components/form-settings/formSettings.utils.ts +2 -7
  52. package/src/components/forms-table/components/formCell.component.tsx +2 -6
  53. package/src/components/forms-table/formsTable.component.tsx +2 -7
  54. package/src/components/input-tags/inputTags.component.tsx +10 -34
  55. package/src/components/input-tags/inputTags.stories.tsx +4 -14
  56. package/src/components/input-text/inputText.component.spec.tsx +56 -0
  57. package/src/components/input-text/inputText.component.tsx +3 -4
  58. package/src/components/input-text/inputText.stories.tsx +6 -26
  59. package/src/components/loader/loader.component.tsx +2 -11
  60. package/src/components/modal/modal.component.spec.tsx +8 -14
  61. package/src/components/modal/modal.component.tsx +6 -27
  62. package/src/components/modal/modal.stories.tsx +1 -5
  63. package/src/components/modal/removeModal.component.tsx +4 -22
  64. package/src/components/pagination/pagination.component.spec.tsx +12 -38
  65. package/src/components/pagination/pagination.component.tsx +8 -41
  66. package/src/components/pagination/pagination.stories.tsx +1 -5
  67. package/src/components/react-component/reactComponent.component.tsx +3 -11
  68. package/src/components/select/select.component.spec.tsx +86 -0
  69. package/src/components/select/select.component.tsx +11 -15
  70. package/src/components/select/select.stories.tsx +6 -26
  71. package/src/components/submissions-table/submissionsTable.component.tsx +1 -3
  72. package/src/components/submissions-table/submissionsTable.stories.tsx +1 -1
  73. package/src/components/table/components/defaultArrowSort.component.tsx +1 -10
  74. package/src/components/table/components/defaultCell.component.tsx +1 -4
  75. package/src/components/table/components/defaultCellHeader.component.tsx +4 -14
  76. package/src/components/table/components/defaultCellOperations.component.tsx +14 -25
  77. package/src/components/table/components/defaultOperationButton.component.tsx +2 -10
  78. package/src/components/table/filters/defaultColumnFilter.component.spec.tsx +1 -1
  79. package/src/components/table/filters/selectColumnFilter.component.spec.tsx +2 -10
  80. package/src/components/table/filters/selectColumnFilter.component.tsx +2 -6
  81. package/src/components/table/table.component.tsx +13 -53
  82. package/src/components/table/table.stories.tsx +1 -1
  83. package/src/components/table/utils/getPageNumbers.ts +3 -11
  84. package/src/components/table/utils/mapFormToColumns.tsx +14 -22
  85. package/src/components/table/utils/useOperations.hook.tsx +2 -12
  86. package/src/components/tabs/tabs.component.spec.tsx +86 -0
  87. package/src/components/tabs/tabs.component.stories.tsx +2 -9
  88. package/src/components/tabs/tabs.component.tsx +9 -43
  89. package/src/interfaces/Operation.ts +1 -4
  90. package/src/react-table.d.ts +9 -28
  91. package/src/stores/action/action.actions.ts +31 -33
  92. package/src/stores/action/action.reducers.spec.ts +1 -8
  93. package/src/stores/action/action.reducers.ts +1 -8
  94. package/src/stores/action/action.selectors.ts +1 -2
  95. package/src/stores/action-info/action-info.actions.spec.ts +1 -5
  96. package/src/stores/action-info/action-info.actions.ts +16 -19
  97. package/src/stores/action-info/action-info.reducers.spec.ts +1 -6
  98. package/src/stores/action-info/action-info.reducers.ts +1 -6
  99. package/src/stores/action-info/action-info.selectors.ts +1 -4
  100. package/src/stores/actions/actions.actions.spec.ts +1 -6
  101. package/src/stores/actions/actions.actions.ts +16 -19
  102. package/src/stores/actions/actions.reducers.spec.ts +1 -6
  103. package/src/stores/actions/actions.reducers.ts +1 -6
  104. package/src/stores/actions/actions.selectors.ts +2 -4
  105. package/src/stores/auth/auth.reducers.ts +1 -4
  106. package/src/stores/auth/auth.selectors.spec.ts +1 -5
  107. package/src/stores/auth/auth.selectors.ts +3 -6
  108. package/src/stores/auth/auth.utils.tsx +2 -8
  109. package/src/stores/auth/getAccess.action.spec.ts +11 -54
  110. package/src/stores/auth/getAccess.action.ts +1 -6
  111. package/src/stores/auth/initAuth.action.ts +15 -17
  112. package/src/stores/form/form.actions.spec.ts +8 -39
  113. package/src/stores/form/form.actions.ts +55 -64
  114. package/src/stores/form/form.reducers.spec.ts +1 -7
  115. package/src/stores/form/form.reducers.ts +1 -8
  116. package/src/stores/form/form.selectors.ts +1 -2
  117. package/src/stores/forms/forms.actions.spec.ts +5 -18
  118. package/src/stores/forms/forms.actions.ts +17 -21
  119. package/src/stores/forms/forms.reducers.spec.ts +1 -6
  120. package/src/stores/forms/forms.reducers.ts +2 -13
  121. package/src/stores/forms/forms.selectors.ts +2 -4
  122. package/src/stores/index.spec.ts +6 -9
  123. package/src/stores/root/root.selectors.spec.ts +1 -6
  124. package/src/stores/root/root.selectors.ts +6 -24
  125. package/src/stores/submission/submission.actions.spec.ts +11 -33
  126. package/src/stores/submission/submission.actions.ts +57 -66
  127. package/src/stores/submission/submission.reducers.spec.ts +17 -27
  128. package/src/stores/submission/submission.reducers.ts +1 -4
  129. package/src/stores/submission/submission.selectors.ts +1 -4
  130. package/src/stores/submissions/submissions.actions.spec.ts +5 -18
  131. package/src/stores/submissions/submissions.actions.ts +17 -26
  132. package/src/stores/submissions/submissions.reducers.spec.ts +3 -12
  133. package/src/stores/submissions/submissions.reducers.ts +3 -17
  134. package/src/stores/submissions/submissions.selectors.spec.ts +1 -4
  135. package/src/stores/submissions/submissions.selectors.ts +2 -4
  136. package/src/utils/getEventValue.ts +1 -4
  137. package/src/utils/iconClass.ts +2 -10
  138. package/src/utils/mapPagination.ts +1 -6
  139. package/src/utils/mapRequestParams.ts +2 -12
  140. package/src/utils/url.test.ts +4 -12
  141. package/src/utils/url.ts +2 -7
  142. package/tsconfig.json +4 -12
  143. package/tsconfig.test.json +1 -1
  144. package/.eslintrc +0 -47
  145. package/.prettierrc +0 -10
@@ -0,0 +1,97 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react";
3
+ import { Sandbox } from "./alert.stories";
4
+
5
+ describe("Alert component", () => {
6
+ it("should NOT display the alert component when no error is received.", () => {
7
+ const { container } = render(<Sandbox {...Sandbox.args} error={null} />);
8
+
9
+ expect(container).toBeEmptyDOMElement();
10
+ });
11
+
12
+ it("should display an error when the error is in string format", () => {
13
+ const error = "error in string format";
14
+ const { getByRole } = render(<Sandbox {...Sandbox.args} error={error} />);
15
+
16
+ const alert = getByRole("alert") as HTMLDivElement;
17
+
18
+ expect(alert).toBeInTheDocument();
19
+ expect(alert).toHaveClass("alert alert-danger");
20
+ expect(alert).toHaveTextContent(error);
21
+ });
22
+
23
+ it("should display error(s) when the error is an array", () => {
24
+ const arrayOfErrors = ["first error", "second error", "third error"];
25
+ const joinedErrors = arrayOfErrors.map((error) => error).join("");
26
+ const { getByRole, getByText } = render(<Sandbox {...Sandbox.args} error={arrayOfErrors} />);
27
+
28
+ const alert = getByRole("alert") as HTMLDivElement;
29
+
30
+ expect(alert).toBeInTheDocument();
31
+ expect(alert).toHaveClass("alert alert-danger");
32
+ expect(getByText(joinedErrors)).toBeInTheDocument();
33
+ });
34
+
35
+ it("should display error's names paths and messages when the error is an object that has an 'errors' property that contains an array of error objects", () => {
36
+ const arrayOfErrors = {
37
+ errors: [
38
+ { name: "first error", path: "/path", message: "message" },
39
+ { name: "second error", path: "/path", message: "message" },
40
+ { name: "third error", path: "/path", message: "message" }
41
+ ]
42
+ };
43
+ const { getByRole } = render(<Sandbox {...Sandbox.args} error={arrayOfErrors} />);
44
+
45
+ const alert = getByRole("alert") as HTMLDivElement;
46
+
47
+ expect(alert).toBeInTheDocument();
48
+ expect(alert).toHaveClass("alert alert-danger");
49
+ expect(alert).toHaveTextContent(arrayOfErrors.errors.map((error) => `${error.name} (${error.path}) - ${error.message}`).join(""));
50
+ });
51
+
52
+ it("should display an error message when the error is a standard error", () => {
53
+ const standardError = { message: "first error" };
54
+ const { getByRole, getByText } = render(<Sandbox {...Sandbox.args} error={standardError} />);
55
+
56
+ const alert = getByRole("alert") as HTMLDivElement;
57
+
58
+ expect(alert).toBeInTheDocument();
59
+ expect(alert).toHaveClass("alert alert-danger");
60
+ expect(getByText(standardError.message)).toBeInTheDocument();
61
+ });
62
+
63
+ it("should display error(s) message(s) when the error is a joi validation error", () => {
64
+ const joiValidationError = { name: "ValidationError", details: [{ message: "message 1" }, { message: "message 2" }] };
65
+ const { getByRole, getByText } = render(<Sandbox {...Sandbox.args} error={joiValidationError} />);
66
+
67
+ const alert = getByRole("alert") as HTMLDivElement;
68
+
69
+ expect(alert).toBeInTheDocument();
70
+ expect(alert).toHaveClass("alert alert-danger");
71
+ expect(getByText("message 1")).toBeInTheDocument();
72
+ expect(getByText("message 2")).toBeInTheDocument();
73
+ });
74
+
75
+ it("should display a custom error message that asks to reload the form when a conflict error occurs in a form", () => {
76
+ const error = { _id: "some id", display: "some value" };
77
+ const messageReturned = "Another user has saved this form already. Please reload and re-apply your changes.";
78
+ const { getByRole } = render(<Sandbox {...Sandbox.args} error={error} />);
79
+
80
+ const alert = getByRole("alert") as HTMLDivElement;
81
+
82
+ expect(alert).toBeInTheDocument();
83
+ expect(alert).toHaveClass("alert alert-danger");
84
+ expect(alert).toHaveTextContent(messageReturned);
85
+ });
86
+
87
+ it("should display an error message by default when the error format does not match any of the conditions of the formatError() handler", () => {
88
+ const messageError: string = "An error occurred. See console logs for details.";
89
+ const { getByRole } = render(<Sandbox {...Sandbox.args} error={true} />);
90
+
91
+ const alert = getByRole("alert") as HTMLDivElement;
92
+
93
+ expect(alert).toBeInTheDocument();
94
+ expect(alert).toHaveClass("alert alert-danger");
95
+ expect(alert).toHaveTextContent(messageError);
96
+ });
97
+ });
@@ -29,20 +29,14 @@ function formatError(error: any): any {
29
29
  }
30
30
 
31
31
  // If this is a joy validation error.
32
- if (
33
- Object.prototype.hasOwnProperty.call(error, "name") &&
34
- error.name === "ValidationError"
35
- ) {
32
+ if (Object.prototype.hasOwnProperty.call(error, "name") && error.name === "ValidationError") {
36
33
  return error.details.map((item: any, index: number) => {
37
34
  return <div key={index}>{item.message}</div>;
38
35
  });
39
36
  }
40
37
 
41
38
  // If a conflict error occurs on a form, the form is returned.
42
- if (
43
- Object.prototype.hasOwnProperty.call(error, "_id") &&
44
- Object.prototype.hasOwnProperty.call(error, "display")
45
- ) {
39
+ if (Object.prototype.hasOwnProperty.call(error, "_id") && Object.prototype.hasOwnProperty.call(error, "display")) {
46
40
  return "Another user has saved this form already. Please reload and re-apply your changes.";
47
41
  }
48
42
 
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { Alert } from "./alert.component";
3
+
4
+ export default {
5
+ title: "ReactFormio/Alert",
6
+ component: Alert,
7
+ argTypes: {},
8
+ parameters: {}
9
+ };
10
+
11
+ export const Sandbox = (args: any) => {
12
+ return <Alert {...args} />;
13
+ };
14
+
15
+ Sandbox.args = {
16
+ error: "error placeholder"
17
+ };
@@ -7,11 +7,7 @@ export interface CardProps {
7
7
  className?: string;
8
8
  }
9
9
 
10
- export function Card({
11
- children,
12
- label,
13
- className
14
- }: PropsWithChildren<CardProps>) {
10
+ export function Card({ children, label, className }: PropsWithChildren<CardProps>) {
15
11
  return (
16
12
  <div className={classnames("card", className)}>
17
13
  <div className={"card-header "}>
@@ -17,13 +17,7 @@ export interface FormProps<Data = any> extends UseFormHookProps<Data> {
17
17
  export function Form(props: Partial<FormProps>) {
18
18
  const { element } = useForm(props);
19
19
 
20
- return (
21
- <div
22
- data-testid={"formioContainer" + (props.name || "")}
23
- ref={element}
24
- className={props.className}
25
- />
26
- );
20
+ return <div data-testid={"formioContainer" + (props.name || "")} ref={element} className={props.className} />;
27
21
  }
28
22
 
29
23
  Form.propTypes = {
@@ -53,7 +47,8 @@ Form.propTypes = {
53
47
  noAlerts: PropTypes.bool,
54
48
  i18n: PropTypes.any,
55
49
  template: PropTypes.string,
56
- saveDraft: PropTypes.bool
50
+ saveDraft: PropTypes.bool,
51
+ hooks: PropTypes.any
57
52
  }),
58
53
  onPrevPage: PropTypes.func,
59
54
  onNextPage: PropTypes.func,
@@ -62,6 +57,7 @@ Form.propTypes = {
62
57
  onCustomEvent: PropTypes.func,
63
58
  onComponentChange: PropTypes.func,
64
59
  onSubmit: PropTypes.func,
60
+ onAsyncSubmit: PropTypes.func,
65
61
  onSubmitDone: PropTypes.func,
66
62
  onFormLoad: PropTypes.func,
67
63
  onError: PropTypes.func,
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
- import { Form } from "./form.component";
2
+ import {Form} from "./form.component";
3
3
  import form from "../__fixtures__/form.fixture.json";
4
+ import {Submission} from "../../interfaces";
4
5
 
5
6
  export default {
6
7
  title: "ReactFormio/Form",
@@ -25,7 +26,7 @@ export const Sandbox = (args: any) => {
25
26
  onFormReady={(formio) => {
26
27
  console.log("ready", formio);
27
28
  }}
28
- options={{ template: "tailwind", iconset: "bx" }}
29
+ options={{template: "tailwind", iconset: "bx"}}
29
30
  />
30
31
  );
31
32
  };
@@ -33,3 +34,66 @@ export const Sandbox = (args: any) => {
33
34
  Sandbox.args = {
34
35
  form
35
36
  };
37
+
38
+ export const TriggerError = (args: any) => {
39
+ delete args.onRender;
40
+ delete args.onComponentChange;
41
+
42
+ return (
43
+ <Form
44
+ {...args}
45
+ form={args.form}
46
+ onAsyncSubmit={(submission: Submission) => {
47
+ return new Promise((resolve, reject) => {
48
+ setTimeout(() => {
49
+ reject(new Error("server error"));
50
+ }, 500);
51
+ }).catch((error) => {
52
+ error.errors = {
53
+ "message": "My custom message about this field",
54
+ "type": "custom",
55
+ "path": ["firstName"],
56
+ "level": "error"
57
+ }
58
+ throw error
59
+ });
60
+ }}
61
+ options={{
62
+ hooks: {
63
+ template: "tailwind",
64
+ iconset: "bx"
65
+ }
66
+ }}
67
+ />
68
+ );
69
+ };
70
+
71
+ TriggerError.args = {
72
+ form: {
73
+ "type": "form",
74
+ "display": "form",
75
+ "tags": [],
76
+ "components": [
77
+ {
78
+ "label": "First name",
79
+ "widget": {
80
+ "type": "input"
81
+ },
82
+ "errorLabel": "",
83
+ "key": "firstName",
84
+ "inputType": "text",
85
+ "type": "textfield",
86
+ "id": "eqb1o4r",
87
+ "defaultValue": ""
88
+ },
89
+ {
90
+ "label": "Submit",
91
+ "showValidations": false,
92
+ "tableView": false,
93
+ "key": "submit",
94
+ "type": "button",
95
+ "input": true
96
+ }
97
+ ]
98
+ }
99
+ };
@@ -38,14 +38,10 @@ export interface UseFormHookProps<Data = any> extends Record<string, any> {
38
38
  onNextPage?: (obj: FormPageChangeProps<Data>) => void;
39
39
  onCancel?: Function;
40
40
  onChange?: (submission: ChangedSubmission) => void;
41
- onCustomEvent?: (obj: {
42
- type: string;
43
- event: string;
44
- component: ExtendedComponentSchema;
45
- data: any;
46
- }) => void;
41
+ onCustomEvent?: (obj: { type: string; event: string; component: ExtendedComponentSchema; data: any }) => void;
47
42
  onComponentChange?: (component: ExtendedComponentSchema) => void;
48
43
  onSubmit?: (submission: Submission<Data>) => void;
44
+ onAsyncSubmit?: (submission: Submission<Data>) => Promise<void>;
49
45
  onSubmitDone?: (submission: Submission<Data>) => void;
50
46
  onFormLoad?: Function;
51
47
  onError?: (errors: any) => void;
@@ -66,13 +62,29 @@ export function useForm<Data = any>(props: UseFormHookProps<Data>) {
66
62
  const instance = useRef<Form>();
67
63
  const events = useRef<Map<string, any>>(new Map());
68
64
 
65
+ async function customValidation(submission: Submission, callback: (err: Error | null) => void) {
66
+ if (events.current.has("onAsyncSubmit")) {
67
+ try {
68
+ await events.current.get("onAsyncSubmit")(submission);
69
+ } catch (err) {
70
+ callback(err?.errors || err);
71
+ }
72
+ } else {
73
+ callback(null);
74
+ }
75
+ }
76
+
69
77
  const createWebForm = (srcOrForm: any, options: any) => {
70
78
  options = Object.assign({}, options);
71
- srcOrForm =
72
- typeof srcOrForm === "string" ? srcOrForm : cloneDeep(srcOrForm);
79
+ srcOrForm = typeof srcOrForm === "string" ? srcOrForm : cloneDeep(srcOrForm);
73
80
 
74
81
  if (!instance.current) {
75
82
  isLoaded.current = false;
83
+ options.hooks = {
84
+ ...(options.hooks || {}),
85
+ customValidation: options?.hooks?.customValidation || customValidation
86
+ };
87
+
76
88
  instance.current = new Form(element.current, srcOrForm, options);
77
89
 
78
90
  instance.current.onAny((event: string, ...args: any[]): void => {
@@ -81,9 +93,7 @@ export function useForm<Data = any>(props: UseFormHookProps<Data>) {
81
93
  }
82
94
 
83
95
  if (event.startsWith("formio.")) {
84
- const funcName = `on${event.charAt(7).toUpperCase()}${event.slice(
85
- 8
86
- )}`;
96
+ const funcName = `on${event.charAt(7).toUpperCase()}${event.slice(8)}`;
87
97
 
88
98
  if (funcName === "onChange") {
89
99
  if (isEqual(get(submission, "data"), args[0].data)) {
@@ -100,7 +110,9 @@ export function useForm<Data = any>(props: UseFormHookProps<Data>) {
100
110
  const fn = callLast(funcs[funcName], 100);
101
111
  events.current.set(funcName, fn);
102
112
  }
103
- events.current.get(funcName)(...args);
113
+
114
+ instance.current.instance.setAlert("success", "");
115
+ events.current.get(funcName)(...args, instance.current);
104
116
  }
105
117
  }
106
118
  });
@@ -165,8 +177,11 @@ export function useForm<Data = any>(props: UseFormHookProps<Data>) {
165
177
  }, [props.onSubmit, events]);
166
178
 
167
179
  useEffect(() => {
168
- props.onSubmitDone &&
169
- events.current.set("onSubmitDone", props.onSubmitDone);
180
+ props.onAsyncSubmit && events.current.set("onAsyncSubmit", props.onAsyncSubmit);
181
+ }, [props.onAsyncSubmit, events]);
182
+
183
+ useEffect(() => {
184
+ props.onSubmitDone && events.current.set("onSubmitDone", props.onSubmitDone);
170
185
  }, [props.onSubmitDone, events]);
171
186
 
172
187
  return {
@@ -1,12 +1,5 @@
1
1
  import PropTypes from "prop-types";
2
- import React, {
3
- PropsWithChildren,
4
- ReactElement,
5
- useCallback,
6
- useEffect,
7
- useMemo,
8
- useState
9
- } from "react";
2
+ import React, { PropsWithChildren, ReactElement, useCallback, useEffect, useMemo, useState } from "react";
10
3
  import { FormOptions, FormSchema, Submission } from "../../interfaces";
11
4
  import { Card } from "../card/card.component";
12
5
  import { Form } from "../form/form.component";
@@ -29,18 +22,11 @@ export interface FormAccessProps {
29
22
  options?: FormOptions;
30
23
  }
31
24
 
32
- function useFormAccess({
33
- form: formDefinition,
34
- roles,
35
- onSubmit,
36
- options
37
- }: FormAccessProps) {
25
+ function useFormAccess({ form: formDefinition, roles, onSubmit, options }: FormAccessProps) {
38
26
  // eslint-disable-next-line no-undef
39
27
  const form = useMemo(() => getFormAccess(roles), [roles]);
40
28
 
41
- const [submissions, setSubmissions] = useState(() =>
42
- dataAccessToSubmissions(formDefinition, form)
43
- );
29
+ const [submissions, setSubmissions] = useState(() => dataAccessToSubmissions(formDefinition, form));
44
30
 
45
31
  const onChange = useCallback(
46
32
  (type: string, submission: Submission<AccessRoles>) => {
@@ -52,10 +38,7 @@ function useFormAccess({
52
38
  useEffect(() => {
53
39
  const input = dataAccessToSubmissions(formDefinition, form);
54
40
  if (formDefinition?._id) {
55
- if (
56
- shouldUpdate("access", submissions.access, input) ||
57
- shouldUpdate("submissionAccess", submissions.submissionAccess, input)
58
- ) {
41
+ if (shouldUpdate("access", submissions.access, input) || shouldUpdate("submissionAccess", submissions.submissionAccess, input)) {
59
42
  setSubmissions(input);
60
43
  }
61
44
  }
@@ -80,21 +63,10 @@ interface NamedFormAccessProps {
80
63
  options: any;
81
64
  onSubmit: any;
82
65
 
83
- onChange(
84
- name: "access" | "submissionAccess",
85
- submission: Submission<AccessRoles>
86
- ): void;
66
+ onChange(name: "access" | "submissionAccess", submission: Submission<AccessRoles>): void;
87
67
  }
88
68
 
89
- function NamedFormAccess({
90
- name,
91
- form,
92
- submissions,
93
- options,
94
- onChange,
95
- onSubmit,
96
- children
97
- }: PropsWithChildren<NamedFormAccessProps>) {
69
+ function NamedFormAccess({ name, form, submissions, options, onChange, onSubmit, children }: PropsWithChildren<NamedFormAccessProps>) {
98
70
  const [isValid, setIsValid] = useState(true);
99
71
 
100
72
  return (
@@ -110,35 +82,21 @@ function NamedFormAccess({
110
82
  options={options}
111
83
  />
112
84
 
113
- <button
114
- disabled={!isValid}
115
- className={"mt-5 btn btn-primary"}
116
- onClick={onSubmit}
117
- >
85
+ <button disabled={!isValid} className={"mt-5 btn btn-primary"} onClick={onSubmit}>
118
86
  Save access
119
87
  </button>
120
88
 
121
89
  {children}
122
90
 
123
91
  <div className={"alert alert-warning mt-5"}>
124
- Elevated permissions allow users to access and modify other user's
125
- entities. Assign with caution.
92
+ Elevated permissions allow users to access and modify other user's entities. Assign with caution.
126
93
  </div>
127
94
  </>
128
95
  );
129
96
  }
130
97
 
131
- export function FormAccess(
132
- props: PropsWithChildren<FormAccessProps>
133
- ): ReactElement {
134
- const {
135
- type,
136
- form,
137
- submissions,
138
- options,
139
- onChange,
140
- onSubmit
141
- } = useFormAccess(props);
98
+ export function FormAccess(props: PropsWithChildren<FormAccessProps>): ReactElement {
99
+ const { type, form, submissions, options, onChange, onSubmit } = useFormAccess(props);
142
100
 
143
101
  return (
144
102
  <div>
@@ -158,22 +116,16 @@ export function FormAccess(
158
116
  </Card>
159
117
  <div className={"w-1/4 pl-4"}>
160
118
  <Card label={"About Submission Data Permissions"}>
161
- <p>
162
- Submission Data Permissions allow you to control who can create,
163
- view, and modify form submission data.
164
- </p>
119
+ <p>Submission Data Permissions allow you to control who can create, view, and modify form submission data.</p>
165
120
 
166
121
  <ul className={"mt-5 pl-7 list-disc"}>
167
122
  <li className={"pb-2"}>
168
- <strong>Own Permissions</strong> - These permissions apply if
169
- the user is the original creator of the submission data and is
170
- listed as the owner of the submission in submission.owner. This
171
- allows users to create and edit their own submission data
123
+ <strong>Own Permissions</strong> - These permissions apply if the user is the original creator of the submission data and is
124
+ listed as the owner of the submission in submission.owner. This allows users to create and edit their own submission data
172
125
  without seeing other user's data.
173
126
  </li>
174
127
  <li>
175
- <strong>All Permissions</strong> - These permissions apply to
176
- all submission data regardless of who owns it.
128
+ <strong>All Permissions</strong> - These permissions apply to all submission data regardless of who owns it.
177
129
  </li>
178
130
  </ul>
179
131
  </Card>
@@ -181,35 +133,20 @@ export function FormAccess(
181
133
  </div>
182
134
  <div className={"flex mb-5"}>
183
135
  <Card label={`Manage ${type} definition access`} className={"flex-1"}>
184
- <NamedFormAccess
185
- name={"access"}
186
- form={form}
187
- submissions={submissions}
188
- onChange={onChange}
189
- onSubmit={onSubmit}
190
- options={options}
191
- >
136
+ <NamedFormAccess name={"access"} form={form} submissions={submissions} onChange={onChange} onSubmit={onSubmit} options={options}>
192
137
  {props.children}
193
138
  </NamedFormAccess>
194
139
  </Card>
195
140
 
196
141
  <div className={"w-1/4 pl-4"}>
197
142
  <Card label={"About Form Definition Access"}>
198
- <p>
199
- These permissions allow you to give access to a single form's JSON
200
- definition so they can render the form.
201
- </p>
143
+ <p>These permissions allow you to give access to a single form's JSON definition so they can render the form.</p>
202
144
 
203
- <p>
204
- Typically you will want to allow all of your roles to be able to
205
- Read the form definition.
206
- </p>
145
+ <p>Typically you will want to allow all of your roles to be able to Read the form definition.</p>
207
146
 
208
147
  <p>
209
- Each form also has an owner at <strong>form.owner</strong> which
210
- is the user who created the form. In some applications users are
211
- allowed to create their own forms. In those cases it is helpful to
212
- have Owner based permissions as well.
148
+ Each form also has an owner at <strong>form.owner</strong> which is the user who created the form. In some applications users
149
+ are allowed to create their own forms. In those cases it is helpful to have Owner based permissions as well.
213
150
  </p>
214
151
  </Card>
215
152
  </div>
@@ -1,13 +1,7 @@
1
1
  import { ExtendedComponentSchema } from "formiojs";
2
2
  import { FormSchema } from "../../interfaces/FormSchema";
3
3
 
4
- export function getRoleComponent({
5
- label,
6
- key,
7
- description,
8
- choices,
9
- data
10
- }: any): ExtendedComponentSchema {
4
+ export function getRoleComponent({ label, key, description, choices, data }: any): ExtendedComponentSchema {
11
5
  return {
12
6
  label,
13
7
  key,
@@ -36,18 +30,12 @@ export function getRoleComponent({
36
30
  }
37
31
 
38
32
  function toDescription(description: string, hr = true): string {
39
- return (
40
- '<span class="text-sm">' +
41
- description +
42
- "</span> " +
43
- (hr ? '<hr class="mt-6 mb-5 border-gray-200 mx-20"/>' : "")
44
- );
33
+ return '<span class="text-sm">' + description + "</span> " + (hr ? '<hr class="mt-6 mb-5 border-gray-200 mx-20"/>' : "");
45
34
  }
46
35
 
47
36
  export function getSubmissionPermissionForm({ choices }: any): FormSchema {
48
37
  return {
49
- description:
50
- "<strong>Elevated permissions allow users to access and modify other user's entities. Assign with caution.</strong>",
38
+ description: "<strong>Elevated permissions allow users to access and modify other user's entities. Assign with caution.</strong>",
51
39
  components: [
52
40
  getRoleComponent({
53
41
  key: "create_own",
@@ -120,13 +108,11 @@ export function getSubmissionPermissionForm({ choices }: any): FormSchema {
120
108
 
121
109
  export function getAccessPermissionForm({ choices }: any): FormSchema {
122
110
  return {
123
- description:
124
- "<strong>Elevated permissions allow users to access and modify other user's entities. Assign with caution.</strong>",
111
+ description: "<strong>Elevated permissions allow users to access and modify other user's entities. Assign with caution.</strong>",
125
112
  components: [
126
113
  getRoleComponent({
127
114
  key: "read_own",
128
- label:
129
- '<h4 class="text-gray-800">Read Form Definition (Restricted to owner)</h4>',
115
+ label: '<h4 class="text-gray-800">Read Form Definition (Restricted to owner)</h4>',
130
116
  description: toDescription(
131
117
  "The Read Own permission will allow a user, with one of the given Roles, to read a form. A user can only read a form if they are defined as its owner."
132
118
  ),
@@ -142,8 +128,7 @@ export function getAccessPermissionForm({ choices }: any): FormSchema {
142
128
  }),
143
129
  getRoleComponent({
144
130
  key: "update_own",
145
- label:
146
- '<h4 class="text-gray-800">Update Form Definition (Restricted to owner)</h4>',
131
+ label: '<h4 class="text-gray-800">Update Form Definition (Restricted to owner)</h4>',
147
132
  description: toDescription(
148
133
  "The Update Own permission will allow a user, with one of the given Roles, to update a form. A user can only update a form if they are defined as its owner."
149
134
  ),
@@ -159,8 +144,7 @@ export function getAccessPermissionForm({ choices }: any): FormSchema {
159
144
  }),
160
145
  getRoleComponent({
161
146
  key: "delete_own",
162
- label:
163
- '<h4 class="text-gray-800">Delete Form Definition (Restricted to owner)</h4>',
147
+ label: '<h4 class="text-gray-800">Delete Form Definition (Restricted to owner)</h4>',
164
148
  description: toDescription(
165
149
  "The Delete Own permission will allow a user, with one of the given Roles, to delete a form. A user can only delete a form if they are defined as its owner."
166
150
  ),
@@ -27,11 +27,8 @@ export default {
27
27
  };
28
28
 
29
29
  export const Sandbox = (args: any) => {
30
- // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
31
30
  // @ts-ignore
32
- return (
33
- <FormAccess {...args} options={{ template: "tailwind", iconset: "bx" }} />
34
- );
31
+ return <FormAccess {...args} options={{ template: "tailwind", iconset: "bx" }} />;
35
32
  };
36
33
 
37
34
  Sandbox.args = {
@@ -42,11 +39,7 @@ Sandbox.args = {
42
39
  owner: "5d0797a382461b6656d2c790",
43
40
  access: [
44
41
  {
45
- roles: [
46
- "5d0797bc872fc747da559858",
47
- "5d0797bc872fc71d05559859",
48
- "5d0797bc872fc7da3b55985a"
49
- ],
42
+ roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
50
43
  type: "read_all"
51
44
  }
52
45
  ],
@@ -1,11 +1,5 @@
1
1
  import { FormSchema } from "../../interfaces";
2
- import {
3
- dataAccessToSubmissions,
4
- getFormAccess,
5
- SubmissionAccess,
6
- submissionsToDataAccess,
7
- updateSubmissions
8
- } from "./formAccess.utils";
2
+ import { dataAccessToSubmissions, getFormAccess, SubmissionAccess, submissionsToDataAccess, updateSubmissions } from "./formAccess.utils";
9
3
 
10
4
  const roles: any[] = [
11
5
  {
@@ -24,11 +18,7 @@ describe("formAccess.utils", () => {
24
18
  components: [],
25
19
  access: [
26
20
  {
27
- roles: [
28
- "5d0797bc872fc747da559858",
29
- "5d0797bc872fc71d05559859",
30
- "5d0797bc872fc7da3b55985a"
31
- ],
21
+ roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
32
22
  type: "read_all"
33
23
  }
34
24
  ],
@@ -47,11 +37,7 @@ describe("formAccess.utils", () => {
47
37
  data: {
48
38
  delete_all: [],
49
39
  delete_own: [],
50
- read_all: [
51
- "5d0797bc872fc747da559858",
52
- "5d0797bc872fc71d05559859",
53
- "5d0797bc872fc7da3b55985a"
54
- ],
40
+ read_all: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
55
41
  read_own: [],
56
42
  update_all: [],
57
43
  update_own: []
@@ -104,11 +90,7 @@ describe("formAccess.utils", () => {
104
90
  components: [],
105
91
  access: [
106
92
  {
107
- roles: [
108
- "5d0797bc872fc747da559858",
109
- "5d0797bc872fc71d05559859",
110
- "5d0797bc872fc7da3b55985a"
111
- ],
93
+ roles: ["5d0797bc872fc747da559858", "5d0797bc872fc71d05559859", "5d0797bc872fc7da3b55985a"],
112
94
  type: "read_all"
113
95
  }
114
96
  ],