@evenicanpm/admin-integrate 1.8.1 → 2.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.
Files changed (71) hide show
  1. package/documents/ProcessTask/fragments.ts +4 -0
  2. package/documents/ProcessTemplate/fragments.ts +30 -0
  3. package/documents/ProcessTemplate/list.ts +29 -0
  4. package/package.json +2 -2
  5. package/src/api/process-config/mutation/process-config-import.mutation.ts +1 -1
  6. package/src/api/templates/queries/get-field-values.query.ts +48 -0
  7. package/src/api/templates/queries/get-field-values.server.ts +9 -0
  8. package/src/api/templates/queries/index.ts +4 -0
  9. package/src/api/templates/queries/types.ts +2 -2
  10. package/src/api/templates/queries/validate-field-on-check.query.ts +22 -0
  11. package/src/api/templates/queries/validate-field-on-check.server.ts +30 -0
  12. package/src/api/templates/queries/validate-field-on-submit.server.ts +18 -0
  13. package/src/components/data-table/table-row.tsx +1 -1
  14. package/src/components/icons/up-down.tsx +1 -0
  15. package/src/components/integration-view/integration-view.tsx +10 -15
  16. package/src/components/integration-view/nodes/task-node.tsx +1 -1
  17. package/src/components/integration-view/utils/mapping.ts +10 -11
  18. package/src/components/list-filter/list-filter.tsx +2 -0
  19. package/src/components/templatesV2/inputs/FormikPageBody.tsx +191 -0
  20. package/src/components/templatesV2/inputs/context/FormModeContext.tsx +31 -0
  21. package/src/components/templatesV2/inputs/context/TemplateContext.tsx +37 -0
  22. package/src/components/templatesV2/inputs/field-names.ts +8 -0
  23. package/src/components/templatesV2/inputs/form-type.ts +48 -0
  24. package/src/components/templatesV2/inputs/index.tsx +33 -0
  25. package/src/components/templatesV2/inputs/input-type.ts +23 -0
  26. package/src/components/templatesV2/inputs/primitives/CheckboxInput.tsx +45 -0
  27. package/src/components/templatesV2/inputs/primitives/NumberInput.tsx +58 -0
  28. package/src/components/templatesV2/inputs/primitives/SelectorInput.tsx +111 -0
  29. package/src/components/templatesV2/inputs/primitives/TextInput.tsx +55 -0
  30. package/src/components/templatesV2/inputs/primitives/TextWithQueryInput.tsx +292 -0
  31. package/src/components/templatesV2/inputs/primitives/index.ts +10 -0
  32. package/src/components/templatesV2/inputs/renderers/index.ts +2 -0
  33. package/src/components/templatesV2/inputs/renderers/renderFormControl.tsx +376 -0
  34. package/src/components/templatesV2/inputs/renderers/renderSearchInput.tsx +129 -0
  35. package/src/components/templatesV2/inputs/search/MultiTextSearchInput.tsx +87 -0
  36. package/src/components/templatesV2/inputs/search/SearchInputWrapper.tsx +113 -0
  37. package/src/components/templatesV2/inputs/search/TextSearchInput.tsx +309 -0
  38. package/src/components/templatesV2/inputs/search/index.ts +4 -0
  39. package/src/components/templatesV2/inputs/search/search-query-key.ts +23 -0
  40. package/src/components/templatesV2/inputs/search/useFieldValuesOptions.ts +58 -0
  41. package/src/components/templatesV2/inputs/search/useSearchInput.ts +74 -0
  42. package/src/components/templatesV2/inputs/table/InputTable.tsx +259 -0
  43. package/src/components/templatesV2/inputs/table/index.ts +1 -0
  44. package/src/components/templatesV2/inputs/utils/applyTemplateConfig.ts +28 -0
  45. package/src/components/templatesV2/inputs/utils/arrangeInputs.ts +51 -0
  46. package/src/components/templatesV2/inputs/utils/index.ts +6 -0
  47. package/src/components/templatesV2/inputs/utils/parseQueryName.ts +20 -0
  48. package/src/components/templatesV2/inputs/utils/renderReadOnlyText.tsx +26 -0
  49. package/src/components/templatesV2/inputs/utils/selectors.ts +69 -0
  50. package/src/components/templatesV2/inputs/utils/toStringArray.ts +23 -0
  51. package/src/components/templatesV2/pageForm.tsx +151 -0
  52. package/src/components/{templates → templatesV2}/templates-list/templates-list-row.tsx +2 -1
  53. package/src/components/{templates → templatesV2}/templates-list/templates-list-table.tsx +2 -2
  54. package/src/components/{templates → templatesV2}/templates-list/templates-list.tsx +19 -28
  55. package/src/components/{templates → templatesV2}/types.tsx +12 -12
  56. package/src/components/templatesV2/validation/buildZodSchema.ts +216 -0
  57. package/src/components/templatesV2/validation/zodFormikValidate.ts +17 -0
  58. package/src/components/templatesV2/wizard.tsx +744 -0
  59. package/src/pages/integration-create/integration-create-steps.ts +8 -0
  60. package/src/pages/integration-create/integration-create.tsx +61 -14
  61. package/src/pages/integration-create/select-step.tsx +3 -3
  62. package/src/pages/integration-create/template-list-step.tsx +28 -3
  63. package/src/pages/integration-create/template-options-step.tsx +119 -0
  64. package/src/pages/integration-create/wizard-step.tsx +5 -4
  65. package/src/pages/integration-details/task-drawer/add-task.tsx +4 -4
  66. package/src/pages/integration-details/task-drawer/edit-task.tsx +3 -3
  67. package/src/components/templates/inputs/index.tsx +0 -1392
  68. package/src/components/templates/wizard.tsx +0 -737
  69. /package/src/components/{templates → templatesV2}/index.ts +0 -0
  70. /package/src/components/{templates → templatesV2}/template-filter.ts +0 -0
  71. /package/src/components/{templates → templatesV2}/templates-list/index.ts +0 -0
@@ -232,6 +232,8 @@ export const PROCESS_TASK_FRAGMENT_XL = gql`
232
232
  helpText
233
233
  validationRegex
234
234
  queryName
235
+ validationQueryOnCheck
236
+ validationQueryOnSubmit
235
237
  created
236
238
  modified
237
239
  schemas {
@@ -243,7 +245,9 @@ export const PROCESS_TASK_FRAGMENT_XL = gql`
243
245
  validationRegex
244
246
  options {
245
247
  id
248
+ sort
246
249
  label
250
+ optionValue
247
251
  }
248
252
  sort
249
253
  isRequired
@@ -24,6 +24,8 @@ export const PROCESS_TEMPLATE_FRAGMENT = gql`
24
24
  helpText
25
25
  validationRegex
26
26
  queryName
27
+ validationQueryOnCheck
28
+ validationQueryOnSubmit
27
29
  created
28
30
  modified
29
31
  defaultValue
@@ -36,7 +38,9 @@ export const PROCESS_TEMPLATE_FRAGMENT = gql`
36
38
  validationRegex
37
39
  options {
38
40
  id
41
+ sort
39
42
  label
43
+ optionValue
40
44
  }
41
45
  sort
42
46
  isRequired
@@ -72,3 +76,29 @@ export const PROCESS_TEMPLATE_GROUP_FRAGMENT = gql`
72
76
  isActive
73
77
  }
74
78
  `;
79
+
80
+ export const WIZARD_FIELD_VALIDATION_FRAGMENT = gql`
81
+ fragment WizardFieldValidationFragment on WizardFieldValidationResult {
82
+ fieldName
83
+ isValid
84
+ message
85
+ }
86
+ `;
87
+
88
+ export const FIELD_VALUE_FRAGMENT = gql`
89
+ fragment FieldValueFragment on FieldValue {
90
+ name
91
+ value
92
+ }
93
+ `;
94
+
95
+ export const FIELD_VALUE_RESULT_FRAGMENT = gql`
96
+ ${FIELD_VALUE_FRAGMENT}
97
+ fragment FieldValueResultFragment on FieldValueResult {
98
+ fieldName
99
+ message
100
+ values {
101
+ ...FieldValueFragment
102
+ }
103
+ }
104
+ `;
@@ -1,9 +1,11 @@
1
1
  import { gql } from "graphql-request";
2
2
 
3
3
  import {
4
+ FIELD_VALUE_RESULT_FRAGMENT,
4
5
  PROCESS_TEMPLATE_FRAGMENT_XS,
5
6
  PROCESS_TEMPLATE_GROUP_FRAGMENT,
6
7
  PROCESS_TEMPLATE_RECORD_FRAGMENT,
8
+ WIZARD_FIELD_VALIDATION_FRAGMENT,
7
9
  } from "./fragments";
8
10
 
9
11
  const _GetProcessTemplateRecords = gql`
@@ -65,3 +67,30 @@ const _GetProcessTemplates = gql`
65
67
  }
66
68
  }
67
69
  `;
70
+
71
+ export const VALIDATE_FIELD_ON_CHECK = gql`
72
+ ${WIZARD_FIELD_VALIDATION_FRAGMENT}
73
+ query ValidateFieldOnCheck($input: WizardFieldCheckValidationInput) {
74
+ validateFieldOnCheck(input: $input) {
75
+ ...WizardFieldValidationFragment
76
+ }
77
+ }
78
+ `;
79
+
80
+ export const VALIDATE_FIELD_ON_SUBMIT = gql`
81
+ ${WIZARD_FIELD_VALIDATION_FRAGMENT}
82
+ query ValidateFieldOnSubmit($input: [WizardFieldValidationInput]) {
83
+ validateFieldOnSubmit(input: $input) {
84
+ ...WizardFieldValidationFragment
85
+ }
86
+ }
87
+ `;
88
+
89
+ export const GET_FIELD_VALUES = gql`
90
+ ${FIELD_VALUE_RESULT_FRAGMENT}
91
+ query GetFieldValues($input: WizardFieldValidationInput) {
92
+ getFieldValues(input: $input) {
93
+ ...FieldValueResultFragment
94
+ }
95
+ }
96
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evenicanpm/admin-integrate",
3
- "version": "1.8.1",
3
+ "version": "2.0.0",
4
4
  "description": "e4Integrate Admin Panel",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,5 +21,5 @@
21
21
  "elkjs": "^0.10.0",
22
22
  "lodash": "^4.17.21"
23
23
  },
24
- "gitHead": "07cfd4496c6a137e1420a6572298998b25b6369d"
24
+ "gitHead": "7552c1e700a0027b8a65506c77cb10dae092fdfb"
25
25
  }
@@ -1,7 +1,7 @@
1
1
  import type { ConfigurationImportMutationVariables } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
2
2
  import { useMutation, useQueryClient } from "@tanstack/react-query";
3
- import { queryFn } from "./process-config-import.server";
4
3
  import { buildConfigurationExportQueryKey } from "../../../api/configuration/queries/configuration-export.query";
4
+ import { queryFn } from "./process-config-import.server";
5
5
 
6
6
  export const buildProcessScheduleGroupDetailsQueryKey = {
7
7
  all: () => ["configurationImport"] as const,
@@ -0,0 +1,48 @@
1
+ import type { GetFieldValuesQueryVariables } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
2
+ import {
3
+ type QueryClient,
4
+ type UseQueryOptions,
5
+ useQuery,
6
+ } from "@tanstack/react-query";
7
+ import { queryFn } from "./get-field-values.server";
8
+
9
+ export const buildGetFieldValuesQueryKey = {
10
+ all: () => ["getFieldValues"] as const,
11
+ byInput: (variables?: GetFieldValuesQueryVariables) => [
12
+ "getFieldValues",
13
+ variables,
14
+ ],
15
+ };
16
+
17
+ export const getFieldValues = {
18
+ queryKey: buildGetFieldValuesQueryKey.all(),
19
+
20
+ prefetch: (
21
+ queryClient: QueryClient,
22
+ variables: GetFieldValuesQueryVariables,
23
+ ) =>
24
+ queryClient.prefetchQuery({
25
+ queryKey: buildGetFieldValuesQueryKey.byInput(variables),
26
+ queryFn: () => queryFn(variables),
27
+ }),
28
+
29
+ fetchData: async (
30
+ queryClient: QueryClient,
31
+ variables: GetFieldValuesQueryVariables,
32
+ ) => {
33
+ return await queryClient.fetchQuery({
34
+ queryKey: buildGetFieldValuesQueryKey.byInput(variables),
35
+ queryFn: () => queryFn(variables),
36
+ });
37
+ },
38
+
39
+ useData: (
40
+ variables: GetFieldValuesQueryVariables,
41
+ options?: UseQueryOptions,
42
+ ) =>
43
+ useQuery({
44
+ queryKey: buildGetFieldValuesQueryKey.byInput(variables),
45
+ queryFn: () => queryFn(variables),
46
+ ...options,
47
+ }),
48
+ };
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import type { GetFieldValuesQueryVariables } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
3
+ import createGraphqlclient from "@evenicanpm/admin-core/api/sdk/graphqlClient.client";
4
+
5
+ export const queryFn = async (variables: GetFieldValuesQueryVariables) => {
6
+ const sdk = await createGraphqlclient();
7
+ const { data } = await sdk.GetFieldValues(variables);
8
+ return data;
9
+ };
@@ -1,3 +1,7 @@
1
+ export {
2
+ buildGetFieldValuesQueryKey,
3
+ getFieldValues,
4
+ } from "./get-field-values.query";
1
5
  export { getProcessTemplate } from "./get-process-template.query";
2
6
  export { getProcessTemplateGroups } from "./get-process-template-groups.query";
3
7
  export { getProcessTemplateRecords } from "./get-process-template-records.query";
@@ -1,10 +1,10 @@
1
1
  import type {
2
+ CheckUniqueIdentifierQuery,
3
+ CheckUniqueIdentifierQueryVariables,
2
4
  GetDataDescriptionsQuery,
3
5
  GetDataDescriptionsQueryVariables,
4
6
  GetSourceEndpointsQuery,
5
7
  GetSourceEndpointsQueryVariables,
6
- CheckUniqueIdentifierQuery,
7
- CheckUniqueIdentifierQueryVariables,
8
8
  } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
9
9
 
10
10
  export type TemplateInputSearchQueryVariables =
@@ -0,0 +1,22 @@
1
+ import type {
2
+ WizardFieldCheckValidationInput,
3
+ WizardFieldValidationResult,
4
+ } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
5
+ import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
6
+ import { queryFn } from "./validate-field-on-check.server";
7
+
8
+ export const buildValidateFieldOnCheckQueryKey = (
9
+ variables: WizardFieldCheckValidationInput,
10
+ ) => ["validateFieldOnCheck", variables] as const;
11
+
12
+ export const validateFieldOnCheckQuery = {
13
+ useData: (
14
+ variables: WizardFieldCheckValidationInput,
15
+ options?: UseQueryOptions<WizardFieldValidationResult | null>,
16
+ ) =>
17
+ useQuery({
18
+ queryKey: buildValidateFieldOnCheckQueryKey(variables),
19
+ queryFn: () => queryFn(variables),
20
+ ...options,
21
+ }),
22
+ };
@@ -0,0 +1,30 @@
1
+ "use server";
2
+
3
+ import type {
4
+ ValidateFieldOnCheckQueryVariables,
5
+ WizardFieldCheckValidationInput,
6
+ WizardFieldValidationResult,
7
+ } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
8
+ import createGraphqlclient from "@evenicanpm/admin-core/api/sdk/graphqlClient.client";
9
+
10
+ export const queryFn = async (
11
+ variables: WizardFieldCheckValidationInput,
12
+ ): Promise<WizardFieldValidationResult | null> => {
13
+ const sdk = await createGraphqlclient();
14
+ const { data } = await sdk.ValidateFieldOnCheck({
15
+ input: {
16
+ fieldId: variables.fieldId,
17
+ fieldName: variables.fieldName,
18
+ value: variables.value,
19
+ },
20
+ });
21
+ return data?.validateFieldOnCheck ?? null;
22
+ };
23
+
24
+ export async function validateFieldOnCheck(
25
+ payload: ValidateFieldOnCheckQueryVariables,
26
+ ): Promise<WizardFieldValidationResult | null> {
27
+ const sdk = await createGraphqlclient();
28
+ const { data } = await sdk.ValidateFieldOnCheck(payload);
29
+ return data?.validateFieldOnCheck ?? null;
30
+ }
@@ -0,0 +1,18 @@
1
+ "use server";
2
+
3
+ import type {
4
+ WizardFieldValidationInput,
5
+ WizardFieldValidationResult,
6
+ } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
7
+ import createGraphqlclient from "@evenicanpm/admin-core/api/sdk/graphqlClient.client";
8
+
9
+ export type ValidateFieldOnSubmitInput = WizardFieldValidationInput;
10
+
11
+ export async function validateFieldOnSubmit(
12
+ input: WizardFieldValidationInput[],
13
+ ): Promise<WizardFieldValidationResult[]> {
14
+ const sdk = await createGraphqlclient();
15
+ const { data } = await sdk.ValidateFieldOnSubmit({ input });
16
+ const results = data?.validateFieldOnSubmit ?? [];
17
+ return results.filter((r): r is WizardFieldValidationResult => r != null);
18
+ }
@@ -24,4 +24,4 @@ const StyledIconButton = styled(IconButton)(({ theme }) => ({
24
24
  ":hover": { color: theme.palette.info.main },
25
25
  }));
26
26
 
27
- export { StyledTableCell, StyledTableRow, StyledIconButton };
27
+ export { StyledIconButton, StyledTableCell, StyledTableRow };
@@ -2,6 +2,7 @@ import createSvgIcon from "@mui/material/utils/createSvgIcon";
2
2
 
3
3
  const UpDown = createSvgIcon(
4
4
  <svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
5
+ <title>Sort ascending and descending</title>
5
6
  <path
6
7
  d="M8.64847 6.88354H3.35158C3.04454 6.88354 2.86173 7.2269 3.03517 7.4812L5.68362 11.3824C5.83596 11.6062 6.16526 11.6062 6.3176 11.3824L8.96605 7.4812C9.13714 7.2269 8.9555 6.88354 8.64847 6.88354Z"
7
8
  fill="currentColor"
@@ -22,6 +22,7 @@ import {
22
22
  useNodesState,
23
23
  useReactFlow,
24
24
  } from "@xyflow/react";
25
+ import _ from "lodash";
25
26
  import type {
26
27
  ConfigExport,
27
28
  ProcessExecutionDetails,
@@ -31,15 +32,13 @@ import type {
31
32
  } from "../../../../admin-core/src/api/e4/graphqlRequestSdk";
32
33
  import { layoutOptions as elkOptions } from "./elk-layout-options";
33
34
  import type { ElkExtendedEdgeWithFlow, ElkNodeWithFlow } from "./elk-types";
34
-
35
- import _ from "lodash";
36
35
  import { edgeTypes, nodeTypes } from "./flow-types";
37
36
 
38
37
  import {
39
- mapToCamelCase,
40
38
  mapEmptyNodesAndEdges,
41
39
  mapProcessConfigToNodesAndEdges,
42
40
  mapProcessTasksToNodesAndEdges,
41
+ mapToCamelCase,
43
42
  } from "./utils/mapping";
44
43
 
45
44
  const elk = new ELK();
@@ -200,9 +199,9 @@ const IntegrationView: React.FC<Props> = ({
200
199
  const onConnect = useCallback(() => {}, []);
201
200
  const onLayout = useCallback(
202
201
  (processInput: any) => {
203
- let tasks;
202
+ let tasks: any;
204
203
 
205
- if (variant == "process") {
204
+ if (variant === "process") {
206
205
  tasks = processInput?.Processes[0]?.ProcessTasks?.map(
207
206
  (processTask: ProcessTaskExport) => mapToCamelCase(processTask),
208
207
  );
@@ -220,7 +219,7 @@ const IntegrationView: React.FC<Props> = ({
220
219
  );
221
220
 
222
221
  const mapped =
223
- variant == "process"
222
+ variant === "process"
224
223
  ? mapProcessConfigToNodesAndEdges(
225
224
  processInput,
226
225
  width,
@@ -333,10 +332,8 @@ const IntegrationView: React.FC<Props> = ({
333
332
  }, [configInput, processExecutionInput]);
334
333
 
335
334
  useLayoutEffect(() => {
336
- let data = globalThis.structuredClone(nodes);
337
-
338
- data = data.map((node: any) => {
339
- return {
335
+ setNodes((prevNodes: any[]) =>
336
+ prevNodes.map((node: any) => ({
340
337
  ...node,
341
338
  data: {
342
339
  ...node.data,
@@ -345,10 +342,8 @@ const IntegrationView: React.FC<Props> = ({
345
342
  selectedProcessTaskId === node.data?.processTask?.id ||
346
343
  selectedProcessTaskId === node.data?.processTaskExecution?.id,
347
344
  },
348
- };
349
- });
350
-
351
- setNodes(data);
345
+ })),
346
+ );
352
347
  }, [drawerOpen, selectedProcessTaskId]);
353
348
 
354
349
  const handleNodeDragStart = (_e: ReactMouseEvent, node: Node): any => {
@@ -392,7 +387,7 @@ const IntegrationView: React.FC<Props> = ({
392
387
  !edge.id.includes((node?.data?.processTask as ProcessTask)?.id),
393
388
  );
394
389
 
395
- let nodesFiltered = nodes.filter(
390
+ const nodesFiltered = nodes.filter(
396
391
  (node: any) => !nodeIds.includes(node?.id),
397
392
  );
398
393
 
@@ -3,8 +3,8 @@ import {
3
3
  Box,
4
4
  Card,
5
5
  CardContent,
6
- Typography,
7
6
  IconButton,
7
+ Typography,
8
8
  useTheme,
9
9
  } from "@mui/material";
10
10
  import { Handle, type NodeProps, Position } from "@xyflow/react";
@@ -1,21 +1,21 @@
1
- import {
2
- ProcessExecutionDetails,
1
+ import type {
3
2
  ConfigExport,
3
+ ProcessExecutionDetails,
4
4
  ProcessExport,
5
5
  ProcessTask,
6
- ProcessTaskExport,
7
6
  ProcessTaskExecution,
7
+ ProcessTaskExport,
8
8
  } from "@evenicanpm/admin-core/src/api/e4/graphqlRequestSdk";
9
- import { Process } from "../../../../../admin-core/src/api/e4/graphqlRequestSdk";
10
- import {
9
+ import { MarkerType } from "@xyflow/react";
10
+ import _ from "lodash";
11
+ import type { Process } from "../../../../../admin-core/src/api/e4/graphqlRequestSdk";
12
+ import type {
11
13
  ElkExtendedEdgeWithFlow,
12
14
  ElkNodeWithFlow,
13
15
  GroupNode,
14
16
  // ProcessTaskExecutionNode,
15
17
  // ProcessTaskNode,
16
18
  } from "../elk-types";
17
- import { MarkerType } from "@xyflow/react";
18
- import _ from "lodash";
19
19
 
20
20
  const markerEnd = {
21
21
  type: MarkerType.ArrowClosed,
@@ -24,10 +24,10 @@ const markerEnd = {
24
24
  };
25
25
 
26
26
  export function mapToCamelCase(processTask: ProcessTaskExport): ProcessTask {
27
- let key,
28
- keys = Object.keys(processTask);
27
+ let key: string;
28
+ const keys = Object.keys(processTask);
29
29
  let n = keys.length;
30
- let newobj: { [key: string]: any } = {};
30
+ const newobj: { [key: string]: any } = {};
31
31
  while (n--) {
32
32
  key = keys[n];
33
33
  newobj[key.substring(0, 1).toLowerCase() + key.substring(1)] =
@@ -296,7 +296,6 @@ export const mapProcessConfigToNodesAndEdges = (
296
296
  processTask: mapToCamelCase(task as ProcessTaskExport) || undefined,
297
297
  label: task?.Name as string,
298
298
  isLast: onAdd ? index === partitionLen - 1 : false,
299
- onAdd: index === partitionLen - 1 ? onAdd : undefined,
300
299
  },
301
300
  position: { x: 0, y: 0 },
302
301
  type: variant === "process" ? "task-node" : "execution-task-node",
@@ -293,6 +293,8 @@ const ListFilter = function ListFilter<FilterShape extends Filters>(
293
293
  onError={(e) => updateFilterErrors(name, e)}
294
294
  />
295
295
  );
296
+ default:
297
+ return null;
296
298
  }
297
299
  })}
298
300
  <Box sx={styles.buttonRow}>
@@ -0,0 +1,191 @@
1
+ "use client";
2
+
3
+ import { Box } from "@mui/material";
4
+ import { useFormikContext } from "formik";
5
+ import * as React from "react";
6
+ import type {
7
+ ErrorState,
8
+ FieldValue,
9
+ FormState,
10
+ ProcessTemplateInput,
11
+ ProcessTemplatePage,
12
+ } from "../types";
13
+ import { templateFieldKey } from "../types";
14
+ import { FormModeProvider } from "./context/FormModeContext";
15
+ import { TemplateProvider } from "./context/TemplateContext";
16
+ import { ReservedFieldName } from "./field-names";
17
+ import { InputType } from "./input-type";
18
+ import { renderFormControl } from "./renderers/renderFormControl";
19
+ import { arrangeInputs } from "./utils/arrangeInputs";
20
+
21
+ function isHiddenInput(input: ProcessTemplateInput | null): boolean {
22
+ return (
23
+ input?.inputType === InputType.HIDDEN ||
24
+ input?.inputType === InputType.HIDDEN_NUMBER ||
25
+ input?.inputType === InputType.HIDDEN_NUMBER_OR_NULL
26
+ );
27
+ }
28
+
29
+ function getDefaultHiddenFieldValue(
30
+ input: ProcessTemplateInput | null,
31
+ ): FieldValue {
32
+ if (input?.inputType === InputType.HIDDEN_NUMBER) return 0 as FieldValue;
33
+ if (input?.inputType === InputType.HIDDEN_NUMBER_OR_NULL) return null;
34
+ return "" as FieldValue;
35
+ }
36
+
37
+ export function FormikPageBody({
38
+ templateId,
39
+ page,
40
+ clearTemplateFields,
41
+ readOnly,
42
+ isEditMode,
43
+ isCreateMode,
44
+ disabledFields,
45
+ setFieldsDisabled,
46
+ templateConfig,
47
+ setFieldValidationInProgress,
48
+ submitValidationResults,
49
+ }: Readonly<{
50
+ templateId: string;
51
+ page: ProcessTemplatePage;
52
+ clearTemplateFields: (templateId: string) => void;
53
+ readOnly?: boolean;
54
+ isEditMode?: boolean;
55
+ isCreateMode?: boolean;
56
+ disabledFields?: Set<string>;
57
+ setFieldsDisabled?: (
58
+ templateId: string,
59
+ fieldNames: string[],
60
+ disabled: boolean,
61
+ ) => void;
62
+ templateConfig?: string;
63
+ setFieldValidationInProgress?: (inProgress: boolean) => void;
64
+ submitValidationResults?: Record<
65
+ string,
66
+ { isValid: boolean; message: string }
67
+ >;
68
+ }>) {
69
+ const {
70
+ values,
71
+ errors,
72
+ touched,
73
+ setFieldValue,
74
+ setFieldTouched,
75
+ validateField,
76
+ validateForm,
77
+ } = useFormikContext<FormState>();
78
+
79
+ React.useEffect(() => {
80
+ const hiddenInputs = page.inputs?.filter(isHiddenInput) ?? [];
81
+
82
+ for (const input of hiddenInputs) {
83
+ const key = templateFieldKey(templateId, input?.fieldName ?? "");
84
+ if (values[key] != null) continue;
85
+
86
+ if (input?.fieldName === ReservedFieldName.ProcessTemplateId) {
87
+ setFieldValue(key, Number(templateId));
88
+ continue;
89
+ }
90
+ setFieldValue(key, getDefaultHiddenFieldValue(input));
91
+ }
92
+ // eslint-disable-next-line react-hooks/exhaustive-deps
93
+ }, [templateId, page.id, page.inputs]);
94
+
95
+ const rows = React.useMemo(() => {
96
+ const inputs = (page.inputs ?? []).filter(
97
+ (inp): inp is ProcessTemplateInput => inp != null,
98
+ ) as ProcessTemplateInput[];
99
+ return arrangeInputs(inputs);
100
+ }, [page.inputs]);
101
+
102
+ const handleFieldChange = (
103
+ tId: string,
104
+ fieldName: string,
105
+ value: FieldValue,
106
+ ) => {
107
+ setFieldValue(templateFieldKey(tId, fieldName), value);
108
+ };
109
+
110
+ const errorsNormalized: ErrorState = React.useMemo(() => {
111
+ const out: Record<string, string | null> = {};
112
+ for (const key of Object.keys(errors ?? {})) {
113
+ const v = (errors as Record<string, unknown>)[key];
114
+ if (v == null) {
115
+ out[key] = null;
116
+ } else if (typeof v === "string") {
117
+ out[key] = v;
118
+ } else if (typeof v === "object") {
119
+ out[key] = "";
120
+ } else if (typeof v === "number" || typeof v === "boolean") {
121
+ out[key] = String(v);
122
+ } else {
123
+ out[key] = "";
124
+ }
125
+ }
126
+ return out;
127
+ }, [errors]);
128
+
129
+ const touchedNormalized: Record<string, boolean> = React.useMemo(() => {
130
+ const t = touched ?? {};
131
+ const out: Record<string, boolean> = {};
132
+ for (const key of Object.keys(t)) {
133
+ out[key] = (t as Record<string, unknown>)[key] === true;
134
+ }
135
+ return out;
136
+ }, [touched]);
137
+
138
+ const formControlProps = {
139
+ templateId,
140
+ values,
141
+ errors: errorsNormalized,
142
+ touched: touchedNormalized,
143
+ handleFieldChange,
144
+ setFieldTouched,
145
+ validateField,
146
+ validateForm,
147
+ readOnly,
148
+ disabledFields,
149
+ setFieldValidationInProgress,
150
+ submitValidationResults,
151
+ };
152
+
153
+ const renderRow = (
154
+ row: (typeof rows)[number],
155
+ idx: number,
156
+ ): React.ReactNode => {
157
+ if (row.type === "pair") {
158
+ const [a, b] = row.items;
159
+ return (
160
+ <Box key={idx} sx={{ display: "flex", gap: 2, marginTop: 2 }}>
161
+ {renderFormControl({ ...formControlProps, input: a })}
162
+ {renderFormControl({ ...formControlProps, input: b })}
163
+ </Box>
164
+ );
165
+ }
166
+ if (row.type === "full") {
167
+ return (
168
+ <Box key={idx} sx={{ mb: 2, marginTop: 2 }}>
169
+ {renderFormControl({ ...formControlProps, input: row.item })}
170
+ </Box>
171
+ );
172
+ }
173
+ return null;
174
+ };
175
+
176
+ return (
177
+ <FormModeProvider value={{ readOnly, isEditMode, isCreateMode }}>
178
+ <TemplateProvider
179
+ value={{
180
+ templateId,
181
+ templateConfig,
182
+ disabledFields,
183
+ setFieldsDisabled,
184
+ clearTemplateFields,
185
+ }}
186
+ >
187
+ <Box>{rows.map(renderRow)}</Box>
188
+ </TemplateProvider>
189
+ </FormModeProvider>
190
+ );
191
+ }
@@ -0,0 +1,31 @@
1
+ import * as React from "react";
2
+
3
+ type FormMode = {
4
+ readOnly?: boolean;
5
+ isEditMode?: boolean;
6
+ isCreateMode?: boolean;
7
+ };
8
+
9
+ const FormModeContext = React.createContext<FormMode | null>(null);
10
+
11
+ export function FormModeProvider({
12
+ value,
13
+ children,
14
+ }: Readonly<{
15
+ value: FormMode;
16
+ children: React.ReactNode;
17
+ }>) {
18
+ return (
19
+ <FormModeContext.Provider value={value}>
20
+ {children}
21
+ </FormModeContext.Provider>
22
+ );
23
+ }
24
+
25
+ export function useFormMode() {
26
+ const ctx = React.useContext(FormModeContext);
27
+ if (!ctx) {
28
+ throw new Error("useFormMode must be used inside FormModeProvider");
29
+ }
30
+ return ctx;
31
+ }