@evenicanpm/admin-integrate 2.0.0 → 2.0.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.
- package/documents/ConfigImport/configuration-import.ts +1 -1
- package/documents/Endpoint/list.ts +3 -3
- package/documents/Process/list.ts +3 -3
- package/documents/ProcessExecution/list.ts +2 -2
- package/documents/ProcessExport/read.ts +1 -1
- package/documents/ProcessSchedule/read.ts +1 -1
- package/documents/ProcessScheduleGroup/read.ts +3 -3
- package/documents/ProcessTemplate/read.ts +1 -1
- package/documents/ScheduledProcess/list.ts +1 -1
- package/package.json +2 -2
- package/src/components/integration-view/animated-svg.tsx +0 -1
- package/src/components/integration-view/elk-types.ts +1 -1
- package/src/components/integration-view/integration-view.tsx +267 -175
- package/src/components/integration-view/nodes/execution-entry-node.tsx +3 -2
- package/src/components/integration-view/types.ts +2 -0
- package/src/components/integration-view/utils/mapping.ts +62 -41
- package/src/components/list-filter/list-filter-types.ts +6 -0
- package/src/components/list-filter/list-filter.tsx +19 -15
- package/src/components/list-filter/multi-select-filter.tsx +7 -7
- package/src/components/list-filter/select-filter.tsx +6 -6
- package/src/components/scheduler/day-selector.tsx +1 -1
- package/src/components/templatesV2/inputs/form-type.ts +7 -1
- package/src/components/templatesV2/inputs/renderers/renderFormControl.tsx +19 -11
- package/src/components/templatesV2/inputs/renderers/renderSearchInput.tsx +3 -4
- package/src/components/templatesV2/inputs/search/useSearchInput.ts +12 -7
- package/src/components/templatesV2/inputs/table/InputTable.tsx +20 -11
- package/src/components/templatesV2/inputs/utils/arrangeInputs.ts +4 -3
- package/src/components/templatesV2/pageForm.tsx +9 -7
- package/src/components/templatesV2/validation/buildZodSchema.ts +0 -4
- package/src/components/templatesV2/wizard.tsx +5 -3
- package/src/pages/dashboard/dashboard-link-cards.tsx +0 -1
- package/src/pages/dashboard/dashboard-list-sections.tsx +1 -1
- package/src/pages/dashboard/dashboard.tsx +0 -1
- package/src/pages/executions/executions-list/executions-list-table.tsx +0 -1
- package/src/pages/executions/executions.tsx +1 -1
- package/src/pages/integration-create/integration-create.tsx +20 -14
- package/src/pages/integration-create/pre-creation-step.tsx +9 -9
- package/src/pages/integration-details/import-process/copy-tasks-list.tsx +1 -3
- package/src/pages/integration-details/integration-details.tsx +1 -1
- package/src/pages/integration-details/task-drawer/edit-task.tsx +2 -2
- package/src/pages/integration-details/task-drawer/task-drawer.tsx +2 -2
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
useTheme,
|
|
10
10
|
} from "@mui/material";
|
|
11
11
|
import { Handle, type NodeProps, Position } from "@xyflow/react";
|
|
12
|
+
import type { ReactNode } from "react";
|
|
12
13
|
|
|
13
14
|
export function ExecutionEntryNode(props: NodeProps): JSX.Element {
|
|
14
15
|
const theme = useTheme();
|
|
@@ -50,7 +51,7 @@ export function ExecutionEntryNode(props: NodeProps): JSX.Element {
|
|
|
50
51
|
}}
|
|
51
52
|
>
|
|
52
53
|
<CardContent sx={styles.cardContent}>
|
|
53
|
-
{props?.data?.icon as
|
|
54
|
+
{props?.data?.icon as ReactNode}
|
|
54
55
|
<Typography variant="h6" sx={styles.label}>
|
|
55
56
|
{props?.data?.label as string}
|
|
56
57
|
</Typography>
|
|
@@ -61,7 +62,7 @@ export function ExecutionEntryNode(props: NodeProps): JSX.Element {
|
|
|
61
62
|
<>
|
|
62
63
|
<Divider sx={styles.divider} />
|
|
63
64
|
<CardContent sx={styles.cardContent}>
|
|
64
|
-
{props?.data?.icon2 as
|
|
65
|
+
{props?.data?.icon2 as ReactNode}
|
|
65
66
|
<Typography variant="h6" sx={styles.label}>
|
|
66
67
|
{props?.data?.label2 as string}
|
|
67
68
|
</Typography>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { MarkerType } from "@xyflow/react";
|
|
2
|
+
import _ from "lodash";
|
|
1
3
|
import type {
|
|
2
4
|
ConfigExport,
|
|
5
|
+
Process,
|
|
3
6
|
ProcessExecutionDetails,
|
|
4
7
|
ProcessExport,
|
|
5
8
|
ProcessTask,
|
|
6
9
|
ProcessTaskExecution,
|
|
7
10
|
ProcessTaskExport,
|
|
8
|
-
} from "
|
|
9
|
-
import { MarkerType } from "@xyflow/react";
|
|
10
|
-
import _ from "lodash";
|
|
11
|
-
import type { Process } from "../../../../../admin-core/src/api/e4/graphqlRequestSdk";
|
|
11
|
+
} from "../../../../../admin-core/src/api/e4/graphqlRequestSdk";
|
|
12
12
|
import type {
|
|
13
13
|
ElkExtendedEdgeWithFlow,
|
|
14
14
|
ElkNodeWithFlow,
|
|
@@ -23,11 +23,23 @@ const markerEnd = {
|
|
|
23
23
|
height: 20,
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
type TaskRecord = Record<string, unknown>;
|
|
27
|
+
type BuildGroupsTask = (group: GroupNode) => TaskRecord[];
|
|
28
|
+
type BuildNodeMapper = (
|
|
29
|
+
task: TaskRecord,
|
|
30
|
+
index: number,
|
|
31
|
+
partitionLen: number,
|
|
32
|
+
parentId: string,
|
|
33
|
+
) => ElkNodeWithFlow;
|
|
34
|
+
export type AddHandler = unknown;
|
|
35
|
+
const asIdentifierString = (value: unknown) =>
|
|
36
|
+
typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
37
|
+
|
|
26
38
|
export function mapToCamelCase(processTask: ProcessTaskExport): ProcessTask {
|
|
27
39
|
let key: string;
|
|
28
40
|
const keys = Object.keys(processTask);
|
|
29
41
|
let n = keys.length;
|
|
30
|
-
const newobj:
|
|
42
|
+
const newobj: Record<string, unknown> = {};
|
|
31
43
|
while (n--) {
|
|
32
44
|
key = keys[n];
|
|
33
45
|
newobj[key.substring(0, 1).toLowerCase() + key.substring(1)] =
|
|
@@ -144,17 +156,17 @@ function buildGroupsAndEdges({
|
|
|
144
156
|
entryPoint: ElkNodeWithFlow;
|
|
145
157
|
entryPointConnector: ElkNodeWithFlow;
|
|
146
158
|
groupLabels: number[];
|
|
147
|
-
getGroupTasks:
|
|
159
|
+
getGroupTasks: BuildGroupsTask;
|
|
148
160
|
// nodeWidth: number,
|
|
149
161
|
variant: "process" | "process-execution";
|
|
150
|
-
onAdd?:
|
|
151
|
-
mapTaskToNode:
|
|
162
|
+
onAdd?: AddHandler;
|
|
163
|
+
mapTaskToNode: BuildNodeMapper;
|
|
152
164
|
groupSortKey: string;
|
|
153
165
|
taskIdKey: string;
|
|
154
166
|
taskNameKey: string;
|
|
155
167
|
connectorIdPrefix: string;
|
|
156
168
|
}) {
|
|
157
|
-
const groups: GroupNode[] = groupLabels.map((groupLabel:
|
|
169
|
+
const groups: GroupNode[] = groupLabels.map((groupLabel: number) => ({
|
|
158
170
|
id: `group-${groupLabel}`,
|
|
159
171
|
data: {
|
|
160
172
|
label: `Group ${groupLabel}`,
|
|
@@ -170,7 +182,7 @@ function buildGroupsAndEdges({
|
|
|
170
182
|
},
|
|
171
183
|
draggable: false,
|
|
172
184
|
}));
|
|
173
|
-
const edges:
|
|
185
|
+
const edges: ElkExtendedEdgeWithFlow[] = [];
|
|
174
186
|
edges.push({
|
|
175
187
|
id: `entry-point-entry-point-connector`,
|
|
176
188
|
sources: ["entry-point"],
|
|
@@ -187,21 +199,25 @@ function buildGroupsAndEdges({
|
|
|
187
199
|
});
|
|
188
200
|
const groupTasks = getGroupTasks(group);
|
|
189
201
|
const tasksPartitioned = _.values(_.groupBy(groupTasks, groupSortKey));
|
|
190
|
-
const groupNodes:
|
|
202
|
+
const groupNodes: ElkNodeWithFlow[] = [];
|
|
191
203
|
tasksPartitioned.forEach((partition) => {
|
|
192
|
-
partition.forEach((task:
|
|
204
|
+
partition.forEach((task: TaskRecord, index: number) => {
|
|
193
205
|
groupNodes.push(mapTaskToNode(task, index, partition.length, group.id));
|
|
194
206
|
});
|
|
195
207
|
});
|
|
196
208
|
let prevConnectorId: string | null = null;
|
|
197
209
|
tasksPartitioned.forEach((partition, tpIndex) => {
|
|
198
|
-
_.sortBy(partition, [(task:
|
|
210
|
+
_.sortBy(partition, [(task: TaskRecord) => task[taskNameKey]]);
|
|
199
211
|
if (prevConnectorId) {
|
|
200
|
-
|
|
212
|
+
const fromConnectorId = prevConnectorId;
|
|
213
|
+
partition.forEach((task: TaskRecord) => {
|
|
214
|
+
const taskIdentifier = asIdentifierString(
|
|
215
|
+
task[taskIdKey] ?? task[taskNameKey],
|
|
216
|
+
);
|
|
201
217
|
edges.push({
|
|
202
|
-
id: `${
|
|
203
|
-
sources: [
|
|
204
|
-
targets: [`task-${
|
|
218
|
+
id: `${fromConnectorId}-${taskIdentifier}`,
|
|
219
|
+
sources: [fromConnectorId],
|
|
220
|
+
targets: [`task-${taskIdentifier}`],
|
|
205
221
|
type: "default-edge",
|
|
206
222
|
markerEnd: markerEnd,
|
|
207
223
|
});
|
|
@@ -210,10 +226,13 @@ function buildGroupsAndEdges({
|
|
|
210
226
|
const connectorId = `${connectorIdPrefix}${group.id}-connect-${tpIndex}`;
|
|
211
227
|
prevConnectorId = connectorId;
|
|
212
228
|
if (tpIndex !== tasksPartitioned.length - 1) {
|
|
213
|
-
partition.forEach((task:
|
|
229
|
+
partition.forEach((task: TaskRecord) => {
|
|
230
|
+
const taskIdentifier = asIdentifierString(
|
|
231
|
+
task[taskIdKey] ?? task[taskNameKey],
|
|
232
|
+
);
|
|
214
233
|
edges.push({
|
|
215
|
-
id: `task-${
|
|
216
|
-
sources: [`task-${
|
|
234
|
+
id: `task-${taskIdentifier}-${connectorId}`,
|
|
235
|
+
sources: [`task-${taskIdentifier}`],
|
|
217
236
|
targets: [connectorId],
|
|
218
237
|
type: "default-edge",
|
|
219
238
|
});
|
|
@@ -240,7 +259,7 @@ export const mapProcessConfigToNodesAndEdges = (
|
|
|
240
259
|
data: ConfigExport,
|
|
241
260
|
nodeWidth: number,
|
|
242
261
|
variant: "process" | "process-execution",
|
|
243
|
-
onAdd?:
|
|
262
|
+
onAdd?: AddHandler,
|
|
244
263
|
) => {
|
|
245
264
|
const process = data.Processes?.[0] as ProcessExport;
|
|
246
265
|
const entryPoint: ElkNodeWithFlow = {
|
|
@@ -273,25 +292,25 @@ export const mapProcessConfigToNodesAndEdges = (
|
|
|
273
292
|
entryPoint,
|
|
274
293
|
entryPointConnector,
|
|
275
294
|
groupLabels,
|
|
276
|
-
getGroupTasks: (group:
|
|
295
|
+
getGroupTasks: (group: GroupNode) =>
|
|
277
296
|
_.sortBy(
|
|
278
297
|
process?.ProcessTasks?.filter(
|
|
279
|
-
(task) =>
|
|
280
|
-
task
|
|
281
|
-
group.id.split("-")[1],
|
|
282
|
-
),
|
|
298
|
+
(task): task is ProcessTaskExport =>
|
|
299
|
+
task != null &&
|
|
300
|
+
task.ParallelProcessingGroup?.toString() === group.id.split("-")[1],
|
|
301
|
+
) ?? [],
|
|
283
302
|
["Sort", "Name"],
|
|
284
|
-
),
|
|
303
|
+
) as TaskRecord[],
|
|
285
304
|
//nodeWidth,
|
|
286
305
|
variant,
|
|
287
306
|
onAdd,
|
|
288
307
|
mapTaskToNode: (
|
|
289
|
-
task:
|
|
308
|
+
task: TaskRecord,
|
|
290
309
|
index: number,
|
|
291
310
|
partitionLen: number,
|
|
292
311
|
parentId: string,
|
|
293
312
|
) => ({
|
|
294
|
-
id: `task-${task
|
|
313
|
+
id: `task-${asIdentifierString(task.ProcessTaskId ?? task.Name)}`,
|
|
295
314
|
data: {
|
|
296
315
|
processTask: mapToCamelCase(task as ProcessTaskExport) || undefined,
|
|
297
316
|
label: task?.Name as string,
|
|
@@ -359,28 +378,30 @@ export const mapProcessTasksToNodesAndEdges = (
|
|
|
359
378
|
entryPoint,
|
|
360
379
|
entryPointConnector,
|
|
361
380
|
groupLabels,
|
|
362
|
-
getGroupTasks: (group:
|
|
363
|
-
|
|
364
|
-
|
|
381
|
+
getGroupTasks: (group: GroupNode) => {
|
|
382
|
+
const tasks =
|
|
383
|
+
variant === "process"
|
|
365
384
|
? (data as Process)?.processTasks
|
|
366
|
-
: (data as ProcessExecutionDetails)?.processTaskExecutions
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
385
|
+
: (data as ProcessExecutionDetails)?.processTaskExecutions;
|
|
386
|
+
return _.sortBy(
|
|
387
|
+
tasks?.filter(
|
|
388
|
+
(task): task is ProcessTask | ProcessTaskExecution =>
|
|
389
|
+
task != null &&
|
|
390
|
+
task.parallelProcessingGroup?.toString() === group.id.split("-")[1],
|
|
391
|
+
) ?? [],
|
|
372
392
|
["sort", "name"],
|
|
373
|
-
)
|
|
393
|
+
) as TaskRecord[];
|
|
394
|
+
},
|
|
374
395
|
//nodeWidth,
|
|
375
396
|
variant,
|
|
376
397
|
onAdd: undefined,
|
|
377
398
|
mapTaskToNode: (
|
|
378
|
-
task:
|
|
399
|
+
task: TaskRecord,
|
|
379
400
|
index: number,
|
|
380
401
|
partitionLen: number,
|
|
381
402
|
parentId: string,
|
|
382
403
|
) => ({
|
|
383
|
-
id: `task-${task
|
|
404
|
+
id: `task-${asIdentifierString(task.id)}`,
|
|
384
405
|
data: {
|
|
385
406
|
processTask: variant === "process" ? (task as ProcessTask) : undefined,
|
|
386
407
|
processTaskExecution:
|
|
@@ -38,6 +38,12 @@ export interface Filters {
|
|
|
38
38
|
| MultiSelectFilter;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export type FilterValue =
|
|
42
|
+
| DateFilter["value"]
|
|
43
|
+
| DateRangeFilter["value"]
|
|
44
|
+
| SelectFilter["value"]
|
|
45
|
+
| MultiSelectFilter["value"];
|
|
46
|
+
|
|
41
47
|
export type FilterResult<FilterShape extends Filters> = {
|
|
42
48
|
[Property in keyof FilterShape]: FilterShape[Property]["value"];
|
|
43
49
|
};
|
|
@@ -33,6 +33,7 @@ import type {
|
|
|
33
33
|
FilterConfig,
|
|
34
34
|
FilterResult,
|
|
35
35
|
Filters,
|
|
36
|
+
FilterValue,
|
|
36
37
|
ListFilterOutput,
|
|
37
38
|
} from "./list-filter-types";
|
|
38
39
|
import MultiSelectFilterComponent from "./multi-select-filter";
|
|
@@ -71,22 +72,22 @@ const ListFilter = function ListFilter<FilterShape extends Filters>(
|
|
|
71
72
|
|
|
72
73
|
const defaultValues = Object.entries(filters).reduce(
|
|
73
74
|
(values, [key, filter]) => {
|
|
74
|
-
if (filter.type === "select" && filter.value)
|
|
75
|
-
return {
|
|
76
|
-
...values,
|
|
75
|
+
if (filter.type === "select" && filter.value) {
|
|
76
|
+
return Object.assign(values, {
|
|
77
77
|
// @ts-expect-error
|
|
78
78
|
[key]: filter.options.find((o) => o.id === filter.value[0].id),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (filter.type === "multiSelect" && filter.value) {
|
|
82
|
+
return Object.assign(values, {
|
|
83
83
|
[key]: filter.options.filter((o) =>
|
|
84
84
|
// @ts-expect-error
|
|
85
85
|
filter.value.find((v) => v.id === o.id),
|
|
86
86
|
),
|
|
87
|
-
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
88
89
|
|
|
89
|
-
return
|
|
90
|
+
return Object.assign(values, { [key]: filter.value });
|
|
90
91
|
},
|
|
91
92
|
{},
|
|
92
93
|
) as FilterResult<FilterShape>;
|
|
@@ -94,10 +95,10 @@ const ListFilter = function ListFilter<FilterShape extends Filters>(
|
|
|
94
95
|
const filterErrorsBase: FilterErrors<FilterShape> = Object.keys(
|
|
95
96
|
filters,
|
|
96
97
|
).reduce(
|
|
97
|
-
(values, key) =>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
(values, key) =>
|
|
99
|
+
Object.assign(values, {
|
|
100
|
+
[key]: false,
|
|
101
|
+
}),
|
|
101
102
|
{},
|
|
102
103
|
) as FilterErrors<FilterShape>;
|
|
103
104
|
|
|
@@ -124,7 +125,7 @@ const ListFilter = function ListFilter<FilterShape extends Filters>(
|
|
|
124
125
|
0,
|
|
125
126
|
);
|
|
126
127
|
|
|
127
|
-
const updateFilterValue = (name: string, value:
|
|
128
|
+
const updateFilterValue = (name: string, value: FilterValue | undefined) => {
|
|
128
129
|
if (Array.isArray(value) && !value.length) value = null;
|
|
129
130
|
setFilterValues({
|
|
130
131
|
...filterValues,
|
|
@@ -174,7 +175,10 @@ const ListFilter = function ListFilter<FilterShape extends Filters>(
|
|
|
174
175
|
|
|
175
176
|
const handleFilterClear = () => {
|
|
176
177
|
const emptyFilterValues = Object.keys(filterValues).reduce(
|
|
177
|
-
(values, key) =>
|
|
178
|
+
(values, key) =>
|
|
179
|
+
Object.assign(values, {
|
|
180
|
+
[key]: null,
|
|
181
|
+
}),
|
|
178
182
|
{},
|
|
179
183
|
) as FilterResult<FilterShape>;
|
|
180
184
|
setPublishedFilterValues(emptyFilterValues);
|
|
@@ -31,15 +31,15 @@ const MultiSelectFilterComponent: React.FC<FilterProps<MultiSelectFilter>> = ({
|
|
|
31
31
|
const t = useTranslations("Integrate");
|
|
32
32
|
|
|
33
33
|
const mappedOptionDictionary = filter.options.reduce(
|
|
34
|
-
(dictionary, option) =>
|
|
35
|
-
|
|
36
|
-
[option.id]: {
|
|
34
|
+
(dictionary, option) => {
|
|
35
|
+
dictionary[option.id] = {
|
|
37
36
|
id: option.id,
|
|
38
37
|
value: t(option.value),
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
};
|
|
39
|
+
return dictionary;
|
|
40
|
+
},
|
|
41
|
+
{} as { [id: string | number]: FilterOption },
|
|
42
|
+
);
|
|
43
43
|
|
|
44
44
|
const [value, setValue] = useState(current);
|
|
45
45
|
|
|
@@ -31,12 +31,12 @@ const SelectFilterComponent: React.FC<FilterProps<SelectFilter>> = ({
|
|
|
31
31
|
const [value, setValue] = useState(current);
|
|
32
32
|
|
|
33
33
|
const mappedOptionDictionary = filter.options.reduce(
|
|
34
|
-
(dictionary, option) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
{},
|
|
39
|
-
)
|
|
34
|
+
(dictionary: { [id: string | number]: FilterOption }, option) => {
|
|
35
|
+
dictionary[option.id] = option;
|
|
36
|
+
return dictionary;
|
|
37
|
+
},
|
|
38
|
+
{} as { [id: string | number]: FilterOption },
|
|
39
|
+
);
|
|
40
40
|
|
|
41
41
|
const updateValue = (optionId: string | number | null) => {
|
|
42
42
|
if (optionId == null) {
|
|
@@ -158,7 +158,7 @@ const getStyles = (theme: Theme): DaySelectorStyles => {
|
|
|
158
158
|
},
|
|
159
159
|
dayOfWeek: {
|
|
160
160
|
color: "grey.700",
|
|
161
|
-
border:
|
|
161
|
+
border: `solid ${theme.palette.grey[500]} ${theme.spacing(0.5)}`,
|
|
162
162
|
backgroundColor: theme.palette.grey[50],
|
|
163
163
|
borderRadius: "50%",
|
|
164
164
|
width: theme.spacing(5),
|
|
@@ -5,6 +5,12 @@ export type TableRow = Record<string, string | number | boolean | null>;
|
|
|
5
5
|
|
|
6
6
|
export type SetRowsFn = (rows: TableRow[]) => void;
|
|
7
7
|
|
|
8
|
+
/** Used for TEXT_UNIQUE_IDENTIFIER when updating a sibling field (e.g. `isUnique`). */
|
|
9
|
+
export type SearchInputExtendedSetValue = (
|
|
10
|
+
v: FieldValue,
|
|
11
|
+
fieldName?: string,
|
|
12
|
+
) => void;
|
|
13
|
+
|
|
8
14
|
export interface InputTableProps {
|
|
9
15
|
rows: TableRow[];
|
|
10
16
|
setRows: SetRowsFn;
|
|
@@ -25,7 +31,7 @@ export type SearchInputWrapperProps = {
|
|
|
25
31
|
setValue:
|
|
26
32
|
| ((v: string) => void)
|
|
27
33
|
| ((v: string[]) => void)
|
|
28
|
-
|
|
|
34
|
+
| SearchInputExtendedSetValue;
|
|
29
35
|
|
|
30
36
|
placeholder?: string | null;
|
|
31
37
|
helpText?: string | null;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Box, FormHelperText, Typography } from "@mui/material";
|
|
4
|
-
import { Field } from "formik";
|
|
4
|
+
import { Field, type FieldProps } from "formik";
|
|
5
5
|
import type * as React from "react";
|
|
6
6
|
import type {
|
|
7
7
|
ErrorState,
|
|
@@ -76,9 +76,13 @@ function queryInputType(
|
|
|
76
76
|
function normalizeInputTableRows(
|
|
77
77
|
value: unknown,
|
|
78
78
|
input: ProcessTemplateInput,
|
|
79
|
-
): Array<Record<string,
|
|
80
|
-
const rows: Array<
|
|
81
|
-
|
|
79
|
+
): Array<Record<string, string | number | boolean | null | undefined>> {
|
|
80
|
+
const rows: Array<
|
|
81
|
+
Record<string, string | number | boolean | null | undefined>
|
|
82
|
+
> = Array.isArray(value)
|
|
83
|
+
? (value as Array<
|
|
84
|
+
Record<string, string | number | boolean | null | undefined>
|
|
85
|
+
>)
|
|
82
86
|
: [];
|
|
83
87
|
if (!value || rows.length > 0 || (input.schemas?.length ?? 0) !== 2) {
|
|
84
88
|
return rows;
|
|
@@ -151,7 +155,11 @@ function renderInputTable({
|
|
|
151
155
|
<InputTable
|
|
152
156
|
rows={rows}
|
|
153
157
|
setRows={(newRows) =>
|
|
154
|
-
handleFieldChange(
|
|
158
|
+
handleFieldChange(
|
|
159
|
+
templateId,
|
|
160
|
+
input.fieldName ?? "",
|
|
161
|
+
newRows as Array<Record<string, string>>,
|
|
162
|
+
)
|
|
155
163
|
}
|
|
156
164
|
schemas={(input.schemas as ProcessTemplateInputSchema[]) ?? []}
|
|
157
165
|
tableError={tableErrorToShow ?? null}
|
|
@@ -204,7 +212,7 @@ export function renderFormControl({
|
|
|
204
212
|
value: FieldValue,
|
|
205
213
|
) => void;
|
|
206
214
|
setFieldTouched?: (field: string, value: boolean) => void;
|
|
207
|
-
validateField?: (field: string) =>
|
|
215
|
+
validateField?: (field: string) => undefined | Promise<unknown>;
|
|
208
216
|
validateForm?: () => Promise<Record<string, unknown>>;
|
|
209
217
|
readOnly?: boolean;
|
|
210
218
|
disabledFields?: Set<string>;
|
|
@@ -230,7 +238,7 @@ export function renderFormControl({
|
|
|
230
238
|
const submitValidationResult = submitValidationResults?.[k] ?? null;
|
|
231
239
|
return (
|
|
232
240
|
<Field name={k}>
|
|
233
|
-
{({ field, form, meta }:
|
|
241
|
+
{({ field, form, meta }: FieldProps) => (
|
|
234
242
|
<TextWithQueryInput
|
|
235
243
|
inputType={queryInputTypeVal}
|
|
236
244
|
label={input.label ?? ""}
|
|
@@ -264,7 +272,7 @@ export function renderFormControl({
|
|
|
264
272
|
if (input.inputType === InputType.CHECKBOX) {
|
|
265
273
|
return (
|
|
266
274
|
<Field name={k}>
|
|
267
|
-
{({ field, form }:
|
|
275
|
+
{({ field, form }: FieldProps) => (
|
|
268
276
|
<CheckboxInput
|
|
269
277
|
label={input.label ?? ""}
|
|
270
278
|
checked={Boolean(field.value ?? false)}
|
|
@@ -280,7 +288,7 @@ export function renderFormControl({
|
|
|
280
288
|
if (input.inputType === InputType.NUMBER) {
|
|
281
289
|
return (
|
|
282
290
|
<Field name={k}>
|
|
283
|
-
{({ field, form, meta }:
|
|
291
|
+
{({ field, form, meta }: FieldProps) => (
|
|
284
292
|
<NumberInput
|
|
285
293
|
label={input.label ?? ""}
|
|
286
294
|
value={(field.value as number) ?? ""}
|
|
@@ -299,7 +307,7 @@ export function renderFormControl({
|
|
|
299
307
|
if (input.inputType === InputType.SELECTOR) {
|
|
300
308
|
return (
|
|
301
309
|
<Field name={k}>
|
|
302
|
-
{({ field, form, meta }:
|
|
310
|
+
{({ field, form, meta }: FieldProps) => (
|
|
303
311
|
<SelectorInput
|
|
304
312
|
fieldName={input.fieldName ?? ""}
|
|
305
313
|
label={input.label ?? ""}
|
|
@@ -359,7 +367,7 @@ export function renderFormControl({
|
|
|
359
367
|
|
|
360
368
|
return (
|
|
361
369
|
<Field name={k}>
|
|
362
|
-
{({ field, form, meta }:
|
|
370
|
+
{({ field, form, meta }: FieldProps) => (
|
|
363
371
|
<TextInput
|
|
364
372
|
label={input.label ?? ""}
|
|
365
373
|
value={(field.value as string) ?? ""}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Field, type FieldProps } from "formik";
|
|
4
|
-
import * as React from "react";
|
|
5
4
|
import {
|
|
6
5
|
type FieldValue,
|
|
7
6
|
type ProcessTemplateInput,
|
|
@@ -46,7 +45,7 @@ export function renderSearchInput({
|
|
|
46
45
|
if (input.inputType === InputType.MULTI_TEXT_SEARCH) {
|
|
47
46
|
return (
|
|
48
47
|
<Field name={k}>
|
|
49
|
-
{({ field, form, meta }:
|
|
48
|
+
{({ field, form, meta }: FieldProps) => (
|
|
50
49
|
<SearchInputWrapper
|
|
51
50
|
inputType={InputType.MULTI_TEXT_SEARCH}
|
|
52
51
|
queryName={queryName}
|
|
@@ -66,7 +65,7 @@ export function renderSearchInput({
|
|
|
66
65
|
if (input.inputType === InputType.TEXT_SEARCH) {
|
|
67
66
|
return (
|
|
68
67
|
<Field name={k}>
|
|
69
|
-
{({ field, form, meta }:
|
|
68
|
+
{({ field, form, meta }: FieldProps) => (
|
|
70
69
|
<SearchInputWrapper
|
|
71
70
|
inputType={InputType.TEXT_SEARCH}
|
|
72
71
|
queryName={queryName}
|
|
@@ -97,7 +96,7 @@ export function renderSearchInput({
|
|
|
97
96
|
|
|
98
97
|
<Field name={k}>
|
|
99
98
|
{({ field, form, meta }: FieldProps) => {
|
|
100
|
-
const setUniqueValue = (v:
|
|
99
|
+
const setUniqueValue = (v: FieldValue, fieldName?: string) => {
|
|
101
100
|
const targetKey = fieldName
|
|
102
101
|
? templateFieldKey(templateId, fieldName)
|
|
103
102
|
: k;
|
|
@@ -3,19 +3,21 @@ import type {
|
|
|
3
3
|
GetSourceEndpointsQuery,
|
|
4
4
|
} from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
|
|
5
5
|
import { templateInputSearch } from "@evenicanpm/admin-integrate/api/templates/queries";
|
|
6
|
-
import type { TemplateInputSearchQueryKey } from "@evenicanpm/admin-integrate/api/templates/queries/types";
|
|
7
6
|
import { useSearchParams } from "next/navigation";
|
|
8
7
|
import React from "react";
|
|
9
8
|
import type { SearchOption } from "../../types";
|
|
10
9
|
import { ReservedFieldName } from "../field-names";
|
|
10
|
+
import type {
|
|
11
|
+
SearchInputExtendedSetValue,
|
|
12
|
+
SearchInputWrapperProps,
|
|
13
|
+
} from "../form-type";
|
|
11
14
|
import { InputType } from "../input-type";
|
|
12
15
|
import { TemplateSearchQueryKey } from "./search-query-key";
|
|
13
16
|
|
|
14
|
-
type UseSearchInputProps =
|
|
15
|
-
|
|
16
|
-
queryName
|
|
17
|
-
|
|
18
|
-
};
|
|
17
|
+
type UseSearchInputProps = Pick<
|
|
18
|
+
SearchInputWrapperProps,
|
|
19
|
+
"inputType" | "queryName" | "setValue"
|
|
20
|
+
>;
|
|
19
21
|
|
|
20
22
|
export function useSearchInput({
|
|
21
23
|
inputType,
|
|
@@ -59,7 +61,10 @@ export function useSearchInput({
|
|
|
59
61
|
const typed = data as CheckUniqueIdentifierQuery;
|
|
60
62
|
const unique = typed.checkUniqueIdentifier?.isUnique ?? null;
|
|
61
63
|
setIsUnique(unique);
|
|
62
|
-
setValue?.(
|
|
64
|
+
(setValue as SearchInputExtendedSetValue | undefined)?.(
|
|
65
|
+
unique,
|
|
66
|
+
ReservedFieldName.IsUnique,
|
|
67
|
+
);
|
|
63
68
|
break;
|
|
64
69
|
}
|
|
65
70
|
}
|
|
@@ -28,15 +28,17 @@ import { renderReadOnlyText } from "../utils/renderReadOnlyText";
|
|
|
28
28
|
/** Reserved key for React list key; not a schema column. */
|
|
29
29
|
const ROW_ID_KEY = "__rowId" as const;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
type RowRecord = Record<string, string | number | boolean | null | undefined>;
|
|
32
|
+
|
|
33
|
+
function getRowId(row: RowRecord, index: number): string {
|
|
32
34
|
const id = row[ROW_ID_KEY];
|
|
33
35
|
if (typeof id === "string" && id.length > 0) return id;
|
|
34
36
|
return `row-${index}`;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
function ensureRowIds(
|
|
38
|
-
rows:
|
|
39
|
-
setRows: (rows:
|
|
40
|
+
rows: RowRecord[],
|
|
41
|
+
setRows: (rows: RowRecord[]) => void,
|
|
40
42
|
): void {
|
|
41
43
|
const needsId = rows.some(
|
|
42
44
|
(r) => r[ROW_ID_KEY] == null || r[ROW_ID_KEY] === "",
|
|
@@ -60,8 +62,8 @@ export function InputTable({
|
|
|
60
62
|
readOnly,
|
|
61
63
|
onCellBlur,
|
|
62
64
|
}: Readonly<{
|
|
63
|
-
rows:
|
|
64
|
-
setRows: (rows:
|
|
65
|
+
rows: RowRecord[];
|
|
66
|
+
setRows: (rows: RowRecord[]) => void;
|
|
65
67
|
schemas: ProcessTemplateInputSchema[];
|
|
66
68
|
tableError: string | null;
|
|
67
69
|
rowErrors?: Array<Record<string, string>>;
|
|
@@ -95,7 +97,7 @@ export function InputTable({
|
|
|
95
97
|
}, [rows, ordered]);
|
|
96
98
|
|
|
97
99
|
const addRow = () => {
|
|
98
|
-
const empty:
|
|
100
|
+
const empty: RowRecord = {
|
|
99
101
|
[ROW_ID_KEY]: crypto.randomUUID(),
|
|
100
102
|
};
|
|
101
103
|
ordered.forEach((s, colIndex) => {
|
|
@@ -112,7 +114,11 @@ export function InputTable({
|
|
|
112
114
|
setRows(copy);
|
|
113
115
|
};
|
|
114
116
|
|
|
115
|
-
const updateCell = (
|
|
117
|
+
const updateCell = (
|
|
118
|
+
idx: number,
|
|
119
|
+
columnKey: string,
|
|
120
|
+
value: string | number | boolean | null | undefined,
|
|
121
|
+
) => {
|
|
116
122
|
const copy = [...rows];
|
|
117
123
|
copy[idx] = { ...copy[idx], [columnKey]: value };
|
|
118
124
|
setRows(copy);
|
|
@@ -141,7 +147,7 @@ export function InputTable({
|
|
|
141
147
|
</TableRow>
|
|
142
148
|
</TableHead>
|
|
143
149
|
<TableBody>
|
|
144
|
-
{(rows ?? []).map((r:
|
|
150
|
+
{(rows ?? []).map((r: RowRecord, i: number) => (
|
|
145
151
|
<TableRow key={getRowId(r, i)}>
|
|
146
152
|
{ordered.map(
|
|
147
153
|
(s: ProcessTemplateInputSchema, colIndex: number) => {
|
|
@@ -188,7 +194,7 @@ export function InputTable({
|
|
|
188
194
|
minWidth={120}
|
|
189
195
|
fieldName={columnKey}
|
|
190
196
|
label={s.label ?? ""}
|
|
191
|
-
value={cell}
|
|
197
|
+
value={cell == null ? "" : String(cell)}
|
|
192
198
|
options={opts}
|
|
193
199
|
setValue={(v) => updateCell(i, columnKey, v)}
|
|
194
200
|
error={cellError}
|
|
@@ -201,11 +207,14 @@ export function InputTable({
|
|
|
201
207
|
return (
|
|
202
208
|
<TableCell key={s.id}>
|
|
203
209
|
{readOnly ? (
|
|
204
|
-
renderReadOnlyText(
|
|
210
|
+
renderReadOnlyText(
|
|
211
|
+
undefined,
|
|
212
|
+
typeof cell === "boolean" ? String(cell) : cell,
|
|
213
|
+
)
|
|
205
214
|
) : (
|
|
206
215
|
<TextField
|
|
207
216
|
size="small"
|
|
208
|
-
value={cell}
|
|
217
|
+
value={cell == null ? "" : String(cell)}
|
|
209
218
|
onChange={(e) =>
|
|
210
219
|
updateCell(i, columnKey, e.target.value)
|
|
211
220
|
}
|