Skip to content

Commit 6f92f6b

Browse files
authored
Added combobox component for Relationship many (#4422)
1 parent dfc1370 commit 6f92f6b

34 files changed

+554
-129
lines changed

frontend/app/src/components/filters/utils/getFiltersFromFormData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const getFiltersFromFormData = (formData: Record<string, FormFieldValue>)
4343
...acc,
4444
{
4545
name: `${fieldName}__ids`,
46-
value: fieldValue.map(({ id }) => id),
46+
value: fieldValue,
4747
},
4848
];
4949
}

frontend/app/src/components/filters/utils/getObjectFromFilters.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Filter } from "@/hooks/useFilters";
22
import { IModelSchema } from "@/state/atoms/schema.atom";
33
import {
44
AttributeType,
5+
Node,
56
RelationshipManyType,
67
RelationshipOneType,
78
RelationshipType,
@@ -31,11 +32,11 @@ export const getObjectFromFilters = (
3132
...acc,
3233
[fieldName]: {
3334
edges: filter.value.map(
34-
(v: string) =>
35+
(v: Node) =>
3536
({
3637
node: {
37-
id: v,
38-
display_label: "",
38+
id: v.id,
39+
display_label: v.display_label,
3940
__typename: relationshipSchema.peer,
4041
},
4142
}) satisfies RelationshipOneType

frontend/app/src/components/form/dynamic-form.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import JsonField from "@/components/form/fields/json.field";
99
import ListField from "@/components/form/fields/list.field";
1010
import NumberField from "@/components/form/fields/number.field";
1111
import PasswordInputField from "@/components/form/fields/password-input.field";
12+
import RelationshipManyField from "@/components/form/fields/relationship-many.field";
1213
import RelationshipField from "@/components/form/fields/relationship.field";
1314
import TextareaField from "@/components/form/fields/textarea.field";
1415
import { DynamicFieldProps, FormFieldValue } from "@/components/form/type";
@@ -109,6 +110,11 @@ export const DynamicInput = (props: DynamicFieldProps) => {
109110
return <EnumField {...otherProps} />;
110111
}
111112
case "relationship": {
113+
if (props.relationship.cardinality === "many") {
114+
const { type, ...otherProps } = props;
115+
return <RelationshipManyField {...otherProps} />;
116+
}
117+
112118
return <RelationshipField {...props} />;
113119
}
114120
default: {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { LabelFormField } from "@/components/form/fields/common";
2+
import { DynamicRelationshipFieldProps, FormRelationshipValue } from "@/components/form/type";
3+
import { FormField, FormInput, FormMessage } from "@/components/ui/form";
4+
5+
import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
6+
import { updateRelationshipFieldValue } from "@/components/form/utils/updateFormFieldValue";
7+
import { RelationshipManyInput } from "@/components/inputs/relationship-many";
8+
import { Node } from "@/utils/getObjectItemDisplayValue";
9+
10+
export interface RelationshipManyInputProps extends Omit<DynamicRelationshipFieldProps, "type"> {}
11+
12+
export default function RelationshipManyField({
13+
defaultValue = DEFAULT_FORM_FIELD_VALUE,
14+
description,
15+
label,
16+
name,
17+
rules,
18+
unique,
19+
...props
20+
}: RelationshipManyInputProps) {
21+
return (
22+
<FormField
23+
key={name}
24+
name={name}
25+
rules={rules}
26+
defaultValue={defaultValue}
27+
render={({ field }) => {
28+
const fieldData: FormRelationshipValue = field.value;
29+
30+
return (
31+
<div className="flex flex-col gap-2">
32+
<LabelFormField
33+
label={label}
34+
unique={unique}
35+
required={!!rules?.required}
36+
description={description}
37+
fieldData={fieldData}
38+
/>
39+
40+
<FormInput>
41+
<RelationshipManyInput
42+
{...field}
43+
{...props}
44+
value={fieldData.value as Node[] | null}
45+
onChange={(newValue) => {
46+
field.onChange(updateRelationshipFieldValue(newValue, defaultValue));
47+
}}
48+
/>
49+
</FormInput>
50+
51+
<FormMessage />
52+
</div>
53+
);
54+
}}
55+
/>
56+
);
57+
}

frontend/app/src/components/form/type.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FormField } from "@/components/ui/form";
44
import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
55
import { AttributeSchema, RelationshipSchema } from "@/screens/schema/types";
66
import { IModelSchema } from "@/state/atoms/schema.atom";
7+
import { Node } from "@/utils/getObjectItemDisplayValue";
78
import { ComponentProps } from "react";
89

910
type SourceType = "schema" | "user";
@@ -55,18 +56,29 @@ export type FormAttributeValue =
5556
| AttributeValueFromPool
5657
| EmptyFieldValue;
5758

58-
export type RelationshipValueFromPool = {
59-
source: PoolSource;
60-
value: { id: string } | { from_pool: { id: string } };
59+
export type RelationshipOneValueFromUser = {
60+
source: {
61+
type: SourceType;
62+
};
63+
value: Node | null;
6164
};
6265

63-
export type RelationshipValueFromUser = {
66+
export type RelationshipManyValueFromUser = {
6467
source: {
6568
type: SourceType;
6669
};
67-
value: { id: string } | Array<{ id: string }> | null;
70+
value: Array<Node> | null;
6871
};
6972

73+
export type RelationshipValueFromPool = {
74+
source: PoolSource;
75+
value: Node | { from_pool: { id: string } };
76+
};
77+
78+
export type RelationshipValueFromUser =
79+
| RelationshipOneValueFromUser
80+
| RelationshipManyValueFromUser;
81+
7082
export type FormRelationshipValue =
7183
| RelationshipValueFromUser
7284
| RelationshipValueFromPool

frontend/app/src/components/form/utils/getRelationshipDefaultValue.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ export const getRelationshipDefaultValue = ({
2222
source: {
2323
type: "user",
2424
},
25-
value: relationshipData.edges.map(({ node }) => ({
26-
id: node?.id!,
27-
})),
25+
value: relationshipData.edges
26+
.map(({ node }) =>
27+
node
28+
? {
29+
id: node.id,
30+
display_label: node.display_label,
31+
__typename: node.__typename,
32+
}
33+
: null
34+
)
35+
.filter((n) => !!n),
2836
};
2937
}
3038

@@ -49,6 +57,11 @@ export const getRelationshipDefaultValue = ({
4957
const sourceSchema = nodes.find(({ kind }) => kind === sourceKind);
5058

5159
if (sourceSchema && sourceSchema.inherit_from?.includes(RESOURCE_GENERIC_KIND)) {
60+
if (!relationshipData.node) {
61+
console.error("Source is a pool but node is null on relationship", relationshipData);
62+
return { source: null, value: null };
63+
}
64+
5265
return {
5366
source: {
5467
type: "pool",

frontend/app/src/components/form/utils/mutations/getCreateMutationFromFormData.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,32 @@ export const getCreateMutationFromFormData = (
1616
return acc;
1717
}
1818

19+
if (isFormFieldValueFromPool(fieldData)) {
20+
return { ...acc, [field.name]: fieldData.value };
21+
}
22+
1923
if (fieldData.source?.type === "user") {
24+
if (fieldData.value === null) {
25+
return { ...acc, [field.name]: { value: null } };
26+
}
27+
28+
if (typeof fieldData.value === "object") {
29+
const fieldValue = Array.isArray(fieldData.value)
30+
? fieldData.value.map(({ id }) => ({ id }))
31+
: { id: fieldData.value.id };
32+
return {
33+
...acc,
34+
[field.name]: fieldValue,
35+
};
36+
}
37+
2038
const fieldValue = fieldData.value === "" ? null : fieldData.value;
2139
return {
2240
...acc,
23-
[field.name]: field.type === "relationship" ? fieldValue : { value: fieldValue },
41+
[field.name]: { value: fieldValue },
2442
};
2543
}
2644

27-
if (isFormFieldValueFromPool(fieldData)) {
28-
return { ...acc, [field.name]: fieldData.value };
29-
}
30-
3145
return acc;
3246
}, {});
3347
};

frontend/app/src/components/form/utils/mutations/getUpdateMutationFromFormData.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,30 @@ export const getUpdateMutationFromFormData = ({
2626
}
2727

2828
switch (fieldData.source?.type) {
29-
case "pool":
29+
case "pool": {
30+
return { ...acc, [field.name]: fieldData.value };
31+
}
3032
case "user": {
31-
const fieldValue = fieldData.value === "" ? null : fieldData.value;
33+
if (fieldData.value === null) {
34+
if (field.type === "relationship") {
35+
return { ...acc, [field.name]: null };
36+
}
37+
return { ...acc, [field.name]: { value: null } };
38+
}
39+
40+
if (typeof fieldData.value === "object") {
41+
const fieldValue = Array.isArray(fieldData.value)
42+
? fieldData.value.map(({ id }) => ({ id }))
43+
: { id: fieldData.value.id };
44+
return {
45+
...acc,
46+
[field.name]: fieldValue,
47+
};
48+
}
49+
3250
return {
3351
...acc,
34-
[field.name]: field.type === "relationship" ? fieldValue : { value: fieldValue },
52+
[field.name]: { value: fieldData.value === "" ? null : fieldData.value },
3553
};
3654
}
3755
case "profile":

0 commit comments

Comments
 (0)