Skip to content

Commit

Permalink
Added combobox component for Relationship many (#4422) (#5095)
Browse files Browse the repository at this point in the history
Co-authored-by: Bilal ABBAD <bilal@opsmill.com>
  • Loading branch information
pa-lem and bilalabbad authored Nov 29, 2024
1 parent d58aeff commit ffc67fb
Show file tree
Hide file tree
Showing 34 changed files with 554 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const getFiltersFromFormData = (formData: Record<string, FormFieldValue>)
...acc,
{
name: `${fieldName}__ids`,
value: fieldValue.map(({ id }) => id),
value: fieldValue,
},
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Filter } from "@/hooks/useFilters";
import { IModelSchema } from "@/state/atoms/schema.atom";
import {
AttributeType,
Node,
RelationshipManyType,
RelationshipOneType,
RelationshipType,
Expand Down Expand Up @@ -31,11 +32,11 @@ export const getObjectFromFilters = (
...acc,
[fieldName]: {
edges: filter.value.map(
(v: string) =>
(v: Node) =>
({
node: {
id: v,
display_label: "",
id: v.id,
display_label: v.display_label,
__typename: relationshipSchema.peer,
},
}) satisfies RelationshipOneType
Expand Down
6 changes: 6 additions & 0 deletions frontend/app/src/components/form/dynamic-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import JsonField from "@/components/form/fields/json.field";
import ListField from "@/components/form/fields/list.field";
import NumberField from "@/components/form/fields/number.field";
import PasswordInputField from "@/components/form/fields/password-input.field";
import RelationshipManyField from "@/components/form/fields/relationship-many.field";
import RelationshipField from "@/components/form/fields/relationship.field";
import TextareaField from "@/components/form/fields/textarea.field";
import { DynamicFieldProps, FormFieldValue } from "@/components/form/type";
Expand Down Expand Up @@ -109,6 +110,11 @@ export const DynamicInput = (props: DynamicFieldProps) => {
return <EnumField {...otherProps} />;
}
case "relationship": {
if (props.relationship.cardinality === "many") {
const { type, ...otherProps } = props;
return <RelationshipManyField {...otherProps} />;
}

return <RelationshipField {...props} />;
}
default: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { LabelFormField } from "@/components/form/fields/common";
import { DynamicRelationshipFieldProps, FormRelationshipValue } from "@/components/form/type";
import { FormField, FormInput, FormMessage } from "@/components/ui/form";

import { DEFAULT_FORM_FIELD_VALUE } from "@/components/form/constants";
import { updateRelationshipFieldValue } from "@/components/form/utils/updateFormFieldValue";
import { RelationshipManyInput } from "@/components/inputs/relationship-many";
import { Node } from "@/utils/getObjectItemDisplayValue";

export interface RelationshipManyInputProps extends Omit<DynamicRelationshipFieldProps, "type"> {}

export default function RelationshipManyField({
defaultValue = DEFAULT_FORM_FIELD_VALUE,
description,
label,
name,
rules,
unique,
...props
}: RelationshipManyInputProps) {
return (
<FormField
key={name}
name={name}
rules={rules}
defaultValue={defaultValue}
render={({ field }) => {
const fieldData: FormRelationshipValue = field.value;

return (
<div className="flex flex-col gap-2">
<LabelFormField
label={label}
unique={unique}
required={!!rules?.required}
description={description}
fieldData={fieldData}
/>

<FormInput>
<RelationshipManyInput
{...field}
{...props}
value={fieldData.value as Node[] | null}
onChange={(newValue) => {
field.onChange(updateRelationshipFieldValue(newValue, defaultValue));
}}
/>
</FormInput>

<FormMessage />
</div>
);
}}
/>
);
}
22 changes: 17 additions & 5 deletions frontend/app/src/components/form/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FormField } from "@/components/ui/form";
import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
import { AttributeSchema, RelationshipSchema } from "@/screens/schema/types";
import { IModelSchema } from "@/state/atoms/schema.atom";
import { Node } from "@/utils/getObjectItemDisplayValue";
import { ComponentProps } from "react";

type SourceType = "schema" | "user";
Expand Down Expand Up @@ -55,18 +56,29 @@ export type FormAttributeValue =
| AttributeValueFromPool
| EmptyFieldValue;

export type RelationshipValueFromPool = {
source: PoolSource;
value: { id: string } | { from_pool: { id: string } };
export type RelationshipOneValueFromUser = {
source: {
type: SourceType;
};
value: Node | null;
};

export type RelationshipValueFromUser = {
export type RelationshipManyValueFromUser = {
source: {
type: SourceType;
};
value: { id: string } | Array<{ id: string }> | null;
value: Array<Node> | null;
};

export type RelationshipValueFromPool = {
source: PoolSource;
value: Node | { from_pool: { id: string } };
};

export type RelationshipValueFromUser =
| RelationshipOneValueFromUser
| RelationshipManyValueFromUser;

export type FormRelationshipValue =
| RelationshipValueFromUser
| RelationshipValueFromPool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,17 @@ export const getRelationshipDefaultValue = ({
source: {
type: "user",
},
value: relationshipData.edges.map(({ node }) => ({
id: node?.id!,
})),
value: relationshipData.edges
.map(({ node }) =>
node
? {
id: node.id,
display_label: node.display_label,
__typename: node.__typename,
}
: null
)
.filter((n) => !!n),
};
}

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

if (sourceSchema && sourceSchema.inherit_from?.includes(RESOURCE_GENERIC_KIND)) {
if (!relationshipData.node) {
console.error("Source is a pool but node is null on relationship", relationshipData);
return { source: null, value: null };
}

return {
source: {
type: "pool",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,32 @@ export const getCreateMutationFromFormData = (
return acc;
}

if (isFormFieldValueFromPool(fieldData)) {
return { ...acc, [field.name]: fieldData.value };
}

if (fieldData.source?.type === "user") {
if (fieldData.value === null) {
return { ...acc, [field.name]: { value: null } };
}

if (typeof fieldData.value === "object") {
const fieldValue = Array.isArray(fieldData.value)
? fieldData.value.map(({ id }) => ({ id }))
: { id: fieldData.value.id };
return {
...acc,
[field.name]: fieldValue,
};
}

const fieldValue = fieldData.value === "" ? null : fieldData.value;
return {
...acc,
[field.name]: field.type === "relationship" ? fieldValue : { value: fieldValue },
[field.name]: { value: fieldValue },
};
}

if (isFormFieldValueFromPool(fieldData)) {
return { ...acc, [field.name]: fieldData.value };
}

return acc;
}, {});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,30 @@ export const getUpdateMutationFromFormData = ({
}

switch (fieldData.source?.type) {
case "pool":
case "pool": {
return { ...acc, [field.name]: fieldData.value };
}
case "user": {
const fieldValue = fieldData.value === "" ? null : fieldData.value;
if (fieldData.value === null) {
if (field.type === "relationship") {
return { ...acc, [field.name]: null };
}
return { ...acc, [field.name]: { value: null } };
}

if (typeof fieldData.value === "object") {
const fieldValue = Array.isArray(fieldData.value)
? fieldData.value.map(({ id }) => ({ id }))
: { id: fieldData.value.id };
return {
...acc,
[field.name]: fieldValue,
};
}

return {
...acc,
[field.name]: field.type === "relationship" ? fieldValue : { value: fieldValue },
[field.name]: { value: fieldData.value === "" ? null : fieldData.value },
};
}
case "profile":
Expand Down
Loading

0 comments on commit ffc67fb

Please sign in to comment.