diff --git a/packages/react/spec/auto/form/PolarisAutoRelatedForm.stories.jsx b/packages/react/spec/auto/form/PolarisAutoRelatedForm.stories.jsx
new file mode 100644
index 000000000..07a9de9cf
--- /dev/null
+++ b/packages/react/spec/auto/form/PolarisAutoRelatedForm.stories.jsx
@@ -0,0 +1,53 @@
+import { AppProvider, Card, Page } from "@shopify/polaris";
+import translations from "@shopify/polaris/locales/en.json";
+import React from "react";
+import { FormProvider, useForm } from "react-hook-form";
+import { Provider } from "../../../src/GadgetProvider.tsx";
+import { PolarisAutoForm } from "../../../src/auto/polaris/PolarisAutoForm.tsx";
+import { PolarisAutoInput } from "../../../src/auto/polaris/inputs/PolarisAutoInput.tsx";
+import { PolarisAutoHasManyInput } from "../../../src/auto/polaris/inputs/relationships/PolarisAutoHasManyInput.tsx";
+import { PolarisAutoRelatedForm } from "../../../src/auto/polaris/inputs/relationships/PolarisAutoRelatedForm.tsx";
+import { PolarisAutoSubmit } from "../../../src/auto/polaris/submit/PolarisAutoSubmit.tsx";
+import { testApi as api } from "../../apis.ts";
+
+const ExampleAutoRelatedForm = (props) => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default {
+ title: "Polaris/AutoForm/AutoRelatedForm",
+ component: ExampleAutoRelatedForm,
+ decorators: [
+ (Story) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+ },
+ ],
+};
+
+export const Primary = {
+ args: {
+ action: api.section.update,
+ findBy: "1",
+ },
+};
diff --git a/packages/react/src/auto/hooks/useBelongsToInputController.tsx b/packages/react/src/auto/hooks/useBelongsToInputController.tsx
index e60f7cd4f..4f38989ad 100644
--- a/packages/react/src/auto/hooks/useBelongsToInputController.tsx
+++ b/packages/react/src/auto/hooks/useBelongsToInputController.tsx
@@ -3,7 +3,7 @@ import { useController } from "react-hook-form";
import { useAutoFormMetadata } from "../AutoFormContext.js";
import type { AutoRelationshipInputProps } from "../interfaces/AutoRelationshipInputProps.js";
import { useFieldMetadata } from "./useFieldMetadata.js";
-import { useRelatedModelOptions } from "./useRelatedModelOptions.js";
+import { useRelatedModelOptions } from "./useRelatedModel.js";
export const useBelongsToInputController = (props: AutoRelationshipInputProps) => {
const { field, control } = props;
diff --git a/packages/react/src/auto/hooks/useHasManyInputController.tsx b/packages/react/src/auto/hooks/useHasManyInputController.tsx
index 2155b5e7c..0e9fcadbb 100644
--- a/packages/react/src/auto/hooks/useHasManyInputController.tsx
+++ b/packages/react/src/auto/hooks/useHasManyInputController.tsx
@@ -4,7 +4,7 @@ import type { GadgetHasManyConfig } from "../../internal/gql/graphql.js";
import { uniq } from "../../utils.js";
import type { AutoRelationshipInputProps } from "../interfaces/AutoRelationshipInputProps.js";
import { useFieldMetadata } from "./useFieldMetadata.js";
-import { useRelatedModelOptions } from "./useRelatedModelOptions.js";
+import { useRelatedModelOptions } from "./useRelatedModel.js";
export const useHasManyInputController = (props: AutoRelationshipInputProps) => {
const { field } = props;
diff --git a/packages/react/src/auto/hooks/useHasOneInputController.tsx b/packages/react/src/auto/hooks/useHasOneInputController.tsx
index 77a39a846..e24e82bef 100644
--- a/packages/react/src/auto/hooks/useHasOneInputController.tsx
+++ b/packages/react/src/auto/hooks/useHasOneInputController.tsx
@@ -4,7 +4,7 @@ import type { GadgetHasOneConfig } from "../../internal/gql/graphql.js";
import { uniq } from "../../utils.js";
import type { AutoRelationshipInputProps } from "../interfaces/AutoRelationshipInputProps.js";
import { useFieldMetadata } from "./useFieldMetadata.js";
-import { useRelatedModelOptions } from "./useRelatedModelOptions.js";
+import { useRelatedModelOptions } from "./useRelatedModel.js";
export const useHasOneInputController = (props: AutoRelationshipInputProps) => {
const { field } = props;
diff --git a/packages/react/src/auto/hooks/useRelatedModelOptions.tsx b/packages/react/src/auto/hooks/useRelatedModel.tsx
similarity index 91%
rename from packages/react/src/auto/hooks/useRelatedModelOptions.tsx
rename to packages/react/src/auto/hooks/useRelatedModel.tsx
index 9f47fe3ff..084de3756 100644
--- a/packages/react/src/auto/hooks/useRelatedModelOptions.tsx
+++ b/packages/react/src/auto/hooks/useRelatedModel.tsx
@@ -13,10 +13,7 @@ import { useModelManager } from "./useModelManager.js";
export const optionRecordsToLoadCount = 25;
export const selectedRecordsToLoadCount = 25;
-export const useRelatedModelOptions = (props: {
- field: string; // Field API identifier
- optionLabel?: OptionLabel; // The label to display for each related model record
-}) => {
+export const useRelatedModelRecords = (props: { field: string }) => {
const { field } = props;
const { metadata } = useFieldMetadata(field);
const { findBy, model } = useAutoFormMetadata();
@@ -30,11 +27,6 @@ export const useRelatedModelOptions = (props: {
const relatedModelInverseFieldApiId =
"inverseField" in relationshipFieldConfig ? relationshipFieldConfig.inverseField?.apiIdentifier : undefined;
- const optionLabel = assert(
- props.optionLabel ?? relationshipFieldConfig.relatedModel?.defaultDisplayField.apiIdentifier,
- "Option label is required for relationships"
- );
-
const { selected } = isBelongsToField
? // eslint-disable-next-line
useLinkedChildModelRelatedModelRecords({
@@ -54,8 +46,30 @@ export const useRelatedModelOptions = (props: {
const relatedModelRecords = useAllRelatedModelRecords({
relatedModel: { apiIdentifier: relatedModelApiIdentifier!, namespace: relatedModelNamespace },
- optionLabel,
+ filter: isBelongsToField ? undefined : { [relatedModelInverseFieldApiId + "Id"]: { isSet: false } },
});
+
+ return {
+ selected,
+ relatedModelRecords,
+ };
+};
+
+export const useRelatedModelOptions = (props: {
+ field: string; // Field API identifier
+ optionLabel?: OptionLabel; // The label to display for each related model record
+}) => {
+ const { field } = props;
+ const { metadata } = useFieldMetadata(field);
+
+ const relationshipFieldConfig = metadata.configuration as RelationshipFieldConfig;
+
+ const optionLabel = assert(
+ props.optionLabel ?? relationshipFieldConfig.relatedModel?.defaultDisplayField.apiIdentifier,
+ "Option label is required for relationships"
+ );
+ const { selected, relatedModelRecords } = useRelatedModelRecords(props);
+
const { relatedModel, pagination, search } = relatedModelRecords;
const getOptions = () => {
@@ -120,7 +134,7 @@ export const getRecordsAsOptions = (records: Record[], optionLabel:
*
* The lookup is done using the `findBy` to lookup on the current model to retrieve the related model record data
*/
-export const useLinkedChildModelRelatedModelRecords = (props: {
+const useLinkedChildModelRelatedModelRecords = (props: {
belongsToFieldApiId: string;
currentRecordId?: string;
currentModel: { apiIdentifier: string; namespace?: string[] | string | null };
@@ -154,7 +168,7 @@ export const useLinkedChildModelRelatedModelRecords = (props: {
/**
* For getting the related child model records in a HasOne/HasMany relationship
*/
-export const useLinkedParentModelRelatedModelRecords = (props: {
+const useLinkedParentModelRelatedModelRecords = (props: {
relatedModel: {
apiIdentifier: string;
namespace?: string[] | string | null;
@@ -177,7 +191,7 @@ export const useLinkedParentModelRelatedModelRecords = (props: {
pause: !currentRecordId, // HasOne/HasMany need the current record to query the inverse field in the related model
first: selectedRecordsToLoadCount, // Many records can point to the current record in hasOne/hasMany
- filter: { [inverseFieldApiIdentifier]: { equals: currentRecordId } }, // Filter by the inverse field belongsTo field value
+ filter: { [inverseFieldApiIdentifier + "Id"]: { equals: currentRecordId } }, // Filter by the inverse field belongsTo field value
});
return {
@@ -189,8 +203,9 @@ export const useLinkedParentModelRelatedModelRecords = (props: {
};
};
-export const useAllRelatedModelRecords = (props: {
+const useAllRelatedModelRecords = (props: {
optionLabel?: OptionLabel;
+ filter?: Record;
relatedModel: { apiIdentifier: string; namespace?: string[] | string | null };
}) => {
const { optionLabel, relatedModel } = props;
@@ -204,6 +219,7 @@ export const useAllRelatedModelRecords = (props: {
const [{ data: newlyFetchedRecords, fetching, error }, _refetch] = useFindMany(relatedModelManager as any, {
first: optionRecordsToLoadCount,
+ ...(props.filter && { filter: props.filter }),
...(paginationPage && { after: paginationPage }),
...(searchValue && { search: searchValue }),
...(optionLabelIsFieldName && { select: { id: true, [optionLabel]: true } }),
diff --git a/packages/react/src/auto/polaris/index.ts b/packages/react/src/auto/polaris/index.ts
index 0a29fce3e..b80a703e9 100644
--- a/packages/react/src/auto/polaris/index.ts
+++ b/packages/react/src/auto/polaris/index.ts
@@ -20,5 +20,6 @@ export {
} from "./inputs/PolarisAutoTextInput.js";
export { PolarisAutoBelongsToInput as AutoBelongsToInput } from "./inputs/relationships/PolarisAutoBelongsToInput.js";
export { PolarisAutoHasManyInput as AutoHasManyInput } from "./inputs/relationships/PolarisAutoHasManyInput.js";
+export { PolarisAutoRelatedForm as AutoRelatedForm } from "./inputs/relationships/PolarisAutoRelatedForm.js";
export { PolarisAutoSubmit as AutoSubmit } from "./submit/PolarisAutoSubmit.js";
export { PolarisSubmitResultBanner as SubmitResultBanner } from "./submit/PolarisSubmitResultBanner.js";
diff --git a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoBelongsToInput.tsx b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoBelongsToInput.tsx
index b3b872804..ce45857d1 100644
--- a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoBelongsToInput.tsx
+++ b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoBelongsToInput.tsx
@@ -1,7 +1,7 @@
import { Combobox, Tag } from "@shopify/polaris";
import React from "react";
import { useBelongsToInputController } from "../../../hooks/useBelongsToInputController.js";
-import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModelOptions.js";
+import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModel.js";
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
import { RelatedModelOptions } from "./RelatedModelOptions.js";
diff --git a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasManyInput.tsx b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasManyInput.tsx
index 02cc3ec43..582dfca57 100644
--- a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasManyInput.tsx
+++ b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasManyInput.tsx
@@ -2,7 +2,7 @@ import type { GadgetRecordList } from "@gadgetinc/api-client-core";
import { Banner, Combobox } from "@shopify/polaris";
import React from "react";
import { useHasManyInputController } from "../../../hooks/useHasManyInputController.js";
-import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModelOptions.js";
+import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModel.js";
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
import { RelatedModelOptions } from "./RelatedModelOptions.js";
import { getSelectedRelatedRecordTags } from "./SelectedRelatedRecordTags.js";
diff --git a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasOneInput.tsx b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasOneInput.tsx
index c08fed9b8..31b185be1 100644
--- a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasOneInput.tsx
+++ b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoHasOneInput.tsx
@@ -1,7 +1,7 @@
import { Banner, Combobox } from "@shopify/polaris";
import React from "react";
import { useHasOneInputController } from "../../../hooks/useHasOneInputController.js";
-import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModelOptions.js";
+import { optionRecordsToLoadCount } from "../../../hooks/useRelatedModel.js";
import type { AutoRelationshipInputProps } from "../../../interfaces/AutoRelationshipInputProps.js";
import { RelatedModelOptions } from "./RelatedModelOptions.js";
import { getSelectedRelatedRecordTags } from "./SelectedRelatedRecordTags.js";
diff --git a/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoRelatedForm.tsx b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoRelatedForm.tsx
new file mode 100644
index 000000000..b9bdb9bf3
--- /dev/null
+++ b/packages/react/src/auto/polaris/inputs/relationships/PolarisAutoRelatedForm.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { useFormContext } from "react-hook-form";
+import { useFieldMetadata } from "../../../hooks/useFieldMetadata.js";
+import { useRelatedModelRecords } from "../../../hooks/useRelatedModel.js";
+
+export const PolarisAutoRelatedForm = (props: { field: string; children: React.ReactNode }) => {
+ const { field } = props;
+ const { getValues } = useFormContext();
+ const { metadata, path } = useFieldMetadata(field);
+ const { selected, relatedModelRecords } = useRelatedModelRecords(props);
+
+ const values = getValues(path);
+
+ console.log({ values, path, field, selected, relatedModelRecords, metadata }, "foo foo fas");
+
+ return hi
;
+};
diff --git a/packages/react/src/use-action-form/utils.ts b/packages/react/src/use-action-form/utils.ts
index ffe158ba7..c96c9d589 100644
--- a/packages/react/src/use-action-form/utils.ts
+++ b/packages/react/src/use-action-form/utils.ts
@@ -390,6 +390,8 @@ const getParentRelationshipFieldGraphqlApiInput = (props: { input: any; result:
const { input, result } = props;
const { __typename, ...rest } = result;
+ console.log({ input, result });
+
if ("__id" in rest) {
if ("__unlinkedInverseField" in rest && rest.__unlinkedInverseField) {
const inverseFieldApiId = rest.__unlinkedInverseField;