Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] Edit form contains only relationship field of cardinality many if kind is Attribute or Parent #4229

Merged
merged 3 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/app/src/components/form/node-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type NodeFormProps = {
onSuccess?: (newObject: any) => void;
currentObject?: Record<string, AttributeType | RelationshipType>;
isFilterForm?: boolean;
isUpdate?: boolean;
onSubmit?: (data: NodeFormSubmitParams) => void;
};

Expand All @@ -49,6 +50,7 @@ export const NodeForm = ({
onSuccess,
isFilterForm,
onSubmit,
isUpdate,
...props
}: NodeFormProps) => {
const branch = useAtomValue(currentBranchAtom);
Expand Down Expand Up @@ -80,6 +82,7 @@ export const NodeForm = ({
isFilterForm,
filters,
pools: numberPools,
isUpdate,
});

async function onSubmitCreate(data: Record<string, FormFieldValue>) {
Expand Down
1 change: 1 addition & 0 deletions frontend/app/src/components/form/object-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface ObjectFormProps extends Omit<DynamicFormProps, "fields" | "onSu
currentObject?: Record<string, AttributeType | RelationshipType>;
currentProfiles?: ProfileData[];
isFilterForm?: boolean;
isUpdate?: boolean;
onSubmit?: (data: NodeFormSubmitParams) => void;
onUpdateComplete?: () => void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ import {
FormFieldValue,
NumberPoolData,
} from "@/components/form/type";
import {
getObjectRelationshipsForForm,
getOptionsFromAttribute,
getRelationshipOptions,
} from "@/utils/getSchemaObjectColumns";
import { getOptionsFromAttribute, getRelationshipOptions } from "@/utils/getSchemaObjectColumns";
import { isGeneric, sortByOrderWeight } from "@/utils/common";
import { getFieldDefaultValue } from "@/components/form/utils/getFieldDefaultValue";
import { SchemaAttributeType } from "@/screens/edit-form-hook/dynamic-control-types";
Expand All @@ -33,6 +29,7 @@ import { getRelationshipDefaultValue } from "@/components/form/utils/getRelation
import { Filter } from "@/hooks/useFilters";
import { getRelationshipParent } from "@/components/form/utils/getRelationshipParent";
import { isRequired } from "@/components/form/utils/validation";
import { getRelationshipsForForm } from "@/components/form/utils/getRelationshipsForForm";

type GetFormFieldsFromSchema = {
schema: iNodeSchema | iGenericSchema;
Expand All @@ -42,6 +39,7 @@ type GetFormFieldsFromSchema = {
isFilterForm?: boolean;
filters?: Array<Filter>;
pools?: Array<NumberPoolData>;
isUpdate?: boolean;
};

export const getFormFieldsFromSchema = ({
Expand All @@ -52,10 +50,11 @@ export const getFormFieldsFromSchema = ({
isFilterForm,
filters,
pools = [],
isUpdate,
}: GetFormFieldsFromSchema): Array<DynamicFieldProps> => {
const unorderedFields = [
...(schema.attributes ?? []),
...getObjectRelationshipsForForm(schema),
...getRelationshipsForForm(schema.relationships ?? [], isUpdate),
].filter((attribute) => !attribute.read_only);
const orderedFields: typeof unorderedFields = sortByOrderWeight(unorderedFields);

Expand Down
19 changes: 19 additions & 0 deletions frontend/app/src/components/form/utils/getRelationshipsForForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { components } from "@/infraops";
import { peersKindForForm } from "@/config/constants";

export const getRelationshipsForForm = (
relationships: components["schemas"]["RelationshipSchema-Output"][],
isUpdate?: boolean
) => {
// Filter relationships based on cardinality and kind for form inclusion
// For create forms, include relationships with cardinality 'one', eligible kinds, or mandatory cardinality 'many'
// For update forms, only include relationships with cardinality 'one' or those with eligible kinds (Attribute or Parent). Other should be display as tabs on details view
return relationships.filter((relationship) => {
if (relationship.cardinality === "one") return true;

const isPeerKindEligibleForForm = peersKindForForm.includes(relationship?.kind ?? "");
if (isUpdate) return isPeerKindEligibleForForm;

return isPeerKindEligibleForForm || !relationship.optional;
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export default function ObjectItemEditComponent(props: Props) {
currentObject={objectDetailsData}
currentProfiles={objectProfiles}
data-cy="object-item-edit"
isUpdate
/>
);
}
20 changes: 0 additions & 20 deletions frontend/app/src/utils/getSchemaObjectColumns.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
attributesKindForDetailsViewExclude,
attributesKindForListView,
peersKindForForm,
relationshipsForDetailsView,
relationshipsForListView,
relationshipsForTabs,
Expand Down Expand Up @@ -143,25 +142,6 @@ export const getObjectTabs = (tabs: any[], data: any) => {
}));
};

// Used by the form to display the fields
export const getObjectRelationshipsForForm = (
schema?: iNodeSchema | iGenericSchema,
isUpdate?: boolean
) => {
const relationships = (schema?.relationships || [])
// Create form includes cardinality many but only if required, edit form doesn't include it at all
.filter(
(relationship) =>
relationship.cardinality === "one" ||
(isUpdate
? peersKindForForm.includes(relationship?.kind ?? "")
: peersKindForForm.includes(relationship?.kind ?? "") || !relationship.optional)
)
.filter(Boolean);

return relationships;
};

// Include current value in the options to make it available in the select component
export const getRelationshipOptions = (row: any, field: any, schemas: any[], generics: any[]) => {
const value = row && (row[field.name]?.node ?? row[field.name]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { describe, expect, it } from "vitest";
import { getRelationshipsForForm } from "@/components/form/utils/getRelationshipsForForm";
import { buildRelationshipSchema } from "./getFormFieldsFromSchema.test";

describe("getRelationshipsForForm", () => {
it("returns an empty array if the provided relationships array is empty", () => {
// GIVEN
const relationships: never[] = [];

// WHEN
const result = getRelationshipsForForm(relationships);

// THEN
expect(result).toEqual([]);
});

it("returns a relationship if cardinality is one", () => {
// GIVEN
const relationships = [buildRelationshipSchema({ cardinality: "one" })];

// WHEN
const result = getRelationshipsForForm(relationships);

// THEN
expect(result).toEqual([relationships[0]]);
});

it("returns a relationship of cardinality many if kind is Attribute or Parent", () => {
// GIVEN
const relationships = [
buildRelationshipSchema({ cardinality: "many", kind: "Attribute" }),
buildRelationshipSchema({ cardinality: "many", kind: "Parent" }),
];

// WHEN
const result = getRelationshipsForForm(relationships);

// THEN
expect(result).toEqual(relationships);
});

it("should not return a relationship of cardinality many if kind is Generic/Component/Hierarchy", () => {
// GIVEN
const relationships = [
buildRelationshipSchema({ cardinality: "many", kind: "Generic" }),
buildRelationshipSchema({ cardinality: "many", kind: "Component" }),
buildRelationshipSchema({ cardinality: "many", kind: "Hierarchy" }),
buildRelationshipSchema({ cardinality: "many", kind: "Group" }),
buildRelationshipSchema({ cardinality: "many", kind: "Profile" }),
];

// WHEN
const result = getRelationshipsForForm(relationships);

// THEN
expect(result).toEqual([]);
});

it("returns a relationship of cardinality many if it's mandatory field", () => {
// GIVEN
const relationships = [
buildRelationshipSchema({ cardinality: "many", kind: "Attribute", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Parent", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Generic", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Component", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Hierarchy", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Group", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Profile", optional: false }),
];

// WHEN
const result = getRelationshipsForForm(relationships);

// THEN
expect(result).toEqual(relationships);
});

it("When update, returns a mandatory relationship of cardinality is many if kind is Attribute or Parent", () => {
// GIVEN
const relationships = [
buildRelationshipSchema({ cardinality: "many", kind: "Attribute", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Parent", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Generic", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Component", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Hierarchy", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Group", optional: false }),
buildRelationshipSchema({ cardinality: "many", kind: "Profile", optional: false }),
];
const isUpdate = true;

// WHEN
const result = getRelationshipsForForm(relationships, isUpdate);

// THEN
expect(result).toEqual([relationships[0], relationships[1]]);
});
});
Loading