diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
index 0987df37..35325fe0 100644
--- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
+++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
@@ -1,9 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`amplify form renderer tests GraphQL form tests should generate a create form 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should 1:1 relationships without types file path - Create 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
+ Autocomplete,
Badge,
Button,
Divider,
@@ -12,14 +13,14 @@ import {
Icon,
ScrollView,
Text,
- TextAreaField,
TextField,
useTheme,
} from \\"@aws-amplify/ui-react\\";
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { createPost } from \\"../graphql/mutations\\";
+import { listDogs } from \\"../graphql/queries\\";
+import { createOwner, updateDog, updateOwner } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -178,63 +179,52 @@ function ArrayField({
);
}
-export default function MyPostForm(props) {
+export default function CreateOwnerForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
- onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
- caption: \\"\\",
- username: \\"\\",
- post_url: \\"\\",
- metadata: \\"\\",
- profile_url: \\"\\",
- nonModelField: \\"\\",
- nonModelFieldArray: [],
+ name: \\"\\",
+ Dog: undefined,
};
- const [caption, setCaption] = React.useState(initialValues.caption);
- const [username, setUsername] = React.useState(initialValues.username);
- const [post_url, setPost_url] = React.useState(initialValues.post_url);
- const [metadata, setMetadata] = React.useState(initialValues.metadata);
- const [profile_url, setProfile_url] = React.useState(
- initialValues.profile_url
- );
- const [nonModelField, setNonModelField] = React.useState(
- initialValues.nonModelField
- );
- const [nonModelFieldArray, setNonModelFieldArray] = React.useState(
- initialValues.nonModelFieldArray
- );
+ const [name, setName] = React.useState(initialValues.name);
+ const [Dog, setDog] = React.useState(initialValues.Dog);
+ const [DogLoading, setDogLoading] = React.useState(false);
+ const [DogRecords, setDogRecords] = React.useState([]);
+ const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
- setCaption(initialValues.caption);
- setUsername(initialValues.username);
- setPost_url(initialValues.post_url);
- setMetadata(initialValues.metadata);
- setProfile_url(initialValues.profile_url);
- setNonModelField(initialValues.nonModelField);
- setNonModelFieldArray(initialValues.nonModelFieldArray);
- setCurrentNonModelFieldArrayValue(\\"\\");
+ setName(initialValues.name);
+ setDog(initialValues.Dog);
+ setCurrentDogValue(undefined);
+ setCurrentDogDisplayValue(\\"\\");
setErrors({});
};
- const [currentNonModelFieldArrayValue, setCurrentNonModelFieldArrayValue] =
+ const [currentDogDisplayValue, setCurrentDogDisplayValue] =
React.useState(\\"\\");
- const nonModelFieldArrayRef = React.createRef();
+ const [currentDogValue, setCurrentDogValue] = React.useState(undefined);
+ const DogRef = React.createRef();
+ const getIDValue = {
+ Dog: (r) => JSON.stringify({ id: r?.id }),
+ };
+ const DogIdSet = new Set(
+ Array.isArray(Dog)
+ ? Dog.map((r) => getIDValue.Dog?.(r))
+ : getIDValue.Dog?.(Dog)
+ );
+ const getDisplayValue = {
+ Dog: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
+ };
const validations = {
- caption: [],
- username: [],
- post_url: [{ type: \\"URL\\" }],
- metadata: [{ type: \\"JSON\\" }],
- profile_url: [{ type: \\"URL\\" }],
- nonModelField: [{ type: \\"JSON\\" }],
- nonModelFieldArray: [{ type: \\"JSON\\" }],
+ name: [{ type: \\"Required\\" }],
+ Dog: [],
};
const runValidationTasks = async (
fieldName,
@@ -253,6 +243,35 @@ export default function MyPostForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
+ const fetchDogRecords = async (value) => {
+ setDogLoading(true);
+ const newOptions = [];
+ let newNext = \\"\\";
+ while (newOptions.length < autocompleteLength && newNext != null) {
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: {
+ or: [{ name: { contains: value } }, { id: { contains: value } }],
+ },
+ };
+ if (newNext) {
+ variables[\\"nextToken\\"] = newNext;
+ }
+ const result = (
+ await API.graphql({
+ query: listDogs,
+ variables,
+ })
+ ).data.listDogs.item;
+ var loaded = result.filter(
+ (item) => !DogIdSet.has(getIDValue.Dog?.(item))
+ );
+ newOptions.push(...loaded);
+ newNext = result.nextToken;
+ }
+ setDogRecords(newOptions.slice(0, autocompleteLength));
+ setDogLoading(false);
+ };
return (
{
event.preventDefault();
let modelFields = {
- caption,
- username,
- post_url,
- metadata,
- profile_url,
- nonModelField,
- nonModelFieldArray,
+ name,
+ Dog,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
if (Array.isArray(modelFields[fieldName])) {
promises.push(
...modelFields[fieldName].map((item) =>
- runValidationTasks(fieldName, item)
+ runValidationTasks(
+ fieldName,
+ item,
+ getDisplayValue[fieldName]
+ )
)
);
return promises;
}
promises.push(
- runValidationTasks(fieldName, modelFields[fieldName])
+ runValidationTasks(
+ fieldName,
+ modelFields[fieldName],
+ getDisplayValue[fieldName]
+ )
);
return promises;
}, [])
@@ -298,27 +320,45 @@ export default function MyPostForm(props) {
modelFields[key] = undefined;
}
});
- const modelFieldsToSave = {
- caption: modelFields.caption,
- username: modelFields.username,
- post_url: modelFields.post_url,
- metadata: modelFields.metadata,
- profile_url: modelFields.profile_url,
- nonModelFieldArray: modelFields.nonModelFieldArray.map((s) =>
- JSON.parse(s)
- ),
- nonModelField: modelFields.nonModelField
- ? JSON.parse(modelFields.nonModelField)
- : modelFields.nonModelField,
- };
- await API.graphql({
- query: createPost,
+ const owner = await API.graphql({
+ query: createOwner,
variables: {
input: {
- ...modelFieldsToSave,
+ ...modelFields,
},
},
});
+ const promises = [];
+ const dogToLink = modelFields.Dog;
+ if (dogToLink) {
+ promises.push(
+ API.graphql({
+ query: updateDog,
+ variables: {
+ input: {
+ ...Dog,
+ Owner: owner,
+ },
+ },
+ })
+ );
+ const ownerToUnlink = await dogToLink.Owner;
+ if (ownerToUnlink) {
+ promises.push(
+ API.graphql({
+ query: updateOwner,
+ variables: {
+ input: {
+ ...ownerToUnlink,
+ Dog: undefined,
+ ownerDogId: undefined,
+ },
+ },
+ })
+ );
+ }
+ }
+ await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
@@ -331,338 +371,180 @@ export default function MyPostForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"MyPostForm\\")}
+ {...getOverrideProps(overrides, \\"CreateOwnerForm\\")}
{...rest}
>
-
-
-
-
-
-
-
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- caption: value,
- username,
- post_url,
- metadata,
- profile_url,
- nonModelField,
- nonModelFieldArray,
+ name: value,
+ Dog,
};
const result = onChange(modelFields);
- value = result?.caption ?? value;
+ value = result?.name ?? value;
}
- if (errors.caption?.hasError) {
- runValidationTasks(\\"caption\\", value);
+ if (errors.name?.hasError) {
+ runValidationTasks(\\"name\\", value);
}
- setCaption(value);
+ setName(value);
}}
- onBlur={() => runValidationTasks(\\"caption\\", caption)}
- errorMessage={errors.caption?.errorMessage}
- hasError={errors.caption?.hasError}
- {...getOverrideProps(overrides, \\"caption\\")}
+ onBlur={() => runValidationTasks(\\"name\\", name)}
+ errorMessage={errors.name?.errorMessage}
+ hasError={errors.name?.hasError}
+ {...getOverrideProps(overrides, \\"name\\")}
>
- {
- let { value } = e.target;
+ {
+ let value = items[0];
if (onChange) {
const modelFields = {
- caption,
- username: value,
- post_url,
- metadata,
- profile_url,
- nonModelField,
- nonModelFieldArray,
- };
- const result = onChange(modelFields);
- value = result?.username ?? value;
- }
- if (errors.username?.hasError) {
- runValidationTasks(\\"username\\", value);
- }
- setUsername(value);
- }}
- onBlur={() => runValidationTasks(\\"username\\", username)}
- errorMessage={errors.username?.errorMessage}
- hasError={errors.username?.hasError}
- {...getOverrideProps(overrides, \\"username\\")}
- >
- {
- let { value } = e.target;
- if (onChange) {
- const modelFields = {
- caption,
- username,
- post_url: value,
- metadata,
- profile_url,
- nonModelField,
- nonModelFieldArray,
- };
- const result = onChange(modelFields);
- value = result?.post_url ?? value;
- }
- if (errors.post_url?.hasError) {
- runValidationTasks(\\"post_url\\", value);
- }
- setPost_url(value);
- }}
- onBlur={() => runValidationTasks(\\"post_url\\", post_url)}
- errorMessage={errors.post_url?.errorMessage}
- hasError={errors.post_url?.hasError}
- {...getOverrideProps(overrides, \\"post_url\\")}
- >
- {
- let { value } = e.target;
- if (onChange) {
- const modelFields = {
- caption,
- username,
- post_url,
- metadata: value,
- profile_url,
- nonModelField,
- nonModelFieldArray,
- };
- const result = onChange(modelFields);
- value = result?.metadata ?? value;
- }
- if (errors.metadata?.hasError) {
- runValidationTasks(\\"metadata\\", value);
- }
- setMetadata(value);
- }}
- onBlur={() => runValidationTasks(\\"metadata\\", metadata)}
- errorMessage={errors.metadata?.errorMessage}
- hasError={errors.metadata?.hasError}
- {...getOverrideProps(overrides, \\"metadata\\")}
- >
- {
- let { value } = e.target;
- if (onChange) {
- const modelFields = {
- caption,
- username,
- post_url,
- metadata,
- profile_url: value,
- nonModelField,
- nonModelFieldArray,
- };
- const result = onChange(modelFields);
- value = result?.profile_url ?? value;
- }
- if (errors.profile_url?.hasError) {
- runValidationTasks(\\"profile_url\\", value);
- }
- setProfile_url(value);
- }}
- onBlur={() => runValidationTasks(\\"profile_url\\", profile_url)}
- errorMessage={errors.profile_url?.errorMessage}
- hasError={errors.profile_url?.hasError}
- {...getOverrideProps(overrides, \\"profile_url\\")}
- >
- {
- let { value } = e.target;
- if (onChange) {
- const modelFields = {
- caption,
- username,
- post_url,
- metadata,
- profile_url,
- nonModelField: value,
- nonModelFieldArray,
+ name,
+ Dog: value,
};
const result = onChange(modelFields);
- value = result?.nonModelField ?? value;
- }
- if (errors.nonModelField?.hasError) {
- runValidationTasks(\\"nonModelField\\", value);
+ value = result?.Dog ?? value;
}
- setNonModelField(value);
+ setDog(value);
+ setCurrentDogValue(undefined);
+ setCurrentDogDisplayValue(\\"\\");
}}
- onBlur={() => runValidationTasks(\\"nonModelField\\", nonModelField)}
- errorMessage={errors.nonModelField?.errorMessage}
- hasError={errors.nonModelField?.hasError}
- {...getOverrideProps(overrides, \\"nonModelField\\")}
- >
- {
- let values = items;
- if (onChange) {
- const modelFields = {
- caption,
- username,
- post_url,
- metadata,
- profile_url,
- nonModelField,
- nonModelFieldArray: values,
- };
- const result = onChange(modelFields);
- values = result?.nonModelFieldArray ?? values;
- }
- setNonModelFieldArray(values);
- setCurrentNonModelFieldArrayValue(\\"\\");
+ currentFieldValue={currentDogValue}
+ label={\\"Dog\\"}
+ items={Dog ? [Dog] : []}
+ hasError={errors?.Dog?.hasError}
+ errorMessage={errors?.Dog?.errorMessage}
+ getBadgeText={getDisplayValue.Dog}
+ setFieldValue={(model) => {
+ setCurrentDogDisplayValue(model ? getDisplayValue.Dog(model) : \\"\\");
+ setCurrentDogValue(model);
}}
- currentFieldValue={currentNonModelFieldArrayValue}
- label={\\"Non model field array\\"}
- items={nonModelFieldArray}
- hasError={errors?.nonModelFieldArray?.hasError}
- errorMessage={errors?.nonModelFieldArray?.errorMessage}
- setFieldValue={setCurrentNonModelFieldArrayValue}
- inputFieldRef={nonModelFieldArrayRef}
+ inputFieldRef={DogRef}
defaultFieldValue={\\"\\"}
>
- !DogIdSet.has(getIDValue.Dog?.(r)))
+ .map((r) => ({
+ id: getIDValue.Dog?.(r),
+ label: getDisplayValue.Dog?.(r),
+ }))}
+ isLoading={DogLoading}
+ onSelect={({ id, label }) => {
+ setCurrentDogValue(
+ dogRecords.find((r) =>
+ Object.entries(JSON.parse(id)).every(
+ ([key, value]) => r[key] === value
+ )
+ )
+ );
+ setCurrentDogDisplayValue(label);
+ runValidationTasks(\\"Dog\\", label);
+ }}
+ onClear={() => {
+ setCurrentDogDisplayValue(\\"\\");
+ }}
onChange={(e) => {
let { value } = e.target;
- if (errors.nonModelFieldArray?.hasError) {
- runValidationTasks(\\"nonModelFieldArray\\", value);
+ fetchDogRecords(value);
+ if (errors.Dog?.hasError) {
+ runValidationTasks(\\"Dog\\", value);
}
- setCurrentNonModelFieldArrayValue(value);
+ setCurrentDogDisplayValue(value);
+ setCurrentDogValue(undefined);
}}
- onBlur={() =>
- runValidationTasks(
- \\"nonModelFieldArray\\",
- currentNonModelFieldArrayValue
- )
- }
- errorMessage={errors.nonModelFieldArray?.errorMessage}
- hasError={errors.nonModelFieldArray?.hasError}
- ref={nonModelFieldArrayRef}
+ onBlur={() => runValidationTasks(\\"Dog\\", currentDogDisplayValue)}
+ errorMessage={errors.Dog?.errorMessage}
+ hasError={errors.Dog?.hasError}
+ ref={DogRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"nonModelFieldArray\\")}
- >
+ {...getOverrideProps(overrides, \\"Dog\\")}
+ >
+
+
+
+
+
+
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should 1:1 relationships without types file path - Create 2`] = `
"import * as React from \\"react\\";
-import { GridProps, TextAreaFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type MyPostFormInputValues = {
- caption?: string;
- username?: string;
- post_url?: string;
- metadata?: string;
- profile_url?: string;
- nonModelField?: string;
- nonModelFieldArray?: string[];
+export declare type CreateOwnerFormInputValues = {
+ name?: string;
+ Dog?: any;
};
-export declare type MyPostFormValidationValues = {
- caption?: ValidationFunction;
- username?: ValidationFunction;
- post_url?: ValidationFunction;
- metadata?: ValidationFunction;
- profile_url?: ValidationFunction;
- nonModelField?: ValidationFunction;
- nonModelFieldArray?: ValidationFunction;
+export declare type CreateOwnerFormValidationValues = {
+ name?: ValidationFunction;
+ Dog?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type MyPostFormOverridesProps = {
- MyPostFormGrid?: PrimitiveOverrideProps;
- caption?: PrimitiveOverrideProps;
- username?: PrimitiveOverrideProps;
- post_url?: PrimitiveOverrideProps;
- metadata?: PrimitiveOverrideProps;
- profile_url?: PrimitiveOverrideProps;
- nonModelField?: PrimitiveOverrideProps;
- nonModelFieldArray?: PrimitiveOverrideProps;
+export declare type CreateOwnerFormOverridesProps = {
+ CreateOwnerFormGrid?: PrimitiveOverrideProps;
+ name?: PrimitiveOverrideProps;
+ Dog?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type MyPostFormProps = React.PropsWithChildren<{
- overrides?: MyPostFormOverridesProps | undefined | null;
+export declare type CreateOwnerFormProps = React.PropsWithChildren<{
+ overrides?: CreateOwnerFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
- onSubmit?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
- onSuccess?: (fields: MyPostFormInputValues) => void;
- onError?: (fields: MyPostFormInputValues, errorMessage: string) => void;
- onCancel?: () => void;
- onChange?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
- onValidate?: MyPostFormValidationValues;
+ onSubmit?: (fields: CreateOwnerFormInputValues) => CreateOwnerFormInputValues;
+ onSuccess?: (fields: CreateOwnerFormInputValues) => void;
+ onError?: (fields: CreateOwnerFormInputValues, errorMessage: string) => void;
+ onChange?: (fields: CreateOwnerFormInputValues) => CreateOwnerFormInputValues;
+ onValidate?: CreateOwnerFormValidationValues;
} & React.CSSProperties>;
-export default function MyPostForm(props: MyPostFormProps): React.ReactElement;
+export default function CreateOwnerForm(props: CreateOwnerFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with belongsTo relationship 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
- Autocomplete,
Badge,
Button,
Divider,
@@ -671,14 +553,14 @@ import {
Icon,
ScrollView,
Text,
+ TextAreaField,
TextField,
useTheme,
} from \\"@aws-amplify/ui-react\\";
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { listTeams } from \\"../graphql/queries\\";
-import { createMember } from \\"../graphql/mutations\\";
+import { createPost } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -837,7 +719,7 @@ function ArrayField({
);
}
-export default function MyMemberForm(props) {
+export default function MyPostForm(props) {
const {
clearOnSuccess = true,
onSuccess,
@@ -850,53 +732,50 @@ export default function MyMemberForm(props) {
...rest
} = props;
const initialValues = {
- name: \\"\\",
- teamID: undefined,
- Team: undefined,
+ caption: \\"\\",
+ username: \\"\\",
+ post_url: \\"\\",
+ metadata: \\"\\",
+ profile_url: \\"\\",
+ nonModelField: \\"\\",
+ nonModelFieldArray: [],
};
- const [name, setName] = React.useState(initialValues.name);
- const [teamID, setTeamID] = React.useState(initialValues.teamID);
- const [teamIDLoading, setTeamIDLoading] = React.useState(false);
- const [teamIDRecords, setTeamIDRecords] = React.useState([]);
- const [Team, setTeam] = React.useState(initialValues.Team);
- const [TeamLoading, setTeamLoading] = React.useState(false);
- const [TeamRecords, setTeamRecords] = React.useState([]);
- const autocompleteLength = 10;
+ const [caption, setCaption] = React.useState(initialValues.caption);
+ const [username, setUsername] = React.useState(initialValues.username);
+ const [post_url, setPost_url] = React.useState(initialValues.post_url);
+ const [metadata, setMetadata] = React.useState(initialValues.metadata);
+ const [profile_url, setProfile_url] = React.useState(
+ initialValues.profile_url
+ );
+ const [nonModelField, setNonModelField] = React.useState(
+ initialValues.nonModelField
+ );
+ const [nonModelFieldArray, setNonModelFieldArray] = React.useState(
+ initialValues.nonModelFieldArray
+ );
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
- setName(initialValues.name);
- setTeamID(initialValues.teamID);
- setCurrentTeamIDValue(undefined);
- setCurrentTeamIDDisplayValue(\\"\\");
- setTeam(initialValues.Team);
- setCurrentTeamValue(undefined);
- setCurrentTeamDisplayValue(\\"\\");
+ setCaption(initialValues.caption);
+ setUsername(initialValues.username);
+ setPost_url(initialValues.post_url);
+ setMetadata(initialValues.metadata);
+ setProfile_url(initialValues.profile_url);
+ setNonModelField(initialValues.nonModelField);
+ setNonModelFieldArray(initialValues.nonModelFieldArray);
+ setCurrentNonModelFieldArrayValue(\\"\\");
setErrors({});
};
- const [currentTeamIDDisplayValue, setCurrentTeamIDDisplayValue] =
- React.useState(\\"\\");
- const [currentTeamIDValue, setCurrentTeamIDValue] = React.useState(undefined);
- const teamIDRef = React.createRef();
- const [currentTeamDisplayValue, setCurrentTeamDisplayValue] =
+ const [currentNonModelFieldArrayValue, setCurrentNonModelFieldArrayValue] =
React.useState(\\"\\");
- const [currentTeamValue, setCurrentTeamValue] = React.useState(undefined);
- const TeamRef = React.createRef();
- const getIDValue = {
- Team: (r) => JSON.stringify({ id: r?.id }),
- };
- const TeamIdSet = new Set(
- Array.isArray(Team)
- ? Team.map((r) => getIDValue.Team?.(r))
- : getIDValue.Team?.(Team)
- );
- const getDisplayValue = {
- teamID: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
- Team: (r) => r?.name,
- };
+ const nonModelFieldArrayRef = React.createRef();
const validations = {
- name: [],
- teamID: [{ type: \\"Required\\" }],
- Team: [],
+ caption: [],
+ username: [],
+ post_url: [{ type: \\"URL\\" }],
+ metadata: [{ type: \\"JSON\\" }],
+ profile_url: [{ type: \\"URL\\" }],
+ nonModelField: [{ type: \\"JSON\\" }],
+ nonModelFieldArray: [{ type: \\"JSON\\" }],
};
const runValidationTasks = async (
fieldName,
@@ -915,62 +794,6 @@ export default function MyMemberForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
- const fetchTeamIDRecords = async (value) => {
- setTeamIDLoading(true);
- const newOptions = [];
- let newNext = \\"\\";
- while (newOptions.length < autocompleteLength && newNext != null) {
- const variables = {
- limit: autocompleteLength * 5,
- filter: {
- or: [{ name: { contains: value } }, { id: { contains: value } }],
- },
- };
- if (newNext) {
- variables[\\"nextToken\\"] = newNext;
- }
- const result = (
- await API.graphql({
- query: listTeams,
- variables,
- })
- ).data.listTeamIDS.item;
- var loaded = result.filter(
- (item) => !teamIDIdSet.has(getIDValue.teamID?.(item))
- );
- newOptions.push(...loaded);
- newNext = result.nextToken;
- }
- setTeamIDRecords(newOptions.slice(0, autocompleteLength));
- setTeamIDLoading(false);
- };
- const fetchTeamRecords = async (value) => {
- setTeamLoading(true);
- const newOptions = [];
- let newNext = \\"\\";
- while (newOptions.length < autocompleteLength && newNext != null) {
- const variables = {
- limit: autocompleteLength * 5,
- filter: { or: [{ name: { contains: value } }] },
- };
- if (newNext) {
- variables[\\"nextToken\\"] = newNext;
- }
- const result = (
- await API.graphql({
- query: listTeams,
- variables,
- })
- ).data.listTeams.item;
- var loaded = result.filter(
- (item) => !TeamIdSet.has(getIDValue.Team?.(item))
- );
- newOptions.push(...loaded);
- newNext = result.nextToken;
- }
- setTeamRecords(newOptions.slice(0, autocompleteLength));
- setTeamLoading(false);
- };
return (
{
event.preventDefault();
let modelFields = {
- name,
- teamID,
- Team,
+ caption,
+ username,
+ post_url,
+ metadata,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
if (Array.isArray(modelFields[fieldName])) {
promises.push(
...modelFields[fieldName].map((item) =>
- runValidationTasks(
- fieldName,
- item,
- getDisplayValue[fieldName]
- )
+ runValidationTasks(fieldName, item)
)
);
return promises;
}
promises.push(
- runValidationTasks(
- fieldName,
- modelFields[fieldName],
- getDisplayValue[fieldName]
- )
+ runValidationTasks(fieldName, modelFields[fieldName])
);
return promises;
}, [])
@@ -1020,11 +839,24 @@ export default function MyMemberForm(props) {
modelFields[key] = undefined;
}
});
+ const modelFieldsToSave = {
+ caption: modelFields.caption,
+ username: modelFields.username,
+ post_url: modelFields.post_url,
+ metadata: modelFields.metadata,
+ profile_url: modelFields.profile_url,
+ nonModelFieldArray: modelFields.nonModelFieldArray.map((s) =>
+ JSON.parse(s)
+ ),
+ nonModelField: modelFields.nonModelField
+ ? JSON.parse(modelFields.nonModelField)
+ : modelFields.nonModelField,
+ };
await API.graphql({
- query: createMember,
+ query: createPost,
variables: {
input: {
- ...modelFields,
+ ...modelFieldsToSave,
},
},
});
@@ -1040,7 +872,7 @@ export default function MyMemberForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"MyMemberForm\\")}
+ {...getOverrideProps(overrides, \\"MyPostForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- name: value,
- teamID,
- Team,
+ caption: value,
+ username,
+ post_url,
+ metadata,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray,
};
const result = onChange(modelFields);
- value = result?.name ?? value;
+ value = result?.caption ?? value;
}
- if (errors.name?.hasError) {
- runValidationTasks(\\"name\\", value);
+ if (errors.caption?.hasError) {
+ runValidationTasks(\\"caption\\", value);
}
- setName(value);
+ setCaption(value);
}}
- onBlur={() => runValidationTasks(\\"name\\", name)}
- errorMessage={errors.name?.errorMessage}
- hasError={errors.name?.hasError}
- {...getOverrideProps(overrides, \\"name\\")}
+ onBlur={() => runValidationTasks(\\"caption\\", caption)}
+ errorMessage={errors.caption?.errorMessage}
+ hasError={errors.caption?.hasError}
+ {...getOverrideProps(overrides, \\"caption\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ caption,
+ username: value,
+ post_url,
+ metadata,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.username ?? value;
+ }
+ if (errors.username?.hasError) {
+ runValidationTasks(\\"username\\", value);
+ }
+ setUsername(value);
+ }}
+ onBlur={() => runValidationTasks(\\"username\\", username)}
+ errorMessage={errors.username?.errorMessage}
+ hasError={errors.username?.hasError}
+ {...getOverrideProps(overrides, \\"username\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ caption,
+ username,
+ post_url: value,
+ metadata,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.post_url ?? value;
+ }
+ if (errors.post_url?.hasError) {
+ runValidationTasks(\\"post_url\\", value);
+ }
+ setPost_url(value);
+ }}
+ onBlur={() => runValidationTasks(\\"post_url\\", post_url)}
+ errorMessage={errors.post_url?.errorMessage}
+ hasError={errors.post_url?.hasError}
+ {...getOverrideProps(overrides, \\"post_url\\")}
>
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ caption,
+ username,
+ post_url,
+ metadata: value,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.metadata ?? value;
+ }
+ if (errors.metadata?.hasError) {
+ runValidationTasks(\\"metadata\\", value);
+ }
+ setMetadata(value);
+ }}
+ onBlur={() => runValidationTasks(\\"metadata\\", metadata)}
+ errorMessage={errors.metadata?.errorMessage}
+ hasError={errors.metadata?.hasError}
+ {...getOverrideProps(overrides, \\"metadata\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ caption,
+ username,
+ post_url,
+ metadata,
+ profile_url: value,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.profile_url ?? value;
+ }
+ if (errors.profile_url?.hasError) {
+ runValidationTasks(\\"profile_url\\", value);
+ }
+ setProfile_url(value);
+ }}
+ onBlur={() => runValidationTasks(\\"profile_url\\", profile_url)}
+ errorMessage={errors.profile_url?.errorMessage}
+ hasError={errors.profile_url?.hasError}
+ {...getOverrideProps(overrides, \\"profile_url\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ caption,
+ username,
+ post_url,
+ metadata,
+ profile_url,
+ nonModelField: value,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.nonModelField ?? value;
+ }
+ if (errors.nonModelField?.hasError) {
+ runValidationTasks(\\"nonModelField\\", value);
+ }
+ setNonModelField(value);
+ }}
+ onBlur={() => runValidationTasks(\\"nonModelField\\", nonModelField)}
+ errorMessage={errors.nonModelField?.errorMessage}
+ hasError={errors.nonModelField?.hasError}
+ {...getOverrideProps(overrides, \\"nonModelField\\")}
+ >
{
- let value = items[0];
+ let values = items;
if (onChange) {
const modelFields = {
- name,
- teamID: value,
- Team,
+ caption,
+ username,
+ post_url,
+ metadata,
+ profile_url,
+ nonModelField,
+ nonModelFieldArray: values,
};
const result = onChange(modelFields);
- value = result?.teamID ?? value;
+ values = result?.nonModelFieldArray ?? values;
}
- setTeamID(value);
- setCurrentTeamIDValue(undefined);
- }}
- currentFieldValue={currentTeamIDValue}
- label={\\"Team id\\"}
- items={teamID ? [teamID] : []}
- hasError={errors?.teamID?.hasError}
- errorMessage={errors?.teamID?.errorMessage}
- getBadgeText={(value) =>
- value
- ? getDisplayValue.teamID(teamRecords.find((r) => r.id === value))
- : \\"\\"
- }
- setFieldValue={(value) => {
- setCurrentTeamIDDisplayValue(
- value
- ? getDisplayValue.teamID(teamRecords.find((r) => r.id === value))
- : \\"\\"
- );
- setCurrentTeamIDValue(value);
+ setNonModelFieldArray(values);
+ setCurrentNonModelFieldArrayValue(\\"\\");
}}
- inputFieldRef={teamIDRef}
+ currentFieldValue={currentNonModelFieldArrayValue}
+ label={\\"Non model field array\\"}
+ items={nonModelFieldArray}
+ hasError={errors?.nonModelFieldArray?.hasError}
+ errorMessage={errors?.nonModelFieldArray?.errorMessage}
+ setFieldValue={setCurrentNonModelFieldArrayValue}
+ inputFieldRef={nonModelFieldArrayRef}
defaultFieldValue={\\"\\"}
>
-
- arr.findIndex((member) => member?.id === r?.id) === i
- )
- .map((r) => ({
- id: r?.id,
- label: getDisplayValue.teamID?.(r),
- }))}
- isLoading={teamIDLoading}
- onSelect={({ id, label }) => {
- setCurrentTeamIDValue(id);
- setCurrentTeamIDDisplayValue(label);
- runValidationTasks(\\"teamID\\", label);
- }}
- onClear={() => {
- setCurrentTeamIDDisplayValue(\\"\\");
- }}
+ value={currentNonModelFieldArrayValue}
onChange={(e) => {
let { value } = e.target;
- fetchTeamIDRecords(value);
- if (errors.teamID?.hasError) {
- runValidationTasks(\\"teamID\\", value);
+ if (errors.nonModelFieldArray?.hasError) {
+ runValidationTasks(\\"nonModelFieldArray\\", value);
}
- setCurrentTeamIDDisplayValue(value);
- setCurrentTeamIDValue(undefined);
+ setCurrentNonModelFieldArrayValue(value);
}}
- onBlur={() => runValidationTasks(\\"teamID\\", currentTeamIDValue)}
- errorMessage={errors.teamID?.errorMessage}
- hasError={errors.teamID?.hasError}
- ref={teamIDRef}
+ onBlur={() =>
+ runValidationTasks(
+ \\"nonModelFieldArray\\",
+ currentNonModelFieldArrayValue
+ )
+ }
+ errorMessage={errors.nonModelFieldArray?.errorMessage}
+ hasError={errors.nonModelFieldArray?.hasError}
+ ref={nonModelFieldArrayRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"teamID\\")}
- >
+ {...getOverrideProps(overrides, \\"nonModelFieldArray\\")}
+ >
- {
- let value = items[0];
- if (onChange) {
- const modelFields = {
- name,
+
+ );
+}
+"
+`;
+
+exports[`amplify form renderer tests GraphQL form tests should generate a create form 2`] = `
+"import * as React from \\"react\\";
+import { GridProps, TextAreaFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
+export declare type ValidationResponse = {
+ hasError: boolean;
+ errorMessage?: string;
+};
+export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
+export declare type MyPostFormInputValues = {
+ caption?: string;
+ username?: string;
+ post_url?: string;
+ metadata?: string;
+ profile_url?: string;
+ nonModelField?: string;
+ nonModelFieldArray?: string[];
+};
+export declare type MyPostFormValidationValues = {
+ caption?: ValidationFunction;
+ username?: ValidationFunction;
+ post_url?: ValidationFunction;
+ metadata?: ValidationFunction;
+ profile_url?: ValidationFunction;
+ nonModelField?: ValidationFunction;
+ nonModelFieldArray?: ValidationFunction;
+};
+export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
+export declare type MyPostFormOverridesProps = {
+ MyPostFormGrid?: PrimitiveOverrideProps;
+ caption?: PrimitiveOverrideProps;
+ username?: PrimitiveOverrideProps;
+ post_url?: PrimitiveOverrideProps;
+ metadata?: PrimitiveOverrideProps;
+ profile_url?: PrimitiveOverrideProps;
+ nonModelField?: PrimitiveOverrideProps;
+ nonModelFieldArray?: PrimitiveOverrideProps;
+} & EscapeHatchProps;
+export declare type MyPostFormProps = React.PropsWithChildren<{
+ overrides?: MyPostFormOverridesProps | undefined | null;
+} & {
+ clearOnSuccess?: boolean;
+ onSubmit?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
+ onSuccess?: (fields: MyPostFormInputValues) => void;
+ onError?: (fields: MyPostFormInputValues, errorMessage: string) => void;
+ onCancel?: () => void;
+ onChange?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
+ onValidate?: MyPostFormValidationValues;
+} & React.CSSProperties>;
+export default function MyPostForm(props: MyPostFormProps): React.ReactElement;
+"
+`;
+
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with belongsTo relationship 1`] = `
+"/* eslint-disable */
+import * as React from \\"react\\";
+import {
+ Autocomplete,
+ Badge,
+ Button,
+ Divider,
+ Flex,
+ Grid,
+ Icon,
+ ScrollView,
+ Text,
+ TextField,
+ useTheme,
+} from \\"@aws-amplify/ui-react\\";
+import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
+import { fetchByPath, validateField } from \\"./utils\\";
+import { API } from \\"aws-amplify\\";
+import { listTeams } from \\"../graphql/queries\\";
+import { createMember } from \\"../graphql/mutations\\";
+function ArrayField({
+ items = [],
+ onChange,
+ label,
+ inputFieldRef,
+ children,
+ hasError,
+ setFieldValue,
+ currentFieldValue,
+ defaultFieldValue,
+ lengthLimit,
+ getBadgeText,
+ errorMessage,
+}) {
+ const labelElement = {label};
+ const {
+ tokens: {
+ components: {
+ fieldmessages: { error: errorStyles },
+ },
+ },
+ } = useTheme();
+ const [selectedBadgeIndex, setSelectedBadgeIndex] = React.useState();
+ const [isEditing, setIsEditing] = React.useState();
+ React.useEffect(() => {
+ if (isEditing) {
+ inputFieldRef?.current?.focus();
+ }
+ }, [isEditing]);
+ const removeItem = async (removeIndex) => {
+ const newItems = items.filter((value, index) => index !== removeIndex);
+ await onChange(newItems);
+ setSelectedBadgeIndex(undefined);
+ };
+ const addItem = async () => {
+ if (
+ currentFieldValue !== undefined &&
+ currentFieldValue !== null &&
+ currentFieldValue !== \\"\\" &&
+ !hasError
+ ) {
+ const newItems = [...items];
+ if (selectedBadgeIndex !== undefined) {
+ newItems[selectedBadgeIndex] = currentFieldValue;
+ setSelectedBadgeIndex(undefined);
+ } else {
+ newItems.push(currentFieldValue);
+ }
+ await onChange(newItems);
+ setIsEditing(false);
+ }
+ };
+ const arraySection = (
+
+ {!!items?.length && (
+
+ {items.map((value, index) => {
+ return (
+ {
+ setSelectedBadgeIndex(index);
+ setFieldValue(items[index]);
+ setIsEditing(true);
+ }}
+ >
+ {getBadgeText ? getBadgeText(value) : value.toString()}
+ {
+ event.stopPropagation();
+ removeItem(index);
+ }}
+ />
+
+ );
+ })}
+
+ )}
+
+
+ );
+ if (lengthLimit !== undefined && items.length >= lengthLimit && !isEditing) {
+ return (
+
+ {labelElement}
+ {arraySection}
+
+ );
+ }
+ return (
+
+ {labelElement}
+ {isEditing && children}
+ {!isEditing ? (
+ <>
+
+ {errorMessage && hasError && (
+
+ {errorMessage}
+
+ )}
+ >
+ ) : (
+
+ {(currentFieldValue || isEditing) && (
+
+ )}
+
+
+ )}
+ {arraySection}
+
+ );
+}
+export default function MyMemberForm(props) {
+ const {
+ clearOnSuccess = true,
+ onSuccess,
+ onError,
+ onSubmit,
+ onCancel,
+ onValidate,
+ onChange,
+ overrides,
+ ...rest
+ } = props;
+ const initialValues = {
+ name: \\"\\",
+ teamID: undefined,
+ Team: undefined,
+ };
+ const [name, setName] = React.useState(initialValues.name);
+ const [teamID, setTeamID] = React.useState(initialValues.teamID);
+ const [teamIDLoading, setTeamIDLoading] = React.useState(false);
+ const [teamIDRecords, setTeamIDRecords] = React.useState([]);
+ const [Team, setTeam] = React.useState(initialValues.Team);
+ const [TeamLoading, setTeamLoading] = React.useState(false);
+ const [TeamRecords, setTeamRecords] = React.useState([]);
+ const autocompleteLength = 10;
+ const [errors, setErrors] = React.useState({});
+ const resetStateValues = () => {
+ setName(initialValues.name);
+ setTeamID(initialValues.teamID);
+ setCurrentTeamIDValue(undefined);
+ setCurrentTeamIDDisplayValue(\\"\\");
+ setTeam(initialValues.Team);
+ setCurrentTeamValue(undefined);
+ setCurrentTeamDisplayValue(\\"\\");
+ setErrors({});
+ };
+ const [currentTeamIDDisplayValue, setCurrentTeamIDDisplayValue] =
+ React.useState(\\"\\");
+ const [currentTeamIDValue, setCurrentTeamIDValue] = React.useState(undefined);
+ const teamIDRef = React.createRef();
+ const [currentTeamDisplayValue, setCurrentTeamDisplayValue] =
+ React.useState(\\"\\");
+ const [currentTeamValue, setCurrentTeamValue] = React.useState(undefined);
+ const TeamRef = React.createRef();
+ const getIDValue = {
+ Team: (r) => JSON.stringify({ id: r?.id }),
+ };
+ const TeamIdSet = new Set(
+ Array.isArray(Team)
+ ? Team.map((r) => getIDValue.Team?.(r))
+ : getIDValue.Team?.(Team)
+ );
+ const getDisplayValue = {
+ teamID: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
+ Team: (r) => r?.name,
+ };
+ const validations = {
+ name: [],
+ teamID: [{ type: \\"Required\\" }],
+ Team: [],
+ };
+ const runValidationTasks = async (
+ fieldName,
+ currentValue,
+ getDisplayValue
+ ) => {
+ const value =
+ currentValue && getDisplayValue
+ ? getDisplayValue(currentValue)
+ : currentValue;
+ let validationResponse = validateField(value, validations[fieldName]);
+ const customValidator = fetchByPath(onValidate, fieldName);
+ if (customValidator) {
+ validationResponse = await customValidator(value, validationResponse);
+ }
+ setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
+ return validationResponse;
+ };
+ const fetchTeamIDRecords = async (value) => {
+ setTeamIDLoading(true);
+ const newOptions = [];
+ let newNext = \\"\\";
+ while (newOptions.length < autocompleteLength && newNext != null) {
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: {
+ or: [{ name: { contains: value } }, { id: { contains: value } }],
+ },
+ };
+ if (newNext) {
+ variables[\\"nextToken\\"] = newNext;
+ }
+ const result = (
+ await API.graphql({
+ query: listTeams,
+ variables,
+ })
+ ).data.listTeamIDS.item;
+ var loaded = result.filter(
+ (item) => !teamIDIdSet.has(getIDValue.teamID?.(item))
+ );
+ newOptions.push(...loaded);
+ newNext = result.nextToken;
+ }
+ setTeamIDRecords(newOptions.slice(0, autocompleteLength));
+ setTeamIDLoading(false);
+ };
+ const fetchTeamRecords = async (value) => {
+ setTeamLoading(true);
+ const newOptions = [];
+ let newNext = \\"\\";
+ while (newOptions.length < autocompleteLength && newNext != null) {
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: { or: [{ name: { contains: value } }] },
+ };
+ if (newNext) {
+ variables[\\"nextToken\\"] = newNext;
+ }
+ const result = (
+ await API.graphql({
+ query: listTeams,
+ variables,
+ })
+ ).data.listTeams.item;
+ var loaded = result.filter(
+ (item) => !TeamIdSet.has(getIDValue.Team?.(item))
+ );
+ newOptions.push(...loaded);
+ newNext = result.nextToken;
+ }
+ setTeamRecords(newOptions.slice(0, autocompleteLength));
+ setTeamLoading(false);
+ };
+ return (
+ {
+ event.preventDefault();
+ let modelFields = {
+ name,
+ teamID,
+ Team,
+ };
+ const validationResponses = await Promise.all(
+ Object.keys(validations).reduce((promises, fieldName) => {
+ if (Array.isArray(modelFields[fieldName])) {
+ promises.push(
+ ...modelFields[fieldName].map((item) =>
+ runValidationTasks(
+ fieldName,
+ item,
+ getDisplayValue[fieldName]
+ )
+ )
+ );
+ return promises;
+ }
+ promises.push(
+ runValidationTasks(
+ fieldName,
+ modelFields[fieldName],
+ getDisplayValue[fieldName]
+ )
+ );
+ return promises;
+ }, [])
+ );
+ if (validationResponses.some((r) => r.hasError)) {
+ return;
+ }
+ if (onSubmit) {
+ modelFields = onSubmit(modelFields);
+ }
+ try {
+ Object.entries(modelFields).forEach(([key, value]) => {
+ if (typeof value === \\"string\\" && value.trim() === \\"\\") {
+ modelFields[key] = undefined;
+ }
+ });
+ await API.graphql({
+ query: createMember,
+ variables: {
+ input: {
+ ...modelFields,
+ },
+ },
+ });
+ if (onSuccess) {
+ onSuccess(modelFields);
+ }
+ if (clearOnSuccess) {
+ resetStateValues();
+ }
+ } catch (err) {
+ if (onError) {
+ onError(modelFields, err.message);
+ }
+ }
+ }}
+ {...getOverrideProps(overrides, \\"MyMemberForm\\")}
+ {...rest}
+ >
+
+
+
+
+
+
+
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ name: value,
+ teamID,
+ Team,
+ };
+ const result = onChange(modelFields);
+ value = result?.name ?? value;
+ }
+ if (errors.name?.hasError) {
+ runValidationTasks(\\"name\\", value);
+ }
+ setName(value);
+ }}
+ onBlur={() => runValidationTasks(\\"name\\", name)}
+ errorMessage={errors.name?.errorMessage}
+ hasError={errors.name?.hasError}
+ {...getOverrideProps(overrides, \\"name\\")}
+ >
+ {
+ let value = items[0];
+ if (onChange) {
+ const modelFields = {
+ name,
+ teamID: value,
+ Team,
+ };
+ const result = onChange(modelFields);
+ value = result?.teamID ?? value;
+ }
+ setTeamID(value);
+ setCurrentTeamIDValue(undefined);
+ }}
+ currentFieldValue={currentTeamIDValue}
+ label={\\"Team id\\"}
+ items={teamID ? [teamID] : []}
+ hasError={errors?.teamID?.hasError}
+ errorMessage={errors?.teamID?.errorMessage}
+ getBadgeText={(value) =>
+ value
+ ? getDisplayValue.teamID(teamRecords.find((r) => r.id === value))
+ : \\"\\"
+ }
+ setFieldValue={(value) => {
+ setCurrentTeamIDDisplayValue(
+ value
+ ? getDisplayValue.teamID(teamRecords.find((r) => r.id === value))
+ : \\"\\"
+ );
+ setCurrentTeamIDValue(value);
+ }}
+ inputFieldRef={teamIDRef}
+ defaultFieldValue={\\"\\"}
+ >
+
+ arr.findIndex((member) => member?.id === r?.id) === i
+ )
+ .map((r) => ({
+ id: r?.id,
+ label: getDisplayValue.teamID?.(r),
+ }))}
+ isLoading={teamIDLoading}
+ onSelect={({ id, label }) => {
+ setCurrentTeamIDValue(id);
+ setCurrentTeamIDDisplayValue(label);
+ runValidationTasks(\\"teamID\\", label);
+ }}
+ onClear={() => {
+ setCurrentTeamIDDisplayValue(\\"\\");
+ }}
+ onChange={(e) => {
+ let { value } = e.target;
+ fetchTeamIDRecords(value);
+ if (errors.teamID?.hasError) {
+ runValidationTasks(\\"teamID\\", value);
+ }
+ setCurrentTeamIDDisplayValue(value);
+ setCurrentTeamIDValue(undefined);
+ }}
+ onBlur={() => runValidationTasks(\\"teamID\\", currentTeamIDValue)}
+ errorMessage={errors.teamID?.errorMessage}
+ hasError={errors.teamID?.hasError}
+ ref={teamIDRef}
+ labelHidden={true}
+ {...getOverrideProps(overrides, \\"teamID\\")}
+ >
+
+ {
+ let value = items[0];
+ if (onChange) {
+ const modelFields = {
+ name,
teamID,
Team: value,
};
const result = onChange(modelFields);
- value = result?.Team ?? value;
+ value = result?.Team ?? value;
+ }
+ setTeam(value);
+ setCurrentTeamValue(undefined);
+ setCurrentTeamDisplayValue(\\"\\");
+ }}
+ currentFieldValue={currentTeamValue}
+ label={\\"Team Label\\"}
+ items={Team ? [Team] : []}
+ hasError={errors?.Team?.hasError}
+ errorMessage={errors?.Team?.errorMessage}
+ getBadgeText={getDisplayValue.Team}
+ setFieldValue={(model) => {
+ setCurrentTeamDisplayValue(model ? getDisplayValue.Team(model) : \\"\\");
+ setCurrentTeamValue(model);
+ }}
+ inputFieldRef={TeamRef}
+ defaultFieldValue={\\"\\"}
+ >
+ !TeamIdSet.has(getIDValue.Team?.(r)))
+ .map((r) => ({
+ id: getIDValue.Team?.(r),
+ label: getDisplayValue.Team?.(r),
+ }))}
+ isLoading={TeamLoading}
+ onSelect={({ id, label }) => {
+ setCurrentTeamValue(
+ teamRecords.find((r) =>
+ Object.entries(JSON.parse(id)).every(
+ ([key, value]) => r[key] === value
+ )
+ )
+ );
+ setCurrentTeamDisplayValue(label);
+ runValidationTasks(\\"Team\\", label);
+ }}
+ onClear={() => {
+ setCurrentTeamDisplayValue(\\"\\");
+ }}
+ onChange={(e) => {
+ let { value } = e.target;
+ fetchTeamRecords(value);
+ if (errors.Team?.hasError) {
+ runValidationTasks(\\"Team\\", value);
+ }
+ setCurrentTeamDisplayValue(value);
+ setCurrentTeamValue(undefined);
+ }}
+ onBlur={() => runValidationTasks(\\"Team\\", currentTeamDisplayValue)}
+ errorMessage={errors.Team?.errorMessage}
+ hasError={errors.Team?.hasError}
+ ref={TeamRef}
+ labelHidden={true}
+ {...getOverrideProps(overrides, \\"Team\\")}
+ >
+
+
+ );
+}
+"
+`;
+
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with belongsTo relationship 2`] = `
+"import * as React from \\"react\\";
+import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
+import { Team } from \\"../API\\";
+export declare type ValidationResponse = {
+ hasError: boolean;
+ errorMessage?: string;
+};
+export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
+export declare type MyMemberFormInputValues = {
+ name?: string;
+ teamID?: string;
+ Team?: Team;
+};
+export declare type MyMemberFormValidationValues = {
+ name?: ValidationFunction;
+ teamID?: ValidationFunction;
+ Team?: ValidationFunction;
+};
+export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
+export declare type MyMemberFormOverridesProps = {
+ MyMemberFormGrid?: PrimitiveOverrideProps;
+ name?: PrimitiveOverrideProps;
+ teamID?: PrimitiveOverrideProps;
+ Team?: PrimitiveOverrideProps;
+} & EscapeHatchProps;
+export declare type MyMemberFormProps = React.PropsWithChildren<{
+ overrides?: MyMemberFormOverridesProps | undefined | null;
+} & {
+ clearOnSuccess?: boolean;
+ onSubmit?: (fields: MyMemberFormInputValues) => MyMemberFormInputValues;
+ onSuccess?: (fields: MyMemberFormInputValues) => void;
+ onError?: (fields: MyMemberFormInputValues, errorMessage: string) => void;
+ onCancel?: () => void;
+ onChange?: (fields: MyMemberFormInputValues) => MyMemberFormInputValues;
+ onValidate?: MyMemberFormValidationValues;
+} & React.CSSProperties>;
+export default function MyMemberForm(props: MyMemberFormProps): React.ReactElement;
+"
+`;
+
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasMany relationship 1`] = `
+"/* eslint-disable */
+import * as React from \\"react\\";
+import {
+ Autocomplete,
+ Badge,
+ Button,
+ Divider,
+ Flex,
+ Grid,
+ Icon,
+ ScrollView,
+ Text,
+ TextField,
+ useTheme,
+} from \\"@aws-amplify/ui-react\\";
+import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
+import { fetchByPath, validateField } from \\"./utils\\";
+import { API } from \\"aws-amplify\\";
+import { listStudents } from \\"../graphql/queries\\";
+import { createSchool, updateSchool } from \\"../graphql/mutations\\";
+function ArrayField({
+ items = [],
+ onChange,
+ label,
+ inputFieldRef,
+ children,
+ hasError,
+ setFieldValue,
+ currentFieldValue,
+ defaultFieldValue,
+ lengthLimit,
+ getBadgeText,
+ errorMessage,
+}) {
+ const labelElement = {label};
+ const {
+ tokens: {
+ components: {
+ fieldmessages: { error: errorStyles },
+ },
+ },
+ } = useTheme();
+ const [selectedBadgeIndex, setSelectedBadgeIndex] = React.useState();
+ const [isEditing, setIsEditing] = React.useState();
+ React.useEffect(() => {
+ if (isEditing) {
+ inputFieldRef?.current?.focus();
+ }
+ }, [isEditing]);
+ const removeItem = async (removeIndex) => {
+ const newItems = items.filter((value, index) => index !== removeIndex);
+ await onChange(newItems);
+ setSelectedBadgeIndex(undefined);
+ };
+ const addItem = async () => {
+ if (
+ currentFieldValue !== undefined &&
+ currentFieldValue !== null &&
+ currentFieldValue !== \\"\\" &&
+ !hasError
+ ) {
+ const newItems = [...items];
+ if (selectedBadgeIndex !== undefined) {
+ newItems[selectedBadgeIndex] = currentFieldValue;
+ setSelectedBadgeIndex(undefined);
+ } else {
+ newItems.push(currentFieldValue);
+ }
+ await onChange(newItems);
+ setIsEditing(false);
+ }
+ };
+ const arraySection = (
+
+ {!!items?.length && (
+
+ {items.map((value, index) => {
+ return (
+ {
+ setSelectedBadgeIndex(index);
+ setFieldValue(items[index]);
+ setIsEditing(true);
+ }}
+ >
+ {getBadgeText ? getBadgeText(value) : value.toString()}
+ {
+ event.stopPropagation();
+ removeItem(index);
+ }}
+ />
+
+ );
+ })}
+
+ )}
+
+
+ );
+ if (lengthLimit !== undefined && items.length >= lengthLimit && !isEditing) {
+ return (
+
+ {labelElement}
+ {arraySection}
+
+ );
+ }
+ return (
+
+ {labelElement}
+ {isEditing && children}
+ {!isEditing ? (
+ <>
+
+ {errorMessage && hasError && (
+
+ {errorMessage}
+
+ )}
+ >
+ ) : (
+
+ {(currentFieldValue || isEditing) && (
+
+ )}
+
+
+ )}
+ {arraySection}
+
+ );
+}
+export default function SchoolCreateForm(props) {
+ const {
+ clearOnSuccess = true,
+ onSuccess,
+ onError,
+ onSubmit,
+ onCancel,
+ onValidate,
+ onChange,
+ overrides,
+ ...rest
+ } = props;
+ const initialValues = {
+ name: \\"\\",
+ Students: [],
+ };
+ const [name, setName] = React.useState(initialValues.name);
+ const [Students, setStudents] = React.useState(initialValues.Students);
+ const [StudentsLoading, setStudentsLoading] = React.useState(false);
+ const [StudentsRecords, setStudentsRecords] = React.useState([]);
+ const autocompleteLength = 10;
+ const [errors, setErrors] = React.useState({});
+ const resetStateValues = () => {
+ setName(initialValues.name);
+ setStudents(initialValues.Students);
+ setCurrentStudentsValue(undefined);
+ setCurrentStudentsDisplayValue(\\"\\");
+ setErrors({});
+ };
+ const [currentStudentsDisplayValue, setCurrentStudentsDisplayValue] =
+ React.useState(\\"\\");
+ const [currentStudentsValue, setCurrentStudentsValue] =
+ React.useState(undefined);
+ const StudentsRef = React.createRef();
+ const getIDValue = {
+ Students: (r) => JSON.stringify({ id: r?.id }),
+ };
+ const StudentsIdSet = new Set(
+ Array.isArray(Students)
+ ? Students.map((r) => getIDValue.Students?.(r))
+ : getIDValue.Students?.(Students)
+ );
+ const getDisplayValue = {
+ Students: (r) => r?.name,
+ };
+ const validations = {
+ name: [],
+ Students: [],
+ };
+ const runValidationTasks = async (
+ fieldName,
+ currentValue,
+ getDisplayValue
+ ) => {
+ const value =
+ currentValue && getDisplayValue
+ ? getDisplayValue(currentValue)
+ : currentValue;
+ let validationResponse = validateField(value, validations[fieldName]);
+ const customValidator = fetchByPath(onValidate, fieldName);
+ if (customValidator) {
+ validationResponse = await customValidator(value, validationResponse);
+ }
+ setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
+ return validationResponse;
+ };
+ const fetchStudentsRecords = async (value) => {
+ setStudentsLoading(true);
+ const newOptions = [];
+ let newNext = \\"\\";
+ while (newOptions.length < autocompleteLength && newNext != null) {
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: { or: [{ name: { contains: value } }] },
+ };
+ if (newNext) {
+ variables[\\"nextToken\\"] = newNext;
+ }
+ const result = (
+ await API.graphql({
+ query: listStudents,
+ variables,
+ })
+ ).data.listStudents.item;
+ var loaded = result.filter(
+ (item) => !StudentsIdSet.has(getIDValue.Students?.(item))
+ );
+ newOptions.push(...loaded);
+ newNext = result.nextToken;
+ }
+ setStudentsRecords(newOptions.slice(0, autocompleteLength));
+ setStudentsLoading(false);
+ };
+ return (
+ {
+ event.preventDefault();
+ let modelFields = {
+ name,
+ Students,
+ };
+ const validationResponses = await Promise.all(
+ Object.keys(validations).reduce((promises, fieldName) => {
+ if (Array.isArray(modelFields[fieldName])) {
+ promises.push(
+ ...modelFields[fieldName].map((item) =>
+ runValidationTasks(
+ fieldName,
+ item,
+ getDisplayValue[fieldName]
+ )
+ )
+ );
+ return promises;
+ }
+ promises.push(
+ runValidationTasks(
+ fieldName,
+ modelFields[fieldName],
+ getDisplayValue[fieldName]
+ )
+ );
+ return promises;
+ }, [])
+ );
+ if (validationResponses.some((r) => r.hasError)) {
+ return;
+ }
+ if (onSubmit) {
+ modelFields = onSubmit(modelFields);
+ }
+ try {
+ Object.entries(modelFields).forEach(([key, value]) => {
+ if (typeof value === \\"string\\" && value.trim() === \\"\\") {
+ modelFields[key] = undefined;
+ }
+ });
+ const modelFieldsToSave = {
+ name: modelFields.name,
+ };
+ const school = await API.graphql({
+ query: createSchool,
+ variables: {
+ input: {
+ ...modelFieldsToSave,
+ },
+ },
+ });
+ const promises = [];
+ promises.push(
+ ...Students.reduce((promises, original) => {
+ promises.push(
+ API.graphql({
+ query: updateSchool,
+ variables: {
+ input: {
+ ...original,
+ schoolID: school.id,
+ },
+ },
+ })
+ );
+ return promises;
+ }, [])
+ );
+ await Promise.all(promises);
+ if (onSuccess) {
+ onSuccess(modelFields);
+ }
+ if (clearOnSuccess) {
+ resetStateValues();
+ }
+ } catch (err) {
+ if (onError) {
+ onError(modelFields, err.message);
+ }
+ }
+ }}
+ {...getOverrideProps(overrides, \\"SchoolCreateForm\\")}
+ {...rest}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ name: value,
+ Students,
+ };
+ const result = onChange(modelFields);
+ value = result?.name ?? value;
+ }
+ if (errors.name?.hasError) {
+ runValidationTasks(\\"name\\", value);
+ }
+ setName(value);
+ }}
+ onBlur={() => runValidationTasks(\\"name\\", name)}
+ errorMessage={errors.name?.errorMessage}
+ hasError={errors.name?.hasError}
+ {...getOverrideProps(overrides, \\"name\\")}
+ >
+ {
+ let values = items;
+ if (onChange) {
+ const modelFields = {
+ name,
+ Students: values,
+ };
+ const result = onChange(modelFields);
+ values = result?.Students ?? values;
}
- setTeam(value);
- setCurrentTeamValue(undefined);
- setCurrentTeamDisplayValue(\\"\\");
+ setStudents(values);
+ setCurrentStudentsValue(undefined);
+ setCurrentStudentsDisplayValue(\\"\\");
}}
- currentFieldValue={currentTeamValue}
- label={\\"Team Label\\"}
- items={Team ? [Team] : []}
- hasError={errors?.Team?.hasError}
- errorMessage={errors?.Team?.errorMessage}
- getBadgeText={getDisplayValue.Team}
+ currentFieldValue={currentStudentsValue}
+ label={\\"Students\\"}
+ items={Students}
+ hasError={errors?.Students?.hasError}
+ errorMessage={errors?.Students?.errorMessage}
+ getBadgeText={getDisplayValue.Students}
setFieldValue={(model) => {
- setCurrentTeamDisplayValue(model ? getDisplayValue.Team(model) : \\"\\");
- setCurrentTeamValue(model);
+ setCurrentStudentsDisplayValue(
+ model ? getDisplayValue.Students(model) : \\"\\"
+ );
+ setCurrentStudentsValue(model);
}}
- inputFieldRef={TeamRef}
+ inputFieldRef={StudentsRef}
defaultFieldValue={\\"\\"}
>
!TeamIdSet.has(getIDValue.Team?.(r)))
+ placeholder=\\"Search Student\\"
+ value={currentStudentsDisplayValue}
+ options={studentsRecords
+ .filter((r) => !StudentsIdSet.has(getIDValue.Students?.(r)))
.map((r) => ({
- id: getIDValue.Team?.(r),
- label: getDisplayValue.Team?.(r),
+ id: getIDValue.Students?.(r),
+ label: getDisplayValue.Students?.(r),
}))}
- isLoading={TeamLoading}
+ isLoading={StudentsLoading}
onSelect={({ id, label }) => {
- setCurrentTeamValue(
- teamRecords.find((r) =>
+ setCurrentStudentsValue(
+ studentRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
- setCurrentTeamDisplayValue(label);
- runValidationTasks(\\"Team\\", label);
+ setCurrentStudentsDisplayValue(label);
+ runValidationTasks(\\"Students\\", label);
}}
onClear={() => {
- setCurrentTeamDisplayValue(\\"\\");
+ setCurrentStudentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
- fetchTeamRecords(value);
- if (errors.Team?.hasError) {
- runValidationTasks(\\"Team\\", value);
+ fetchStudentsRecords(value);
+ if (errors.Students?.hasError) {
+ runValidationTasks(\\"Students\\", value);
}
- setCurrentTeamDisplayValue(value);
- setCurrentTeamValue(undefined);
+ setCurrentStudentsDisplayValue(value);
+ setCurrentStudentsValue(undefined);
}}
- onBlur={() => runValidationTasks(\\"Team\\", currentTeamDisplayValue)}
- errorMessage={errors.Team?.errorMessage}
- hasError={errors.Team?.hasError}
- ref={TeamRef}
+ onBlur={() =>
+ runValidationTasks(\\"Students\\", currentStudentsDisplayValue)
+ }
+ errorMessage={errors.Students?.errorMessage}
+ hasError={errors.Students?.hasError}
+ ref={StudentsRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"Team\\")}
+ {...getOverrideProps(overrides, \\"Students\\")}
>
+
+
+
+
+
+
+
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with belongsTo relationship 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasMany relationship 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Team } from \\"../API\\";
+import { Student } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type MyMemberFormInputValues = {
+export declare type SchoolCreateFormInputValues = {
name?: string;
- teamID?: string;
- Team?: Team;
+ Students?: Student[];
};
-export declare type MyMemberFormValidationValues = {
+export declare type SchoolCreateFormValidationValues = {
name?: ValidationFunction;
- teamID?: ValidationFunction;
- Team?: ValidationFunction;
+ Students?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type MyMemberFormOverridesProps = {
- MyMemberFormGrid?: PrimitiveOverrideProps;
+export declare type SchoolCreateFormOverridesProps = {
+ SchoolCreateFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
- teamID?: PrimitiveOverrideProps;
- Team?: PrimitiveOverrideProps;
+ Students?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type MyMemberFormProps = React.PropsWithChildren<{
- overrides?: MyMemberFormOverridesProps | undefined | null;
+export declare type SchoolCreateFormProps = React.PropsWithChildren<{
+ overrides?: SchoolCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
- onSubmit?: (fields: MyMemberFormInputValues) => MyMemberFormInputValues;
- onSuccess?: (fields: MyMemberFormInputValues) => void;
- onError?: (fields: MyMemberFormInputValues, errorMessage: string) => void;
+ onSubmit?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
+ onSuccess?: (fields: SchoolCreateFormInputValues) => void;
+ onError?: (fields: SchoolCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
- onChange?: (fields: MyMemberFormInputValues) => MyMemberFormInputValues;
- onValidate?: MyMemberFormValidationValues;
+ onChange?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
+ onValidate?: SchoolCreateFormValidationValues;
} & React.CSSProperties>;
-export default function MyMemberForm(props: MyMemberFormProps): React.ReactElement;
+export default function SchoolCreateForm(props: SchoolCreateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasMany relationship 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasOne relationship 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
@@ -1322,8 +2407,8 @@ import {
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { listStudents } from \\"../graphql/queries\\";
-import { createSchool, updateSchool } from \\"../graphql/mutations\\";
+import { listAuthors } from \\"../graphql/queries\\";
+import { createBook } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -1482,7 +2567,7 @@ function ArrayField({
);
}
-export default function SchoolCreateForm(props) {
+export default function BookCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
@@ -1496,40 +2581,44 @@ export default function SchoolCreateForm(props) {
} = props;
const initialValues = {
name: \\"\\",
- Students: [],
+ primaryAuthor: undefined,
};
const [name, setName] = React.useState(initialValues.name);
- const [Students, setStudents] = React.useState(initialValues.Students);
- const [StudentsLoading, setStudentsLoading] = React.useState(false);
- const [StudentsRecords, setStudentsRecords] = React.useState([]);
+ const [primaryAuthor, setPrimaryAuthor] = React.useState(
+ initialValues.primaryAuthor
+ );
+ const [primaryAuthorLoading, setPrimaryAuthorLoading] = React.useState(false);
+ const [primaryAuthorRecords, setPrimaryAuthorRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
setName(initialValues.name);
- setStudents(initialValues.Students);
- setCurrentStudentsValue(undefined);
- setCurrentStudentsDisplayValue(\\"\\");
+ setPrimaryAuthor(initialValues.primaryAuthor);
+ setCurrentPrimaryAuthorValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
setErrors({});
};
- const [currentStudentsDisplayValue, setCurrentStudentsDisplayValue] =
- React.useState(\\"\\");
- const [currentStudentsValue, setCurrentStudentsValue] =
+ const [
+ currentPrimaryAuthorDisplayValue,
+ setCurrentPrimaryAuthorDisplayValue,
+ ] = React.useState(\\"\\");
+ const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
React.useState(undefined);
- const StudentsRef = React.createRef();
+ const primaryAuthorRef = React.createRef();
const getIDValue = {
- Students: (r) => JSON.stringify({ id: r?.id }),
+ primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
};
- const StudentsIdSet = new Set(
- Array.isArray(Students)
- ? Students.map((r) => getIDValue.Students?.(r))
- : getIDValue.Students?.(Students)
+ const primaryAuthorIdSet = new Set(
+ Array.isArray(primaryAuthor)
+ ? primaryAuthor.map((r) => getIDValue.primaryAuthor?.(r))
+ : getIDValue.primaryAuthor?.(primaryAuthor)
);
const getDisplayValue = {
- Students: (r) => r?.name,
+ primaryAuthor: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
name: [],
- Students: [],
+ primaryAuthor: [],
};
const runValidationTasks = async (
fieldName,
@@ -1548,32 +2637,34 @@ export default function SchoolCreateForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
- const fetchStudentsRecords = async (value) => {
- setStudentsLoading(true);
+ const fetchPrimaryAuthorRecords = async (value) => {
+ setPrimaryAuthorLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
- filter: { or: [{ name: { contains: value } }] },
+ filter: {
+ or: [{ name: { contains: value } }, { id: { contains: value } }],
+ },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
- query: listStudents,
+ query: listAuthors,
variables,
})
- ).data.listStudents.item;
+ ).data.listPrimaryAuthors.item;
var loaded = result.filter(
- (item) => !StudentsIdSet.has(getIDValue.Students?.(item))
+ (item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
- setStudentsRecords(newOptions.slice(0, autocompleteLength));
- setStudentsLoading(false);
+ setPrimaryAuthorRecords(newOptions.slice(0, autocompleteLength));
+ setPrimaryAuthorLoading(false);
};
return (
{
@@ -1623,35 +2714,14 @@ export default function SchoolCreateForm(props) {
modelFields[key] = undefined;
}
});
- const modelFieldsToSave = {
- name: modelFields.name,
- };
- const school = await API.graphql({
- query: createSchool,
+ await API.graphql({
+ query: createBook,
variables: {
input: {
- ...modelFieldsToSave,
+ ...modelFields,
},
},
});
- const promises = [];
- promises.push(
- ...Students.reduce((promises, original) => {
- promises.push(
- API.graphql({
- query: updateSchool,
- variables: {
- input: {
- ...original,
- schoolID: school.id,
- },
- },
- })
- );
- return promises;
- }, [])
- );
- await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
@@ -1664,9 +2734,43 @@ export default function SchoolCreateForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"SchoolCreateForm\\")}
+ {...getOverrideProps(overrides, \\"BookCreateForm\\")}
{...rest}
>
+
+
+
+
+
+
+
{
- let values = items;
+ let value = items[0];
if (onChange) {
const modelFields = {
name,
- Students: values,
+ primaryAuthor: value,
};
const result = onChange(modelFields);
- values = result?.Students ?? values;
+ value = result?.primaryAuthor ?? value;
}
- setStudents(values);
- setCurrentStudentsValue(undefined);
- setCurrentStudentsDisplayValue(\\"\\");
+ setPrimaryAuthor(value);
+ setCurrentPrimaryAuthorValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
- currentFieldValue={currentStudentsValue}
- label={\\"Students\\"}
- items={Students}
- hasError={errors?.Students?.hasError}
- errorMessage={errors?.Students?.errorMessage}
- getBadgeText={getDisplayValue.Students}
+ currentFieldValue={currentPrimaryAuthorValue}
+ label={\\"Primary author\\"}
+ items={primaryAuthor ? [primaryAuthor] : []}
+ hasError={errors?.primaryAuthor?.hasError}
+ errorMessage={errors?.primaryAuthor?.errorMessage}
+ getBadgeText={getDisplayValue.primaryAuthor}
setFieldValue={(model) => {
- setCurrentStudentsDisplayValue(
- model ? getDisplayValue.Students(model) : \\"\\"
+ setCurrentPrimaryAuthorDisplayValue(
+ model ? getDisplayValue.primaryAuthor(model) : \\"\\"
);
- setCurrentStudentsValue(model);
+ setCurrentPrimaryAuthorValue(model);
}}
- inputFieldRef={StudentsRef}
+ inputFieldRef={primaryAuthorRef}
defaultFieldValue={\\"\\"}
>
!StudentsIdSet.has(getIDValue.Students?.(r)))
+ placeholder=\\"Search Author\\"
+ value={currentPrimaryAuthorDisplayValue}
+ options={primaryAuthorRecords
+ .filter(
+ (r) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
+ )
.map((r) => ({
- id: getIDValue.Students?.(r),
- label: getDisplayValue.Students?.(r),
+ id: getIDValue.primaryAuthor?.(r),
+ label: getDisplayValue.primaryAuthor?.(r),
}))}
- isLoading={StudentsLoading}
+ isLoading={primaryAuthorLoading}
onSelect={({ id, label }) => {
- setCurrentStudentsValue(
- studentRecords.find((r) =>
+ setCurrentPrimaryAuthorValue(
+ authorRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
- setCurrentStudentsDisplayValue(label);
- runValidationTasks(\\"Students\\", label);
+ setCurrentPrimaryAuthorDisplayValue(label);
+ runValidationTasks(\\"primaryAuthor\\", label);
}}
onClear={() => {
- setCurrentStudentsDisplayValue(\\"\\");
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
- fetchStudentsRecords(value);
- if (errors.Students?.hasError) {
- runValidationTasks(\\"Students\\", value);
+ fetchPrimaryAuthorRecords(value);
+ if (errors.primaryAuthor?.hasError) {
+ runValidationTasks(\\"primaryAuthor\\", value);
}
- setCurrentStudentsDisplayValue(value);
- setCurrentStudentsValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(value);
+ setCurrentPrimaryAuthorValue(undefined);
}}
onBlur={() =>
- runValidationTasks(\\"Students\\", currentStudentsDisplayValue)
+ runValidationTasks(
+ \\"primaryAuthor\\",
+ currentPrimaryAuthorDisplayValue
+ )
}
- errorMessage={errors.Students?.errorMessage}
- hasError={errors.Students?.hasError}
- ref={StudentsRef}
+ errorMessage={errors.primaryAuthor?.errorMessage}
+ hasError={errors.primaryAuthor?.hasError}
+ ref={primaryAuthorRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"Students\\")}
+ {...getOverrideProps(overrides, \\"primaryAuthor\\")}
>
-
-
-
-
-
-
-
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasMany relationship 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasOne relationship 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Student } from \\"../API\\";
+import { Author } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type SchoolCreateFormInputValues = {
+export declare type BookCreateFormInputValues = {
name?: string;
- Students?: Student[];
+ primaryAuthor?: Author;
};
-export declare type SchoolCreateFormValidationValues = {
+export declare type BookCreateFormValidationValues = {
name?: ValidationFunction;
- Students?: ValidationFunction;
+ primaryAuthor?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type SchoolCreateFormOverridesProps = {
- SchoolCreateFormGrid?: PrimitiveOverrideProps;
+export declare type BookCreateFormOverridesProps = {
+ BookCreateFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
- Students?: PrimitiveOverrideProps;
+ primaryAuthor?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type SchoolCreateFormProps = React.PropsWithChildren<{
- overrides?: SchoolCreateFormOverridesProps | undefined | null;
+export declare type BookCreateFormProps = React.PropsWithChildren<{
+ overrides?: BookCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
- onSubmit?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
- onSuccess?: (fields: SchoolCreateFormInputValues) => void;
- onError?: (fields: SchoolCreateFormInputValues, errorMessage: string) => void;
+ onSubmit?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
+ onSuccess?: (fields: BookCreateFormInputValues) => void;
+ onError?: (fields: BookCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
- onChange?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
- onValidate?: SchoolCreateFormValidationValues;
+ onChange?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
+ onValidate?: BookCreateFormValidationValues;
} & React.CSSProperties>;
-export default function SchoolCreateForm(props: SchoolCreateFormProps): React.ReactElement;
+export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasOne relationship 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with manyToMany relationship 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
@@ -1859,6 +2935,7 @@ import {
Grid,
Icon,
ScrollView,
+ SelectField,
Text,
TextField,
useTheme,
@@ -1866,8 +2943,8 @@ import {
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { listAuthors } from \\"../graphql/queries\\";
-import { createBook } from \\"../graphql/mutations\\";
+import { listPosts } from \\"../graphql/queries\\";
+import { createTag, createTagPost } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -2026,7 +3103,7 @@ function ArrayField({
);
}
-export default function BookCreateForm(props) {
+export default function TagCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
@@ -2039,45 +3116,55 @@ export default function BookCreateForm(props) {
...rest
} = props;
const initialValues = {
- name: \\"\\",
- primaryAuthor: undefined,
+ label: \\"\\",
+ Posts: [],
+ statuses: [],
};
- const [name, setName] = React.useState(initialValues.name);
- const [primaryAuthor, setPrimaryAuthor] = React.useState(
- initialValues.primaryAuthor
- );
- const [primaryAuthorLoading, setPrimaryAuthorLoading] = React.useState(false);
- const [primaryAuthorRecords, setPrimaryAuthorRecords] = React.useState([]);
+ const [label, setLabel] = React.useState(initialValues.label);
+ const [Posts, setPosts] = React.useState(initialValues.Posts);
+ const [PostsLoading, setPostsLoading] = React.useState(false);
+ const [PostsRecords, setPostsRecords] = React.useState([]);
+ const [statuses, setStatuses] = React.useState(initialValues.statuses);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
- setName(initialValues.name);
- setPrimaryAuthor(initialValues.primaryAuthor);
- setCurrentPrimaryAuthorValue(undefined);
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setLabel(initialValues.label);
+ setPosts(initialValues.Posts);
+ setCurrentPostsValue(undefined);
+ setCurrentPostsDisplayValue(\\"\\");
+ setStatuses(initialValues.statuses);
+ setCurrentStatusesValue(\\"\\");
setErrors({});
};
- const [
- currentPrimaryAuthorDisplayValue,
- setCurrentPrimaryAuthorDisplayValue,
- ] = React.useState(\\"\\");
- const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
- React.useState(undefined);
- const primaryAuthorRef = React.createRef();
+ const [currentPostsDisplayValue, setCurrentPostsDisplayValue] =
+ React.useState(\\"\\");
+ const [currentPostsValue, setCurrentPostsValue] = React.useState(undefined);
+ const PostsRef = React.createRef();
+ const [currentStatusesValue, setCurrentStatusesValue] = React.useState(\\"\\");
+ const statusesRef = React.createRef();
const getIDValue = {
- primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
+ Posts: (r) => JSON.stringify({ id: r?.id }),
};
- const primaryAuthorIdSet = new Set(
- Array.isArray(primaryAuthor)
- ? primaryAuthor.map((r) => getIDValue.primaryAuthor?.(r))
- : getIDValue.primaryAuthor?.(primaryAuthor)
+ const PostsIdSet = new Set(
+ Array.isArray(Posts)
+ ? Posts.map((r) => getIDValue.Posts?.(r))
+ : getIDValue.Posts?.(Posts)
);
const getDisplayValue = {
- primaryAuthor: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
+ Posts: (r) => r?.title,
+ statuses: (r) => {
+ const enumDisplayValueMap = {
+ PENDING: \\"Pending\\",
+ POSTED: \\"Posted\\",
+ IN_REVIEW: \\"In review\\",
+ };
+ return enumDisplayValueMap[r];
+ },
};
const validations = {
- name: [],
- primaryAuthor: [],
+ label: [],
+ Posts: [],
+ statuses: [],
};
const runValidationTasks = async (
fieldName,
@@ -2096,34 +3183,32 @@ export default function BookCreateForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
- const fetchPrimaryAuthorRecords = async (value) => {
- setPrimaryAuthorLoading(true);
+ const fetchPostsRecords = async (value) => {
+ setPostsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
- const variables = {
- limit: autocompleteLength * 5,
- filter: {
- or: [{ name: { contains: value } }, { id: { contains: value } }],
- },
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: { or: [{ title: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
- query: listAuthors,
+ query: listPosts,
variables,
})
- ).data.listPrimaryAuthors.item;
+ ).data.listPosts.item;
var loaded = result.filter(
- (item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
+ (item) => !PostsIdSet.has(getIDValue.Posts?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
- setPrimaryAuthorRecords(newOptions.slice(0, autocompleteLength));
- setPrimaryAuthorLoading(false);
+ setPostsRecords(newOptions.slice(0, autocompleteLength));
+ setPostsLoading(false);
};
return (
{
event.preventDefault();
let modelFields = {
- name,
- primaryAuthor,
+ label,
+ Posts,
+ statuses,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
@@ -2173,14 +3259,36 @@ export default function BookCreateForm(props) {
modelFields[key] = undefined;
}
});
- await API.graphql({
- query: createBook,
+ const modelFieldsToSave = {
+ label: modelFields.label,
+ statuses: modelFields.statuses,
+ };
+ const tag = await API.graphql({
+ query: createTag,
variables: {
input: {
- ...modelFields,
+ ...modelFieldsToSave,
},
},
});
+ const promises = [];
+ promises.push(
+ ...Posts.reduce((promises, post) => {
+ promises.push(
+ API.graphql({
+ query: createTagPost,
+ variables: {
+ input: {
+ tag,
+ post,
+ },
+ },
+ })
+ );
+ return promises;
+ }, [])
+ );
+ await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
@@ -2193,196 +3301,252 @@ export default function BookCreateForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"BookCreateForm\\")}
+ {...getOverrideProps(overrides, \\"TagCreateForm\\")}
{...rest}
>
-
-
-
-
-
-
-
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- name: value,
- primaryAuthor,
+ label: value,
+ Posts,
+ statuses,
};
const result = onChange(modelFields);
- value = result?.name ?? value;
+ value = result?.label ?? value;
}
- if (errors.name?.hasError) {
- runValidationTasks(\\"name\\", value);
+ if (errors.label?.hasError) {
+ runValidationTasks(\\"label\\", value);
}
- setName(value);
+ setLabel(value);
}}
- onBlur={() => runValidationTasks(\\"name\\", name)}
- errorMessage={errors.name?.errorMessage}
- hasError={errors.name?.hasError}
- {...getOverrideProps(overrides, \\"name\\")}
+ onBlur={() => runValidationTasks(\\"label\\", label)}
+ errorMessage={errors.label?.errorMessage}
+ hasError={errors.label?.hasError}
+ {...getOverrideProps(overrides, \\"label\\")}
>
{
- let value = items[0];
+ let values = items;
if (onChange) {
const modelFields = {
- name,
- primaryAuthor: value,
+ label,
+ Posts: values,
+ statuses,
};
const result = onChange(modelFields);
- value = result?.primaryAuthor ?? value;
+ values = result?.Posts ?? values;
}
- setPrimaryAuthor(value);
- setCurrentPrimaryAuthorValue(undefined);
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setPosts(values);
+ setCurrentPostsValue(undefined);
+ setCurrentPostsDisplayValue(\\"\\");
}}
- currentFieldValue={currentPrimaryAuthorValue}
- label={\\"Primary author\\"}
- items={primaryAuthor ? [primaryAuthor] : []}
- hasError={errors?.primaryAuthor?.hasError}
- errorMessage={errors?.primaryAuthor?.errorMessage}
- getBadgeText={getDisplayValue.primaryAuthor}
+ currentFieldValue={currentPostsValue}
+ label={\\"Posts\\"}
+ items={Posts}
+ hasError={errors?.Posts?.hasError}
+ errorMessage={errors?.Posts?.errorMessage}
+ getBadgeText={getDisplayValue.Posts}
setFieldValue={(model) => {
- setCurrentPrimaryAuthorDisplayValue(
- model ? getDisplayValue.primaryAuthor(model) : \\"\\"
+ setCurrentPostsDisplayValue(
+ model ? getDisplayValue.Posts(model) : \\"\\"
);
- setCurrentPrimaryAuthorValue(model);
+ setCurrentPostsValue(model);
}}
- inputFieldRef={primaryAuthorRef}
+ inputFieldRef={PostsRef}
defaultFieldValue={\\"\\"}
>
!primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
- )
- .map((r) => ({
- id: getIDValue.primaryAuthor?.(r),
- label: getDisplayValue.primaryAuthor?.(r),
- }))}
- isLoading={primaryAuthorLoading}
+ placeholder=\\"Search Post\\"
+ value={currentPostsDisplayValue}
+ options={postsRecords.map((r) => ({
+ id: getIDValue.Posts?.(r),
+ label: getDisplayValue.Posts?.(r),
+ }))}
+ isLoading={PostsLoading}
onSelect={({ id, label }) => {
- setCurrentPrimaryAuthorValue(
- authorRecords.find((r) =>
+ setCurrentPostsValue(
+ postRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
- setCurrentPrimaryAuthorDisplayValue(label);
- runValidationTasks(\\"primaryAuthor\\", label);
+ setCurrentPostsDisplayValue(label);
+ runValidationTasks(\\"Posts\\", label);
}}
onClear={() => {
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setCurrentPostsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
- fetchPrimaryAuthorRecords(value);
- if (errors.primaryAuthor?.hasError) {
- runValidationTasks(\\"primaryAuthor\\", value);
+ fetchPostsRecords(value);
+ if (errors.Posts?.hasError) {
+ runValidationTasks(\\"Posts\\", value);
}
- setCurrentPrimaryAuthorDisplayValue(value);
- setCurrentPrimaryAuthorValue(undefined);
+ setCurrentPostsDisplayValue(value);
+ setCurrentPostsValue(undefined);
}}
- onBlur={() =>
- runValidationTasks(
- \\"primaryAuthor\\",
- currentPrimaryAuthorDisplayValue
- )
- }
- errorMessage={errors.primaryAuthor?.errorMessage}
- hasError={errors.primaryAuthor?.hasError}
- ref={primaryAuthorRef}
+ onBlur={() => runValidationTasks(\\"Posts\\", currentPostsDisplayValue)}
+ errorMessage={errors.Posts?.errorMessage}
+ hasError={errors.Posts?.hasError}
+ ref={PostsRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"primaryAuthor\\")}
+ {...getOverrideProps(overrides, \\"Posts\\")}
>
+ {
+ let values = items;
+ if (onChange) {
+ const modelFields = {
+ label,
+ Posts,
+ statuses: values,
+ };
+ const result = onChange(modelFields);
+ values = result?.statuses ?? values;
+ }
+ setStatuses(values);
+ setCurrentStatusesValue(\\"\\");
+ }}
+ currentFieldValue={currentStatusesValue}
+ label={\\"Statuses\\"}
+ items={statuses}
+ hasError={errors?.statuses?.hasError}
+ errorMessage={errors?.statuses?.errorMessage}
+ getBadgeText={getDisplayValue.statuses}
+ setFieldValue={setCurrentStatusesValue}
+ inputFieldRef={statusesRef}
+ defaultFieldValue={\\"\\"}
+ >
+ {
+ let { value } = e.target;
+ if (errors.statuses?.hasError) {
+ runValidationTasks(\\"statuses\\", value);
+ }
+ setCurrentStatusesValue(value);
+ }}
+ onBlur={() => runValidationTasks(\\"statuses\\", currentStatusesValue)}
+ errorMessage={errors.statuses?.errorMessage}
+ hasError={errors.statuses?.hasError}
+ ref={statusesRef}
+ labelHidden={true}
+ {...getOverrideProps(overrides, \\"statuses\\")}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with hasOne relationship 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with manyToMany relationship 2`] = `
"import * as React from \\"react\\";
-import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { AutocompleteProps, GridProps, SelectFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Author } from \\"../API\\";
+import { Post } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type BookCreateFormInputValues = {
- name?: string;
- primaryAuthor?: Author;
+export declare type TagCreateFormInputValues = {
+ label?: string;
+ Posts?: Post[];
+ statuses?: string[];
};
-export declare type BookCreateFormValidationValues = {
- name?: ValidationFunction;
- primaryAuthor?: ValidationFunction;
+export declare type TagCreateFormValidationValues = {
+ label?: ValidationFunction;
+ Posts?: ValidationFunction;
+ statuses?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type BookCreateFormOverridesProps = {
- BookCreateFormGrid?: PrimitiveOverrideProps;
- name?: PrimitiveOverrideProps;
- primaryAuthor?: PrimitiveOverrideProps;
+export declare type TagCreateFormOverridesProps = {
+ TagCreateFormGrid?: PrimitiveOverrideProps;
+ label?: PrimitiveOverrideProps;
+ Posts?: PrimitiveOverrideProps;
+ statuses?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type BookCreateFormProps = React.PropsWithChildren<{
- overrides?: BookCreateFormOverridesProps | undefined | null;
+export declare type TagCreateFormProps = React.PropsWithChildren<{
+ overrides?: TagCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
- onSubmit?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
- onSuccess?: (fields: BookCreateFormInputValues) => void;
- onError?: (fields: BookCreateFormInputValues, errorMessage: string) => void;
+ onSubmit?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
+ onSuccess?: (fields: TagCreateFormInputValues) => void;
+ onError?: (fields: TagCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
- onChange?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
- onValidate?: BookCreateFormValidationValues;
+ onChange?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
+ onValidate?: TagCreateFormValidationValues;
} & React.CSSProperties>;
-export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
+export default function TagCreateForm(props: TagCreateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with manyToMany relationship 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with multiple hasOne relationships 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
@@ -2394,7 +3558,6 @@ import {
Grid,
Icon,
ScrollView,
- SelectField,
Text,
TextField,
useTheme,
@@ -2402,8 +3565,8 @@ import {
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { listPosts } from \\"../graphql/queries\\";
-import { createTag, createTagPost } from \\"../graphql/mutations\\";
+import { listAuthors, listTitles } from \\"../graphql/queries\\";
+import { createBook } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -2562,7 +3725,7 @@ function ArrayField({
);
}
-export default function TagCreateForm(props) {
+export default function BookCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
@@ -2575,55 +3738,67 @@ export default function TagCreateForm(props) {
...rest
} = props;
const initialValues = {
- label: \\"\\",
- Posts: [],
- statuses: [],
+ name: \\"\\",
+ primaryAuthor: undefined,
+ primaryTitle: undefined,
};
- const [label, setLabel] = React.useState(initialValues.label);
- const [Posts, setPosts] = React.useState(initialValues.Posts);
- const [PostsLoading, setPostsLoading] = React.useState(false);
- const [PostsRecords, setPostsRecords] = React.useState([]);
- const [statuses, setStatuses] = React.useState(initialValues.statuses);
+ const [name, setName] = React.useState(initialValues.name);
+ const [primaryAuthor, setPrimaryAuthor] = React.useState(
+ initialValues.primaryAuthor
+ );
+ const [primaryAuthorLoading, setPrimaryAuthorLoading] = React.useState(false);
+ const [primaryAuthorRecords, setPrimaryAuthorRecords] = React.useState([]);
+ const [primaryTitle, setPrimaryTitle] = React.useState(
+ initialValues.primaryTitle
+ );
+ const [primaryTitleLoading, setPrimaryTitleLoading] = React.useState(false);
+ const [primaryTitleRecords, setPrimaryTitleRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
- setLabel(initialValues.label);
- setPosts(initialValues.Posts);
- setCurrentPostsValue(undefined);
- setCurrentPostsDisplayValue(\\"\\");
- setStatuses(initialValues.statuses);
- setCurrentStatusesValue(\\"\\");
+ setName(initialValues.name);
+ setPrimaryAuthor(initialValues.primaryAuthor);
+ setCurrentPrimaryAuthorValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setPrimaryTitle(initialValues.primaryTitle);
+ setCurrentPrimaryTitleValue(undefined);
+ setCurrentPrimaryTitleDisplayValue(\\"\\");
setErrors({});
};
- const [currentPostsDisplayValue, setCurrentPostsDisplayValue] =
+ const [
+ currentPrimaryAuthorDisplayValue,
+ setCurrentPrimaryAuthorDisplayValue,
+ ] = React.useState(\\"\\");
+ const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
+ React.useState(undefined);
+ const primaryAuthorRef = React.createRef();
+ const [currentPrimaryTitleDisplayValue, setCurrentPrimaryTitleDisplayValue] =
React.useState(\\"\\");
- const [currentPostsValue, setCurrentPostsValue] = React.useState(undefined);
- const PostsRef = React.createRef();
- const [currentStatusesValue, setCurrentStatusesValue] = React.useState(\\"\\");
- const statusesRef = React.createRef();
+ const [currentPrimaryTitleValue, setCurrentPrimaryTitleValue] =
+ React.useState(undefined);
+ const primaryTitleRef = React.createRef();
const getIDValue = {
- Posts: (r) => JSON.stringify({ id: r?.id }),
+ primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
+ primaryTitle: (r) => JSON.stringify({ id: r?.id }),
};
- const PostsIdSet = new Set(
- Array.isArray(Posts)
- ? Posts.map((r) => getIDValue.Posts?.(r))
- : getIDValue.Posts?.(Posts)
+ const primaryAuthorIdSet = new Set(
+ Array.isArray(primaryAuthor)
+ ? primaryAuthor.map((r) => getIDValue.primaryAuthor?.(r))
+ : getIDValue.primaryAuthor?.(primaryAuthor)
+ );
+ const primaryTitleIdSet = new Set(
+ Array.isArray(primaryTitle)
+ ? primaryTitle.map((r) => getIDValue.primaryTitle?.(r))
+ : getIDValue.primaryTitle?.(primaryTitle)
);
const getDisplayValue = {
- Posts: (r) => r?.title,
- statuses: (r) => {
- const enumDisplayValueMap = {
- PENDING: \\"Pending\\",
- POSTED: \\"Posted\\",
- IN_REVIEW: \\"In review\\",
- };
- return enumDisplayValueMap[r];
- },
+ primaryAuthor: (r) => r?.name,
+ primaryTitle: (r) => r?.name,
};
const validations = {
- label: [],
- Posts: [],
- statuses: [],
+ name: [],
+ primaryAuthor: [],
+ primaryTitle: [],
};
const runValidationTasks = async (
fieldName,
@@ -2642,32 +3817,59 @@ export default function TagCreateForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
- const fetchPostsRecords = async (value) => {
- setPostsLoading(true);
+ const fetchPrimaryAuthorRecords = async (value) => {
+ setPrimaryAuthorLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
- filter: { or: [{ title: { contains: value } }] },
+ filter: { or: [{ name: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
- query: listPosts,
+ query: listAuthors,
variables,
})
- ).data.listPosts.item;
+ ).data.listPrimaryAuthors.item;
var loaded = result.filter(
- (item) => !PostsIdSet.has(getIDValue.Posts?.(item))
+ (item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
- setPostsRecords(newOptions.slice(0, autocompleteLength));
- setPostsLoading(false);
+ setPrimaryAuthorRecords(newOptions.slice(0, autocompleteLength));
+ setPrimaryAuthorLoading(false);
+ };
+ const fetchPrimaryTitleRecords = async (value) => {
+ setPrimaryTitleLoading(true);
+ const newOptions = [];
+ let newNext = \\"\\";
+ while (newOptions.length < autocompleteLength && newNext != null) {
+ const variables = {
+ limit: autocompleteLength * 5,
+ filter: { or: [{ name: { contains: value } }] },
+ };
+ if (newNext) {
+ variables[\\"nextToken\\"] = newNext;
+ }
+ const result = (
+ await API.graphql({
+ query: listTitles,
+ variables,
+ })
+ ).data.listPrimaryTitles.item;
+ var loaded = result.filter(
+ (item) => !primaryTitleIdSet.has(getIDValue.primaryTitle?.(item))
+ );
+ newOptions.push(...loaded);
+ newNext = result.nextToken;
+ }
+ setPrimaryTitleRecords(newOptions.slice(0, autocompleteLength));
+ setPrimaryTitleLoading(false);
};
return (
{
event.preventDefault();
let modelFields = {
- label,
- Posts,
- statuses,
+ name,
+ primaryAuthor,
+ primaryTitle,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
@@ -2718,36 +3920,14 @@ export default function TagCreateForm(props) {
modelFields[key] = undefined;
}
});
- const modelFieldsToSave = {
- label: modelFields.label,
- statuses: modelFields.statuses,
- };
- const tag = await API.graphql({
- query: createTag,
+ await API.graphql({
+ query: createBook,
variables: {
input: {
- ...modelFieldsToSave,
+ ...modelFields,
},
},
});
- const promises = [];
- promises.push(
- ...Posts.reduce((promises, post) => {
- promises.push(
- API.graphql({
- query: createTagPost,
- variables: {
- input: {
- tag,
- post,
- },
- },
- })
- );
- return promises;
- }, [])
- );
- await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
@@ -2760,252 +3940,279 @@ export default function TagCreateForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"TagCreateForm\\")}
+ {...getOverrideProps(overrides, \\"BookCreateForm\\")}
{...rest}
>
+
+
+
+
+
+
+
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- label: value,
- Posts,
- statuses,
+ name: value,
+ primaryAuthor,
+ primaryTitle,
};
const result = onChange(modelFields);
- value = result?.label ?? value;
+ value = result?.name ?? value;
}
- if (errors.label?.hasError) {
- runValidationTasks(\\"label\\", value);
+ if (errors.name?.hasError) {
+ runValidationTasks(\\"name\\", value);
}
- setLabel(value);
+ setName(value);
}}
- onBlur={() => runValidationTasks(\\"label\\", label)}
- errorMessage={errors.label?.errorMessage}
- hasError={errors.label?.hasError}
- {...getOverrideProps(overrides, \\"label\\")}
+ onBlur={() => runValidationTasks(\\"name\\", name)}
+ errorMessage={errors.name?.errorMessage}
+ hasError={errors.name?.hasError}
+ {...getOverrideProps(overrides, \\"name\\")}
>
{
- let values = items;
+ let value = items[0];
if (onChange) {
const modelFields = {
- label,
- Posts: values,
- statuses,
+ name,
+ primaryAuthor: value,
+ primaryTitle,
};
const result = onChange(modelFields);
- values = result?.Posts ?? values;
+ value = result?.primaryAuthor ?? value;
}
- setPosts(values);
- setCurrentPostsValue(undefined);
- setCurrentPostsDisplayValue(\\"\\");
+ setPrimaryAuthor(value);
+ setCurrentPrimaryAuthorValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
- currentFieldValue={currentPostsValue}
- label={\\"Posts\\"}
- items={Posts}
- hasError={errors?.Posts?.hasError}
- errorMessage={errors?.Posts?.errorMessage}
- getBadgeText={getDisplayValue.Posts}
+ currentFieldValue={currentPrimaryAuthorValue}
+ label={\\"Primary author\\"}
+ items={primaryAuthor ? [primaryAuthor] : []}
+ hasError={errors?.primaryAuthor?.hasError}
+ errorMessage={errors?.primaryAuthor?.errorMessage}
+ getBadgeText={getDisplayValue.primaryAuthor}
setFieldValue={(model) => {
- setCurrentPostsDisplayValue(
- model ? getDisplayValue.Posts(model) : \\"\\"
+ setCurrentPrimaryAuthorDisplayValue(
+ model ? getDisplayValue.primaryAuthor(model) : \\"\\"
);
- setCurrentPostsValue(model);
+ setCurrentPrimaryAuthorValue(model);
}}
- inputFieldRef={PostsRef}
+ inputFieldRef={primaryAuthorRef}
defaultFieldValue={\\"\\"}
>
({
- id: getIDValue.Posts?.(r),
- label: getDisplayValue.Posts?.(r),
- }))}
- isLoading={PostsLoading}
+ placeholder=\\"Search Author\\"
+ value={currentPrimaryAuthorDisplayValue}
+ options={primaryAuthorRecords
+ .filter(
+ (r) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
+ )
+ .map((r) => ({
+ id: getIDValue.primaryAuthor?.(r),
+ label: getDisplayValue.primaryAuthor?.(r),
+ }))}
+ isLoading={primaryAuthorLoading}
onSelect={({ id, label }) => {
- setCurrentPostsValue(
- postRecords.find((r) =>
+ setCurrentPrimaryAuthorValue(
+ authorRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
- setCurrentPostsDisplayValue(label);
- runValidationTasks(\\"Posts\\", label);
+ setCurrentPrimaryAuthorDisplayValue(label);
+ runValidationTasks(\\"primaryAuthor\\", label);
}}
onClear={() => {
- setCurrentPostsDisplayValue(\\"\\");
+ setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
- fetchPostsRecords(value);
- if (errors.Posts?.hasError) {
- runValidationTasks(\\"Posts\\", value);
+ fetchPrimaryAuthorRecords(value);
+ if (errors.primaryAuthor?.hasError) {
+ runValidationTasks(\\"primaryAuthor\\", value);
}
- setCurrentPostsDisplayValue(value);
- setCurrentPostsValue(undefined);
+ setCurrentPrimaryAuthorDisplayValue(value);
+ setCurrentPrimaryAuthorValue(undefined);
}}
- onBlur={() => runValidationTasks(\\"Posts\\", currentPostsDisplayValue)}
- errorMessage={errors.Posts?.errorMessage}
- hasError={errors.Posts?.hasError}
- ref={PostsRef}
+ onBlur={() =>
+ runValidationTasks(
+ \\"primaryAuthor\\",
+ currentPrimaryAuthorDisplayValue
+ )
+ }
+ errorMessage={errors.primaryAuthor?.errorMessage}
+ hasError={errors.primaryAuthor?.hasError}
+ ref={primaryAuthorRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"Posts\\")}
+ {...getOverrideProps(overrides, \\"primaryAuthor\\")}
>
{
- let values = items;
+ let value = items[0];
if (onChange) {
const modelFields = {
- label,
- Posts,
- statuses: values,
+ name,
+ primaryAuthor,
+ primaryTitle: value,
};
const result = onChange(modelFields);
- values = result?.statuses ?? values;
+ value = result?.primaryTitle ?? value;
}
- setStatuses(values);
- setCurrentStatusesValue(\\"\\");
+ setPrimaryTitle(value);
+ setCurrentPrimaryTitleValue(undefined);
+ setCurrentPrimaryTitleDisplayValue(\\"\\");
}}
- currentFieldValue={currentStatusesValue}
- label={\\"Statuses\\"}
- items={statuses}
- hasError={errors?.statuses?.hasError}
- errorMessage={errors?.statuses?.errorMessage}
- getBadgeText={getDisplayValue.statuses}
- setFieldValue={setCurrentStatusesValue}
- inputFieldRef={statusesRef}
+ currentFieldValue={currentPrimaryTitleValue}
+ label={\\"Primary title\\"}
+ items={primaryTitle ? [primaryTitle] : []}
+ hasError={errors?.primaryTitle?.hasError}
+ errorMessage={errors?.primaryTitle?.errorMessage}
+ getBadgeText={getDisplayValue.primaryTitle}
+ setFieldValue={(model) => {
+ setCurrentPrimaryTitleDisplayValue(
+ model ? getDisplayValue.primaryTitle(model) : \\"\\"
+ );
+ setCurrentPrimaryTitleValue(model);
+ }}
+ inputFieldRef={primaryTitleRef}
defaultFieldValue={\\"\\"}
>
- {
- let { value } = e.target;
- if (errors.statuses?.hasError) {
- runValidationTasks(\\"statuses\\", value);
- }
- setCurrentStatusesValue(value);
- }}
- onBlur={() => runValidationTasks(\\"statuses\\", currentStatusesValue)}
- errorMessage={errors.statuses?.errorMessage}
- hasError={errors.statuses?.hasError}
- ref={statusesRef}
- labelHidden={true}
- {...getOverrideProps(overrides, \\"statuses\\")}
- >
-
-
-
-
-
-
-
-
-
-
-
-
+ onClear={() => {
+ setCurrentPrimaryTitleDisplayValue(\\"\\");
+ }}
+ onChange={(e) => {
+ let { value } = e.target;
+ fetchPrimaryTitleRecords(value);
+ if (errors.primaryTitle?.hasError) {
+ runValidationTasks(\\"primaryTitle\\", value);
+ }
+ setCurrentPrimaryTitleDisplayValue(value);
+ setCurrentPrimaryTitleValue(undefined);
+ }}
+ onBlur={() =>
+ runValidationTasks(\\"primaryTitle\\", currentPrimaryTitleDisplayValue)
+ }
+ errorMessage={errors.primaryTitle?.errorMessage}
+ hasError={errors.primaryTitle?.hasError}
+ ref={primaryTitleRef}
+ labelHidden={true}
+ {...getOverrideProps(overrides, \\"primaryTitle\\")}
+ >
+
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with manyToMany relationship 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a create form with multiple hasOne relationships 2`] = `
"import * as React from \\"react\\";
-import { AutocompleteProps, GridProps, SelectFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Post } from \\"../API\\";
+import { Author, Title } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type TagCreateFormInputValues = {
- label?: string;
- Posts?: Post[];
- statuses?: string[];
+export declare type BookCreateFormInputValues = {
+ name?: string;
+ primaryAuthor?: Author;
+ primaryTitle?: Title;
};
-export declare type TagCreateFormValidationValues = {
- label?: ValidationFunction;
- Posts?: ValidationFunction;
- statuses?: ValidationFunction;
+export declare type BookCreateFormValidationValues = {
+ name?: ValidationFunction;
+ primaryAuthor?: ValidationFunction;
+ primaryTitle?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type TagCreateFormOverridesProps = {
- TagCreateFormGrid?: PrimitiveOverrideProps;
- label?: PrimitiveOverrideProps;
- Posts?: PrimitiveOverrideProps;
- statuses?: PrimitiveOverrideProps;
+export declare type BookCreateFormOverridesProps = {
+ BookCreateFormGrid?: PrimitiveOverrideProps;
+ name?: PrimitiveOverrideProps;
+ primaryAuthor?: PrimitiveOverrideProps;
+ primaryTitle?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type TagCreateFormProps = React.PropsWithChildren<{
- overrides?: TagCreateFormOverridesProps | undefined | null;
+export declare type BookCreateFormProps = React.PropsWithChildren<{
+ overrides?: BookCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
- onSubmit?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
- onSuccess?: (fields: TagCreateFormInputValues) => void;
- onError?: (fields: TagCreateFormInputValues, errorMessage: string) => void;
+ onSubmit?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
+ onSuccess?: (fields: BookCreateFormInputValues) => void;
+ onError?: (fields: BookCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
- onChange?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
- onValidate?: TagCreateFormValidationValues;
+ onChange?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
+ onValidate?: BookCreateFormValidationValues;
} & React.CSSProperties>;
-export default function TagCreateForm(props: TagCreateFormProps): React.ReactElement;
+export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with multiple hasOne relationships 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a relationship update form with autocomplete 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
@@ -3024,8 +4231,8 @@ import {
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { listAuthors, listTitles } from \\"../graphql/queries\\";
-import { createBook } from \\"../graphql/mutations\\";
+import { commentsByPostID, getPost, listComments } from \\"../graphql/queries\\";
+import { deleteComment, updateComment, updatePost } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -3184,151 +4391,165 @@ function ArrayField({
);
}
-export default function BookCreateForm(props) {
+export default function PostUpdateForm(props) {
const {
- clearOnSuccess = true,
+ id: idProp,
+ post: postModelProp,
onSuccess,
onError,
onSubmit,
- onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
- name: \\"\\",
- primaryAuthor: undefined,
- primaryTitle: undefined,
+ title: \\"\\",
+ body: \\"\\",
+ publishDate: \\"\\",
+ Comments: [],
};
- const [name, setName] = React.useState(initialValues.name);
- const [primaryAuthor, setPrimaryAuthor] = React.useState(
- initialValues.primaryAuthor
- );
- const [primaryAuthorLoading, setPrimaryAuthorLoading] = React.useState(false);
- const [primaryAuthorRecords, setPrimaryAuthorRecords] = React.useState([]);
- const [primaryTitle, setPrimaryTitle] = React.useState(
- initialValues.primaryTitle
+ const [title, setTitle] = React.useState(initialValues.title);
+ const [body, setBody] = React.useState(initialValues.body);
+ const [publishDate, setPublishDate] = React.useState(
+ initialValues.publishDate
);
- const [primaryTitleLoading, setPrimaryTitleLoading] = React.useState(false);
- const [primaryTitleRecords, setPrimaryTitleRecords] = React.useState([]);
+ const [Comments, setComments] = React.useState(initialValues.Comments);
+ const [CommentsLoading, setCommentsLoading] = React.useState(false);
+ const [CommentsRecords, setCommentsRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
- setName(initialValues.name);
- setPrimaryAuthor(initialValues.primaryAuthor);
- setCurrentPrimaryAuthorValue(undefined);
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
- setPrimaryTitle(initialValues.primaryTitle);
- setCurrentPrimaryTitleValue(undefined);
- setCurrentPrimaryTitleDisplayValue(\\"\\");
+ const cleanValues = postRecord
+ ? { ...initialValues, ...postRecord, Comments: linkedComments }
+ : initialValues;
+ setTitle(cleanValues.title);
+ setBody(cleanValues.body);
+ setPublishDate(cleanValues.publishDate);
+ setComments(cleanValues.Comments ?? []);
+ setCurrentCommentsValue(undefined);
+ setCurrentCommentsDisplayValue(\\"\\");
setErrors({});
};
- const [
- currentPrimaryAuthorDisplayValue,
- setCurrentPrimaryAuthorDisplayValue,
- ] = React.useState(\\"\\");
- const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
- React.useState(undefined);
- const primaryAuthorRef = React.createRef();
- const [currentPrimaryTitleDisplayValue, setCurrentPrimaryTitleDisplayValue] =
+ const [postRecord, setPostRecord] = React.useState(postModelProp);
+ const [linkedComments, setLinkedComments] = React.useState([]);
+ const canUnlinkComments = false;
+ React.useEffect(() => {
+ const queryData = async () => {
+ const record = idProp
+ ? (
+ await API.graphql({
+ query: getPost,
+ variables: {
+ input: {
+ id: idProp,
+ },
+ },
+ })
+ ).data.getPost
+ : postModelProp;
+ setPostRecord(record);
+ const linkedComments = record
+ ? (
+ await API.graphql({
+ query: commentsByPostID,
+ variables: {
+ input: {
+ postID: record.id,
+ },
+ },
+ })
+ ).data.commentsByPostID.items
+ : [];
+ setLinkedComments(linkedComments);
+ };
+ queryData();
+ }, [idProp, postModelProp]);
+ React.useEffect(resetStateValues, [postRecord, linkedComments]);
+ const [currentCommentsDisplayValue, setCurrentCommentsDisplayValue] =
React.useState(\\"\\");
- const [currentPrimaryTitleValue, setCurrentPrimaryTitleValue] =
+ const [currentCommentsValue, setCurrentCommentsValue] =
React.useState(undefined);
- const primaryTitleRef = React.createRef();
+ const CommentsRef = React.createRef();
const getIDValue = {
- primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
- primaryTitle: (r) => JSON.stringify({ id: r?.id }),
+ Comments: (r) => JSON.stringify({ id: r?.id }),
};
- const primaryAuthorIdSet = new Set(
- Array.isArray(primaryAuthor)
- ? primaryAuthor.map((r) => getIDValue.primaryAuthor?.(r))
- : getIDValue.primaryAuthor?.(primaryAuthor)
- );
- const primaryTitleIdSet = new Set(
- Array.isArray(primaryTitle)
- ? primaryTitle.map((r) => getIDValue.primaryTitle?.(r))
- : getIDValue.primaryTitle?.(primaryTitle)
+ const CommentsIdSet = new Set(
+ Array.isArray(Comments)
+ ? Comments.map((r) => getIDValue.Comments?.(r))
+ : getIDValue.Comments?.(Comments)
);
const getDisplayValue = {
- primaryAuthor: (r) => r?.name,
- primaryTitle: (r) => r?.name,
+ Comments: (r) => \`\${r?.body ? r?.body + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
- name: [],
- primaryAuthor: [],
- primaryTitle: [],
- };
- const runValidationTasks = async (
- fieldName,
- currentValue,
- getDisplayValue
- ) => {
- const value =
- currentValue && getDisplayValue
- ? getDisplayValue(currentValue)
- : currentValue;
- let validationResponse = validateField(value, validations[fieldName]);
- const customValidator = fetchByPath(onValidate, fieldName);
- if (customValidator) {
- validationResponse = await customValidator(value, validationResponse);
- }
- setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
- return validationResponse;
- };
- const fetchPrimaryAuthorRecords = async (value) => {
- setPrimaryAuthorLoading(true);
- const newOptions = [];
- let newNext = \\"\\";
- while (newOptions.length < autocompleteLength && newNext != null) {
- const variables = {
- limit: autocompleteLength * 5,
- filter: { or: [{ name: { contains: value } }] },
- };
- if (newNext) {
- variables[\\"nextToken\\"] = newNext;
- }
- const result = (
- await API.graphql({
- query: listAuthors,
- variables,
- })
- ).data.listPrimaryAuthors.item;
- var loaded = result.filter(
- (item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
- );
- newOptions.push(...loaded);
- newNext = result.nextToken;
+ title: [],
+ body: [],
+ publishDate: [],
+ Comments: [],
+ };
+ const runValidationTasks = async (
+ fieldName,
+ currentValue,
+ getDisplayValue
+ ) => {
+ const value =
+ currentValue && getDisplayValue
+ ? getDisplayValue(currentValue)
+ : currentValue;
+ let validationResponse = validateField(value, validations[fieldName]);
+ const customValidator = fetchByPath(onValidate, fieldName);
+ if (customValidator) {
+ validationResponse = await customValidator(value, validationResponse);
}
- setPrimaryAuthorRecords(newOptions.slice(0, autocompleteLength));
- setPrimaryAuthorLoading(false);
+ setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
+ return validationResponse;
};
- const fetchPrimaryTitleRecords = async (value) => {
- setPrimaryTitleLoading(true);
+ const convertToLocal = (date) => {
+ const df = new Intl.DateTimeFormat(\\"default\\", {
+ year: \\"numeric\\",
+ month: \\"2-digit\\",
+ day: \\"2-digit\\",
+ hour: \\"2-digit\\",
+ minute: \\"2-digit\\",
+ calendar: \\"iso8601\\",
+ numberingSystem: \\"latn\\",
+ hourCycle: \\"h23\\",
+ });
+ const parts = df.formatToParts(date).reduce((acc, part) => {
+ acc[part.type] = part.value;
+ return acc;
+ }, {});
+ return \`\${parts.year}-\${parts.month}-\${parts.day}T\${parts.hour}:\${parts.minute}\`;
+ };
+ const fetchCommentsRecords = async (value) => {
+ setCommentsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
- filter: { or: [{ name: { contains: value } }] },
+ filter: {
+ or: [{ body: { contains: value } }, { id: { contains: value } }],
+ },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
- query: listTitles,
+ query: listComments,
variables,
})
- ).data.listPrimaryTitles.item;
+ ).data.listComments.item;
var loaded = result.filter(
- (item) => !primaryTitleIdSet.has(getIDValue.primaryTitle?.(item))
+ (item) => !CommentsIdSet.has(getIDValue.Comments?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
- setPrimaryTitleRecords(newOptions.slice(0, autocompleteLength));
- setPrimaryTitleLoading(false);
+ setCommentsRecords(newOptions.slice(0, autocompleteLength));
+ setCommentsLoading(false);
};
return (
{
event.preventDefault();
let modelFields = {
- name,
- primaryAuthor,
- primaryTitle,
+ title,
+ body,
+ publishDate,
+ Comments,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
@@ -3379,303 +4601,328 @@ export default function BookCreateForm(props) {
modelFields[key] = undefined;
}
});
- await API.graphql({
- query: createBook,
- variables: {
- input: {
- ...modelFields,
- },
- },
+ const promises = [];
+ const commentsToLink = [];
+ const commentsToUnLink = [];
+ const commentsSet = new Set();
+ const linkedCommentsSet = new Set();
+ Comments.forEach((r) => commentsSet.add(getIDValue.Comments?.(r)));
+ linkedComments.forEach((r) =>
+ linkedCommentsSet.add(getIDValue.Comments?.(r))
+ );
+ linkedComments.forEach((r) => {
+ if (!commentsSet.has(getIDValue.Comments?.(r))) {
+ commentsToUnLink.push(r);
+ }
+ });
+ Comments.forEach((r) => {
+ if (!linkedCommentsSet.has(getIDValue.Comments?.(r))) {
+ commentsToLink.push(r);
+ }
+ });
+ commentsToUnLink.forEach((original) => {
+ if (!canUnlinkComments) {
+ throw Error(
+ \`Comment \${original.id} cannot be unlinked from Post because postID is a required field.\`
+ );
+ }
+ promises.push(
+ API.graphql({
+ query: deleteComment,
+ variables: {
+ input: {
+ id: original.id,
+ },
+ },
+ })
+ );
+ });
+ commentsToLink.forEach((original) => {
+ promises.push(
+ API.graphql({
+ query: updateComment,
+ variables: {
+ input: {
+ id: original.id,
+ postID: postRecord.id,
+ },
+ },
+ })
+ );
});
+ const modelFieldsToSave = {
+ title: modelFields.title,
+ body: modelFields.body,
+ publishDate: modelFields.publishDate,
+ };
+ promises.push(
+ API.graphql({
+ query: updatePost,
+ variables: {
+ input: {
+ id: postRecord.id,
+ ...modelFieldsToSave,
+ },
+ },
+ })
+ );
+ await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
- if (clearOnSuccess) {
- resetStateValues();
- }
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
- {...getOverrideProps(overrides, \\"BookCreateForm\\")}
+ {...getOverrideProps(overrides, \\"PostUpdateForm\\")}
{...rest}
>
-
-
-
-
-
-
-
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- name: value,
- primaryAuthor,
- primaryTitle,
+ title: value,
+ body,
+ publishDate,
+ Comments,
};
const result = onChange(modelFields);
- value = result?.name ?? value;
+ value = result?.title ?? value;
}
- if (errors.name?.hasError) {
- runValidationTasks(\\"name\\", value);
+ if (errors.title?.hasError) {
+ runValidationTasks(\\"title\\", value);
}
- setName(value);
+ setTitle(value);
}}
- onBlur={() => runValidationTasks(\\"name\\", name)}
- errorMessage={errors.name?.errorMessage}
- hasError={errors.name?.hasError}
- {...getOverrideProps(overrides, \\"name\\")}
+ onBlur={() => runValidationTasks(\\"title\\", title)}
+ errorMessage={errors.title?.errorMessage}
+ hasError={errors.title?.hasError}
+ {...getOverrideProps(overrides, \\"title\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ title,
+ body: value,
+ publishDate,
+ Comments,
+ };
+ const result = onChange(modelFields);
+ value = result?.body ?? value;
+ }
+ if (errors.body?.hasError) {
+ runValidationTasks(\\"body\\", value);
+ }
+ setBody(value);
+ }}
+ onBlur={() => runValidationTasks(\\"body\\", body)}
+ errorMessage={errors.body?.errorMessage}
+ hasError={errors.body?.hasError}
+ {...getOverrideProps(overrides, \\"body\\")}
+ >
+ {
+ let value =
+ e.target.value === \\"\\" ? \\"\\" : new Date(e.target.value).toISOString();
+ if (onChange) {
+ const modelFields = {
+ title,
+ body,
+ publishDate: value,
+ Comments,
+ };
+ const result = onChange(modelFields);
+ value = result?.publishDate ?? value;
+ }
+ if (errors.publishDate?.hasError) {
+ runValidationTasks(\\"publishDate\\", value);
+ }
+ setPublishDate(value);
+ }}
+ onBlur={() => runValidationTasks(\\"publishDate\\", publishDate)}
+ errorMessage={errors.publishDate?.errorMessage}
+ hasError={errors.publishDate?.hasError}
+ {...getOverrideProps(overrides, \\"publishDate\\")}
>
{
- let value = items[0];
+ let values = items;
if (onChange) {
const modelFields = {
- name,
- primaryAuthor: value,
- primaryTitle,
+ title,
+ body,
+ publishDate,
+ Comments: values,
};
const result = onChange(modelFields);
- value = result?.primaryAuthor ?? value;
+ values = result?.Comments ?? values;
}
- setPrimaryAuthor(value);
- setCurrentPrimaryAuthorValue(undefined);
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setComments(values);
+ setCurrentCommentsValue(undefined);
+ setCurrentCommentsDisplayValue(\\"\\");
}}
- currentFieldValue={currentPrimaryAuthorValue}
- label={\\"Primary author\\"}
- items={primaryAuthor ? [primaryAuthor] : []}
- hasError={errors?.primaryAuthor?.hasError}
- errorMessage={errors?.primaryAuthor?.errorMessage}
- getBadgeText={getDisplayValue.primaryAuthor}
+ currentFieldValue={currentCommentsValue}
+ label={\\"Comments\\"}
+ items={Comments}
+ hasError={errors?.Comments?.hasError}
+ errorMessage={errors?.Comments?.errorMessage}
+ getBadgeText={getDisplayValue.Comments}
setFieldValue={(model) => {
- setCurrentPrimaryAuthorDisplayValue(
- model ? getDisplayValue.primaryAuthor(model) : \\"\\"
+ setCurrentCommentsDisplayValue(
+ model ? getDisplayValue.Comments(model) : \\"\\"
);
- setCurrentPrimaryAuthorValue(model);
+ setCurrentCommentsValue(model);
}}
- inputFieldRef={primaryAuthorRef}
+ inputFieldRef={CommentsRef}
defaultFieldValue={\\"\\"}
>
!primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
- )
- .map((r) => ({
- id: getIDValue.primaryAuthor?.(r),
- label: getDisplayValue.primaryAuthor?.(r),
- }))}
- isLoading={primaryAuthorLoading}
+ placeholder=\\"Search Comment\\"
+ value={currentCommentsDisplayValue}
+ options={commentsRecords.map((r) => ({
+ id: getIDValue.Comments?.(r),
+ label: getDisplayValue.Comments?.(r),
+ }))}
+ isLoading={CommentsLoading}
onSelect={({ id, label }) => {
- setCurrentPrimaryAuthorValue(
- authorRecords.find((r) =>
+ setCurrentCommentsValue(
+ commentRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
- setCurrentPrimaryAuthorDisplayValue(label);
- runValidationTasks(\\"primaryAuthor\\", label);
+ setCurrentCommentsDisplayValue(label);
+ runValidationTasks(\\"Comments\\", label);
}}
onClear={() => {
- setCurrentPrimaryAuthorDisplayValue(\\"\\");
+ setCurrentCommentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
- fetchPrimaryAuthorRecords(value);
- if (errors.primaryAuthor?.hasError) {
- runValidationTasks(\\"primaryAuthor\\", value);
+ fetchCommentsRecords(value);
+ if (errors.Comments?.hasError) {
+ runValidationTasks(\\"Comments\\", value);
}
- setCurrentPrimaryAuthorDisplayValue(value);
- setCurrentPrimaryAuthorValue(undefined);
+ setCurrentCommentsDisplayValue(value);
+ setCurrentCommentsValue(undefined);
}}
onBlur={() =>
- runValidationTasks(
- \\"primaryAuthor\\",
- currentPrimaryAuthorDisplayValue
- )
+ runValidationTasks(\\"Comments\\", currentCommentsDisplayValue)
}
- errorMessage={errors.primaryAuthor?.errorMessage}
- hasError={errors.primaryAuthor?.hasError}
- ref={primaryAuthorRef}
+ errorMessage={errors.Comments?.errorMessage}
+ hasError={errors.Comments?.hasError}
+ ref={CommentsRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"primaryAuthor\\")}
+ {...getOverrideProps(overrides, \\"Comments\\")}
>
- {
- let value = items[0];
- if (onChange) {
- const modelFields = {
- name,
- primaryAuthor,
- primaryTitle: value,
- };
- const result = onChange(modelFields);
- value = result?.primaryTitle ?? value;
- }
- setPrimaryTitle(value);
- setCurrentPrimaryTitleValue(undefined);
- setCurrentPrimaryTitleDisplayValue(\\"\\");
- }}
- currentFieldValue={currentPrimaryTitleValue}
- label={\\"Primary title\\"}
- items={primaryTitle ? [primaryTitle] : []}
- hasError={errors?.primaryTitle?.hasError}
- errorMessage={errors?.primaryTitle?.errorMessage}
- getBadgeText={getDisplayValue.primaryTitle}
- setFieldValue={(model) => {
- setCurrentPrimaryTitleDisplayValue(
- model ? getDisplayValue.primaryTitle(model) : \\"\\"
- );
- setCurrentPrimaryTitleValue(model);
- }}
- inputFieldRef={primaryTitleRef}
- defaultFieldValue={\\"\\"}
+
- !primaryTitleIdSet.has(getIDValue.primaryTitle?.(r)))
- .map((r) => ({
- id: getIDValue.primaryTitle?.(r),
- label: getDisplayValue.primaryTitle?.(r),
- }))}
- isLoading={primaryTitleLoading}
- onSelect={({ id, label }) => {
- setCurrentPrimaryTitleValue(
- titleRecords.find((r) =>
- Object.entries(JSON.parse(id)).every(
- ([key, value]) => r[key] === value
- )
- )
- );
- setCurrentPrimaryTitleDisplayValue(label);
- runValidationTasks(\\"primaryTitle\\", label);
- }}
- onClear={() => {
- setCurrentPrimaryTitleDisplayValue(\\"\\");
+
+
+
-
+ {...getOverrideProps(overrides, \\"SubmitButton\\")}
+ >
+
+
);
}
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a create form with multiple hasOne relationships 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a relationship update form with autocomplete 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Author, Title } from \\"../API\\";
+import { Comment, Post } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type BookCreateFormInputValues = {
- name?: string;
- primaryAuthor?: Author;
- primaryTitle?: Title;
+export declare type PostUpdateFormInputValues = {
+ title?: string;
+ body?: string;
+ publishDate?: string;
+ Comments?: Comment[];
};
-export declare type BookCreateFormValidationValues = {
- name?: ValidationFunction;
- primaryAuthor?: ValidationFunction;
- primaryTitle?: ValidationFunction;
+export declare type PostUpdateFormValidationValues = {
+ title?: ValidationFunction;
+ body?: ValidationFunction;
+ publishDate?: ValidationFunction;
+ Comments?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type BookCreateFormOverridesProps = {
- BookCreateFormGrid?: PrimitiveOverrideProps;
- name?: PrimitiveOverrideProps;
- primaryAuthor?: PrimitiveOverrideProps;
- primaryTitle?: PrimitiveOverrideProps;
+export declare type PostUpdateFormOverridesProps = {
+ PostUpdateFormGrid?: PrimitiveOverrideProps;
+ title?: PrimitiveOverrideProps;
+ body?: PrimitiveOverrideProps;
+ publishDate?: PrimitiveOverrideProps;
+ Comments?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type BookCreateFormProps = React.PropsWithChildren<{
- overrides?: BookCreateFormOverridesProps | undefined | null;
+export declare type PostUpdateFormProps = React.PropsWithChildren<{
+ overrides?: PostUpdateFormOverridesProps | undefined | null;
} & {
- clearOnSuccess?: boolean;
- onSubmit?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
- onSuccess?: (fields: BookCreateFormInputValues) => void;
- onError?: (fields: BookCreateFormInputValues, errorMessage: string) => void;
- onCancel?: () => void;
- onChange?: (fields: BookCreateFormInputValues) => BookCreateFormInputValues;
- onValidate?: BookCreateFormValidationValues;
+ id?: string;
+ post?: Post;
+ onSubmit?: (fields: PostUpdateFormInputValues) => PostUpdateFormInputValues;
+ onSuccess?: (fields: PostUpdateFormInputValues) => void;
+ onError?: (fields: PostUpdateFormInputValues, errorMessage: string) => void;
+ onChange?: (fields: PostUpdateFormInputValues) => PostUpdateFormInputValues;
+ onValidate?: PostUpdateFormValidationValues;
} & React.CSSProperties>;
-export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
+export default function PostUpdateForm(props: PostUpdateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a relationship update form with autocomplete 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate a update form without relationships 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
- Autocomplete,
Badge,
Button,
Divider,
@@ -3684,14 +4931,15 @@ import {
Icon,
ScrollView,
Text,
+ TextAreaField,
TextField,
useTheme,
} from \\"@aws-amplify/ui-react\\";
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { commentsByPostID, getPost, listComments } from \\"../graphql/queries\\";
-import { deleteComment, updateComment, updatePost } from \\"../graphql/mutations\\";
+import { getPost } from \\"../graphql/queries\\";
+import { updatePost } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
onChange,
@@ -3850,49 +5098,74 @@ function ArrayField({
);
}
-export default function PostUpdateForm(props) {
+export default function MyPostForm(props) {
const {
id: idProp,
post: postModelProp,
onSuccess,
onError,
onSubmit,
+ onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
- title: \\"\\",
- body: \\"\\",
- publishDate: \\"\\",
- Comments: [],
+ TextAreaFieldbbd63464: \\"\\",
+ caption: \\"\\",
+ username: \\"\\",
+ profile_url: \\"\\",
+ post_url: \\"\\",
+ metadata: \\"\\",
+ nonModelField: \\"\\",
+ nonModelFieldArray: [],
};
- const [title, setTitle] = React.useState(initialValues.title);
- const [body, setBody] = React.useState(initialValues.body);
- const [publishDate, setPublishDate] = React.useState(
- initialValues.publishDate
+ const [TextAreaFieldbbd63464, setTextAreaFieldbbd63464] = React.useState(
+ initialValues.TextAreaFieldbbd63464
+ );
+ const [caption, setCaption] = React.useState(initialValues.caption);
+ const [username, setUsername] = React.useState(initialValues.username);
+ const [profile_url, setProfile_url] = React.useState(
+ initialValues.profile_url
+ );
+ const [post_url, setPost_url] = React.useState(initialValues.post_url);
+ const [metadata, setMetadata] = React.useState(initialValues.metadata);
+ const [nonModelField, setNonModelField] = React.useState(
+ initialValues.nonModelField
+ );
+ const [nonModelFieldArray, setNonModelFieldArray] = React.useState(
+ initialValues.nonModelFieldArray
);
- const [Comments, setComments] = React.useState(initialValues.Comments);
- const [CommentsLoading, setCommentsLoading] = React.useState(false);
- const [CommentsRecords, setCommentsRecords] = React.useState([]);
- const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = postRecord
- ? { ...initialValues, ...postRecord, Comments: linkedComments }
+ ? { ...initialValues, ...postRecord }
: initialValues;
- setTitle(cleanValues.title);
- setBody(cleanValues.body);
- setPublishDate(cleanValues.publishDate);
- setComments(cleanValues.Comments ?? []);
- setCurrentCommentsValue(undefined);
- setCurrentCommentsDisplayValue(\\"\\");
+ setTextAreaFieldbbd63464(cleanValues.TextAreaFieldbbd63464);
+ setCaption(cleanValues.caption);
+ setUsername(cleanValues.username);
+ setProfile_url(cleanValues.profile_url);
+ setPost_url(cleanValues.post_url);
+ setMetadata(
+ typeof cleanValues.metadata === \\"string\\"
+ ? cleanValues.metadata
+ : JSON.stringify(cleanValues.metadata)
+ );
+ setNonModelField(
+ typeof cleanValues.nonModelField === \\"string\\"
+ ? cleanValues.nonModelField
+ : JSON.stringify(cleanValues.nonModelField)
+ );
+ setNonModelFieldArray(
+ cleanValues.nonModelFieldArray?.map((item) =>
+ typeof item === \\"string\\" ? item : JSON.stringify(item)
+ ) ?? []
+ );
+ setCurrentNonModelFieldArrayValue(\\"\\");
setErrors({});
};
const [postRecord, setPostRecord] = React.useState(postModelProp);
- const [linkedComments, setLinkedComments] = React.useState([]);
- const canUnlinkComments = false;
React.useEffect(() => {
const queryData = async () => {
const record = idProp
@@ -3908,44 +5181,22 @@ export default function PostUpdateForm(props) {
).data.getPost
: postModelProp;
setPostRecord(record);
- const linkedComments = record
- ? (
- await API.graphql({
- query: commentsByPostID,
- variables: {
- input: {
- postID: record.id,
- },
- },
- })
- ).data.commentsByPostID.items
- : [];
- setLinkedComments(linkedComments);
};
queryData();
}, [idProp, postModelProp]);
- React.useEffect(resetStateValues, [postRecord, linkedComments]);
- const [currentCommentsDisplayValue, setCurrentCommentsDisplayValue] =
+ React.useEffect(resetStateValues, [postRecord]);
+ const [currentNonModelFieldArrayValue, setCurrentNonModelFieldArrayValue] =
React.useState(\\"\\");
- const [currentCommentsValue, setCurrentCommentsValue] =
- React.useState(undefined);
- const CommentsRef = React.createRef();
- const getIDValue = {
- Comments: (r) => JSON.stringify({ id: r?.id }),
- };
- const CommentsIdSet = new Set(
- Array.isArray(Comments)
- ? Comments.map((r) => getIDValue.Comments?.(r))
- : getIDValue.Comments?.(Comments)
- );
- const getDisplayValue = {
- Comments: (r) => \`\${r?.body ? r?.body + \\" - \\" : \\"\\"}\${r?.id}\`,
- };
+ const nonModelFieldArrayRef = React.createRef();
const validations = {
- title: [],
- body: [],
- publishDate: [],
- Comments: [],
+ TextAreaFieldbbd63464: [],
+ caption: [],
+ username: [],
+ profile_url: [{ type: \\"URL\\" }],
+ post_url: [{ type: \\"URL\\" }],
+ metadata: [{ type: \\"JSON\\" }],
+ nonModelField: [{ type: \\"JSON\\" }],
+ nonModelFieldArray: [{ type: \\"JSON\\" }],
};
const runValidationTasks = async (
fieldName,
@@ -3964,52 +5215,6 @@ export default function PostUpdateForm(props) {
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
- const convertToLocal = (date) => {
- const df = new Intl.DateTimeFormat(\\"default\\", {
- year: \\"numeric\\",
- month: \\"2-digit\\",
- day: \\"2-digit\\",
- hour: \\"2-digit\\",
- minute: \\"2-digit\\",
- calendar: \\"iso8601\\",
- numberingSystem: \\"latn\\",
- hourCycle: \\"h23\\",
- });
- const parts = df.formatToParts(date).reduce((acc, part) => {
- acc[part.type] = part.value;
- return acc;
- }, {});
- return \`\${parts.year}-\${parts.month}-\${parts.day}T\${parts.hour}:\${parts.minute}\`;
- };
- const fetchCommentsRecords = async (value) => {
- setCommentsLoading(true);
- const newOptions = [];
- let newNext = \\"\\";
- while (newOptions.length < autocompleteLength && newNext != null) {
- const variables = {
- limit: autocompleteLength * 5,
- filter: {
- or: [{ body: { contains: value } }, { id: { contains: value } }],
- },
- };
- if (newNext) {
- variables[\\"nextToken\\"] = newNext;
- }
- const result = (
- await API.graphql({
- query: listComments,
- variables,
- })
- ).data.listComments.item;
- var loaded = result.filter(
- (item) => !CommentsIdSet.has(getIDValue.Comments?.(item))
- );
- newOptions.push(...loaded);
- newNext = result.nextToken;
- }
- setCommentsRecords(newOptions.slice(0, autocompleteLength));
- setCommentsLoading(false);
- };
return (
{
event.preventDefault();
let modelFields = {
- title,
- body,
- publishDate,
- Comments,
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
};
const validationResponses = await Promise.all(
Object.keys(validations).reduce((promises, fieldName) => {
if (Array.isArray(modelFields[fieldName])) {
promises.push(
...modelFields[fieldName].map((item) =>
- runValidationTasks(
- fieldName,
- item,
- getDisplayValue[fieldName]
- )
+ runValidationTasks(fieldName, item)
)
);
return promises;
}
promises.push(
- runValidationTasks(
- fieldName,
- modelFields[fieldName],
- getDisplayValue[fieldName]
- )
+ runValidationTasks(fieldName, modelFields[fieldName])
);
return promises;
}, [])
@@ -4060,72 +5261,28 @@ export default function PostUpdateForm(props) {
modelFields[key] = undefined;
}
});
- const promises = [];
- const commentsToLink = [];
- const commentsToUnLink = [];
- const commentsSet = new Set();
- const linkedCommentsSet = new Set();
- Comments.forEach((r) => commentsSet.add(getIDValue.Comments?.(r)));
- linkedComments.forEach((r) =>
- linkedCommentsSet.add(getIDValue.Comments?.(r))
- );
- linkedComments.forEach((r) => {
- if (!commentsSet.has(getIDValue.Comments?.(r))) {
- commentsToUnLink.push(r);
- }
- });
- Comments.forEach((r) => {
- if (!linkedCommentsSet.has(getIDValue.Comments?.(r))) {
- commentsToLink.push(r);
- }
- });
- commentsToUnLink.forEach((original) => {
- if (!canUnlinkComments) {
- throw Error(
- \`Comment \${original.id} cannot be unlinked from Post because postID is a required field.\`
- );
- }
- promises.push(
- API.graphql({
- query: deleteComment,
- variables: {
- input: {
- id: original.id,
- },
- },
- })
- );
- });
- commentsToLink.forEach((original) => {
- promises.push(
- API.graphql({
- query: updateComment,
- variables: {
- input: {
- id: original.id,
- postID: postRecord.id,
- },
- },
- })
- );
- });
const modelFieldsToSave = {
- title: modelFields.title,
- body: modelFields.body,
- publishDate: modelFields.publishDate,
+ caption: modelFields.caption,
+ username: modelFields.username,
+ profile_url: modelFields.profile_url,
+ post_url: modelFields.post_url,
+ metadata: modelFields.metadata,
+ nonModelFieldArray: modelFields.nonModelFieldArray.map((s) =>
+ JSON.parse(s)
+ ),
+ nonModelField: modelFields.nonModelField
+ ? JSON.parse(modelFields.nonModelField)
+ : modelFields.nonModelField,
};
- promises.push(
- API.graphql({
- query: updatePost,
- variables: {
- input: {
- id: postRecord.id,
- ...modelFieldsToSave,
- },
+ await API.graphql({
+ query: updatePost,
+ variables: {
+ input: {
+ id: postRecord.id,
+ ...modelFieldsToSave,
},
- })
- );
- await Promise.all(promises);
+ },
+ });
if (onSuccess) {
onSuccess(modelFields);
}
@@ -4135,167 +5292,317 @@ export default function PostUpdateForm(props) {
}
}
}}
- {...getOverrideProps(overrides, \\"PostUpdateForm\\")}
+ {...getOverrideProps(overrides, \\"MyPostForm\\")}
{...rest}
>
+
+
+
+
+
+
+
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ TextAreaFieldbbd63464: value,
+ caption,
+ username,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.TextAreaFieldbbd63464 ?? value;
+ }
+ if (errors.TextAreaFieldbbd63464?.hasError) {
+ runValidationTasks(\\"TextAreaFieldbbd63464\\", value);
+ }
+ setTextAreaFieldbbd63464(value);
+ }}
+ onBlur={() =>
+ runValidationTasks(\\"TextAreaFieldbbd63464\\", TextAreaFieldbbd63464)
+ }
+ errorMessage={errors.TextAreaFieldbbd63464?.errorMessage}
+ hasError={errors.TextAreaFieldbbd63464?.hasError}
+ {...getOverrideProps(overrides, \\"TextAreaFieldbbd63464\\")}
+ >
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- title: value,
- body,
- publishDate,
- Comments,
+ TextAreaFieldbbd63464,
+ caption: value,
+ username,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
};
const result = onChange(modelFields);
- value = result?.title ?? value;
+ value = result?.caption ?? value;
}
- if (errors.title?.hasError) {
- runValidationTasks(\\"title\\", value);
+ if (errors.caption?.hasError) {
+ runValidationTasks(\\"caption\\", value);
}
- setTitle(value);
+ setCaption(value);
}}
- onBlur={() => runValidationTasks(\\"title\\", title)}
- errorMessage={errors.title?.errorMessage}
- hasError={errors.title?.hasError}
- {...getOverrideProps(overrides, \\"title\\")}
+ onBlur={() => runValidationTasks(\\"caption\\", caption)}
+ errorMessage={errors.caption?.errorMessage}
+ hasError={errors.caption?.hasError}
+ {...getOverrideProps(overrides, \\"caption\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
- title,
- body: value,
- publishDate,
- Comments,
+ TextAreaFieldbbd63464,
+ caption,
+ username: value,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
};
const result = onChange(modelFields);
- value = result?.body ?? value;
+ value = result?.username ?? value;
}
- if (errors.body?.hasError) {
- runValidationTasks(\\"body\\", value);
+ if (errors.username?.hasError) {
+ runValidationTasks(\\"username\\", value);
}
- setBody(value);
+ setUsername(value);
}}
- onBlur={() => runValidationTasks(\\"body\\", body)}
- errorMessage={errors.body?.errorMessage}
- hasError={errors.body?.hasError}
- {...getOverrideProps(overrides, \\"body\\")}
+ onBlur={() => runValidationTasks(\\"username\\", username)}
+ errorMessage={errors.username?.errorMessage}
+ hasError={errors.username?.hasError}
+ {...getOverrideProps(overrides, \\"username\\")}
>
{
- let value =
- e.target.value === \\"\\" ? \\"\\" : new Date(e.target.value).toISOString();
+ let { value } = e.target;
if (onChange) {
const modelFields = {
- title,
- body,
- publishDate: value,
- Comments,
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url: value,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.profile_url ?? value;
+ }
+ if (errors.profile_url?.hasError) {
+ runValidationTasks(\\"profile_url\\", value);
+ }
+ setProfile_url(value);
+ }}
+ onBlur={() => runValidationTasks(\\"profile_url\\", profile_url)}
+ errorMessage={errors.profile_url?.errorMessage}
+ hasError={errors.profile_url?.hasError}
+ {...getOverrideProps(overrides, \\"profile_url\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url,
+ post_url: value,
+ metadata,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.post_url ?? value;
+ }
+ if (errors.post_url?.hasError) {
+ runValidationTasks(\\"post_url\\", value);
+ }
+ setPost_url(value);
+ }}
+ onBlur={() => runValidationTasks(\\"post_url\\", post_url)}
+ errorMessage={errors.post_url?.errorMessage}
+ hasError={errors.post_url?.hasError}
+ {...getOverrideProps(overrides, \\"post_url\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url,
+ post_url,
+ metadata: value,
+ nonModelField,
+ nonModelFieldArray,
+ };
+ const result = onChange(modelFields);
+ value = result?.metadata ?? value;
+ }
+ if (errors.metadata?.hasError) {
+ runValidationTasks(\\"metadata\\", value);
+ }
+ setMetadata(value);
+ }}
+ onBlur={() => runValidationTasks(\\"metadata\\", metadata)}
+ errorMessage={errors.metadata?.errorMessage}
+ hasError={errors.metadata?.hasError}
+ {...getOverrideProps(overrides, \\"metadata\\")}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField: value,
+ nonModelFieldArray,
};
const result = onChange(modelFields);
- value = result?.publishDate ?? value;
+ value = result?.nonModelField ?? value;
}
- if (errors.publishDate?.hasError) {
- runValidationTasks(\\"publishDate\\", value);
+ if (errors.nonModelField?.hasError) {
+ runValidationTasks(\\"nonModelField\\", value);
}
- setPublishDate(value);
+ setNonModelField(value);
}}
- onBlur={() => runValidationTasks(\\"publishDate\\", publishDate)}
- errorMessage={errors.publishDate?.errorMessage}
- hasError={errors.publishDate?.hasError}
- {...getOverrideProps(overrides, \\"publishDate\\")}
- >
+ onBlur={() => runValidationTasks(\\"nonModelField\\", nonModelField)}
+ errorMessage={errors.nonModelField?.errorMessage}
+ hasError={errors.nonModelField?.hasError}
+ {...getOverrideProps(overrides, \\"nonModelField\\")}
+ >
{
let values = items;
if (onChange) {
const modelFields = {
- title,
- body,
- publishDate,
- Comments: values,
+ TextAreaFieldbbd63464,
+ caption,
+ username,
+ profile_url,
+ post_url,
+ metadata,
+ nonModelField,
+ nonModelFieldArray: values,
};
const result = onChange(modelFields);
- values = result?.Comments ?? values;
+ values = result?.nonModelFieldArray ?? values;
}
- setComments(values);
- setCurrentCommentsValue(undefined);
- setCurrentCommentsDisplayValue(\\"\\");
- }}
- currentFieldValue={currentCommentsValue}
- label={\\"Comments\\"}
- items={Comments}
- hasError={errors?.Comments?.hasError}
- errorMessage={errors?.Comments?.errorMessage}
- getBadgeText={getDisplayValue.Comments}
- setFieldValue={(model) => {
- setCurrentCommentsDisplayValue(
- model ? getDisplayValue.Comments(model) : \\"\\"
- );
- setCurrentCommentsValue(model);
+ setNonModelFieldArray(values);
+ setCurrentNonModelFieldArrayValue(\\"\\");
}}
- inputFieldRef={CommentsRef}
+ currentFieldValue={currentNonModelFieldArrayValue}
+ label={\\"Non model field array\\"}
+ items={nonModelFieldArray}
+ hasError={errors?.nonModelFieldArray?.hasError}
+ errorMessage={errors?.nonModelFieldArray?.errorMessage}
+ setFieldValue={setCurrentNonModelFieldArrayValue}
+ inputFieldRef={nonModelFieldArrayRef}
defaultFieldValue={\\"\\"}
>
- ({
- id: getIDValue.Comments?.(r),
- label: getDisplayValue.Comments?.(r),
- }))}
- isLoading={CommentsLoading}
- onSelect={({ id, label }) => {
- setCurrentCommentsValue(
- commentRecords.find((r) =>
- Object.entries(JSON.parse(id)).every(
- ([key, value]) => r[key] === value
- )
- )
- );
- setCurrentCommentsDisplayValue(label);
- runValidationTasks(\\"Comments\\", label);
- }}
- onClear={() => {
- setCurrentCommentsDisplayValue(\\"\\");
- }}
+ value={currentNonModelFieldArrayValue}
onChange={(e) => {
let { value } = e.target;
- fetchCommentsRecords(value);
- if (errors.Comments?.hasError) {
- runValidationTasks(\\"Comments\\", value);
+ if (errors.nonModelFieldArray?.hasError) {
+ runValidationTasks(\\"nonModelFieldArray\\", value);
}
- setCurrentCommentsDisplayValue(value);
- setCurrentCommentsValue(undefined);
+ setCurrentNonModelFieldArrayValue(value);
}}
onBlur={() =>
- runValidationTasks(\\"Comments\\", currentCommentsDisplayValue)
+ runValidationTasks(
+ \\"nonModelFieldArray\\",
+ currentNonModelFieldArrayValue
+ )
}
- errorMessage={errors.Comments?.errorMessage}
- hasError={errors.Comments?.hasError}
- ref={CommentsRef}
+ errorMessage={errors.nonModelFieldArray?.errorMessage}
+ hasError={errors.nonModelFieldArray?.hasError}
+ ref={nonModelFieldArrayRef}
labelHidden={true}
- {...getOverrideProps(overrides, \\"Comments\\")}
- >
+ {...getOverrideProps(overrides, \\"nonModelFieldArray\\")}
+ >
+
- {
- onCancel && onCancel();
- }}
- {...getOverrideProps(overrides, \\"CancelButton\\")}
- >
e?.hasError)
}
{...getOverrideProps(overrides, \\"SubmitButton\\")}
@@ -5107,65 +6372,52 @@ export default function MyPostForm(props) {
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate a update form without relationships 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate an update form with hasMany relationship 2`] = `
"import * as React from \\"react\\";
-import { GridProps, TextAreaFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Post } from \\"../API\\";
+import { Comment, Post } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
-export declare type MyPostFormInputValues = {
- TextAreaFieldbbd63464?: string;
- caption?: string;
- username?: string;
- profile_url?: string;
- post_url?: string;
- metadata?: string;
- nonModelField?: string;
- nonModelFieldArray?: string[];
+export declare type CommentUpdateFormInputValues = {
+ content?: string;
+ postID?: string;
+ Post?: Post;
+ post?: string;
};
-export declare type MyPostFormValidationValues = {
- TextAreaFieldbbd63464?: ValidationFunction;
- caption?: ValidationFunction;
- username?: ValidationFunction;
- profile_url?: ValidationFunction;
- post_url?: ValidationFunction;
- metadata?: ValidationFunction;
- nonModelField?: ValidationFunction;
- nonModelFieldArray?: ValidationFunction;
+export declare type CommentUpdateFormValidationValues = {
+ content?: ValidationFunction;
+ postID?: ValidationFunction;
+ Post?: ValidationFunction;
+ post?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
-export declare type MyPostFormOverridesProps = {
- MyPostFormGrid?: PrimitiveOverrideProps;
- TextAreaFieldbbd63464?: PrimitiveOverrideProps;
- caption?: PrimitiveOverrideProps;
- username?: PrimitiveOverrideProps;
- profile_url?: PrimitiveOverrideProps;
- post_url?: PrimitiveOverrideProps;
- metadata?: PrimitiveOverrideProps;
- nonModelField?: PrimitiveOverrideProps;
- nonModelFieldArray?: PrimitiveOverrideProps;
+export declare type CommentUpdateFormOverridesProps = {
+ CommentUpdateFormGrid?: PrimitiveOverrideProps;
+ content?: PrimitiveOverrideProps;
+ postID?: PrimitiveOverrideProps;
+ Post?: PrimitiveOverrideProps;
+ post?: PrimitiveOverrideProps;
} & EscapeHatchProps;
-export declare type MyPostFormProps = React.PropsWithChildren<{
- overrides?: MyPostFormOverridesProps | undefined | null;
+export declare type CommentUpdateFormProps = React.PropsWithChildren<{
+ overrides?: CommentUpdateFormOverridesProps | undefined | null;
} & {
id?: string;
- post?: Post;
- onSubmit?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
- onSuccess?: (fields: MyPostFormInputValues) => void;
- onError?: (fields: MyPostFormInputValues, errorMessage: string) => void;
- onCancel?: () => void;
- onChange?: (fields: MyPostFormInputValues) => MyPostFormInputValues;
- onValidate?: MyPostFormValidationValues;
+ comment?: Comment;
+ onSubmit?: (fields: CommentUpdateFormInputValues) => CommentUpdateFormInputValues;
+ onSuccess?: (fields: CommentUpdateFormInputValues) => void;
+ onError?: (fields: CommentUpdateFormInputValues, errorMessage: string) => void;
+ onChange?: (fields: CommentUpdateFormInputValues) => CommentUpdateFormInputValues;
+ onValidate?: CommentUpdateFormValidationValues;
} & React.CSSProperties>;
-export default function MyPostForm(props: MyPostFormProps): React.ReactElement;
+export default function CommentUpdateForm(props: CommentUpdateFormProps): React.ReactElement;
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate an update form with hasMany relationship 1`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate an update form with hasMany relationship without types file 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
@@ -5184,7 +6436,7 @@ import {
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import { API } from \\"aws-amplify\\";
-import { getComment, listPosts } from \\"../graphql/queries\\";
+import { getComment, listPostIDS, listPosts } from \\"../graphql/queries\\";
import { updateComment } from \\"../graphql/mutations\\";
function ArrayField({
items = [],
@@ -5469,7 +6721,7 @@ export default function CommentUpdateForm(props) {
}
const result = (
await API.graphql({
- query: listPosts,
+ query: listPostIDS,
variables,
})
).data.listPostIDS.item;
@@ -5831,11 +7083,10 @@ export default function CommentUpdateForm(props) {
"
`;
-exports[`amplify form renderer tests GraphQL form tests should generate an update form with hasMany relationship 2`] = `
+exports[`amplify form renderer tests GraphQL form tests should generate an update form with hasMany relationship without types file 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
-import { Comment, Post } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
@@ -5844,13 +7095,13 @@ export declare type ValidationFunction = (value: T, validationResponse: Valid
export declare type CommentUpdateFormInputValues = {
content?: string;
postID?: string;
- Post?: Post;
+ Post?: any;
post?: string;
};
export declare type CommentUpdateFormValidationValues = {
content?: ValidationFunction;
postID?: ValidationFunction;
- Post?: ValidationFunction;
+ Post?: ValidationFunction;
post?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
@@ -5865,7 +7116,7 @@ export declare type CommentUpdateFormProps = React.PropsWithChildren<{
overrides?: CommentUpdateFormOverridesProps | undefined | null;
} & {
id?: string;
- comment?: Comment;
+ comment?: any;
onSubmit?: (fields: CommentUpdateFormInputValues) => CommentUpdateFormInputValues;
onSuccess?: (fields: CommentUpdateFormInputValues) => void;
onError?: (fields: CommentUpdateFormInputValues, errorMessage: string) => void;
diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
index 4f381544..95019e99 100644
--- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
@@ -15,6 +15,7 @@
*/
/* eslint-disable no-template-curly-in-string */
import { ImportSource } from '../imports';
+import { ReactRenderConfig } from '../react-render-config';
import {
defaultCLIRenderConfig,
generateComponentOnlyWithAmplifyFormRenderer,
@@ -708,6 +709,16 @@ describe('amplify form renderer tests', () => {
});
describe('GraphQL form tests', () => {
+ const noTypesFileConfig: ReactRenderConfig = {
+ apiConfiguration: {
+ dataApi: 'GraphQL',
+ typesFilePath: '',
+ queriesFilePath: '../graphql/queries',
+ mutationsFilePath: '../graphql/mutations',
+ subscriptionsFilePath: '../graphql/subscriptions',
+ fragmentsFilePath: '../graphql/fragments',
+ },
+ };
it('should generate a create form', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/post-datastore-create',
@@ -777,6 +788,24 @@ describe('amplify form renderer tests', () => {
expect(declaration).toMatchSnapshot();
});
+ it('should generate an update form with hasMany relationship without types file', () => {
+ const { componentText, declaration } = generateWithAmplifyFormRenderer(
+ 'forms/relationships/update-comment',
+ 'datastore/relationships/has-many-comment',
+ { ...defaultCLIRenderConfig, ...noTypesFileConfig },
+ { isNonModelSupported: true, isRelationshipSupported: true },
+ );
+
+ // check for import statement for graphql operation
+ expect(componentText).not.toContain('DataStore');
+
+ expect(componentText).toContain('await API.graphql({');
+ expect(componentText).toContain('query: updateComment');
+
+ expect(componentText).toMatchSnapshot();
+ expect(declaration).toMatchSnapshot();
+ });
+
it('should generate a relationship update form with autocomplete', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/relationships/update-post',
@@ -980,6 +1009,20 @@ describe('amplify form renderer tests', () => {
expect(componentText).toMatchSnapshot();
expect(declaration).toMatchSnapshot();
});
+
+ it('should 1:1 relationships without types file path - Create', () => {
+ const { componentText, declaration } = generateWithAmplifyFormRenderer(
+ 'forms/owner-dog-create',
+ 'datastore/dog-owner-required',
+ { ...defaultCLIRenderConfig, ...noTypesFileConfig },
+ { isNonModelSupported: true, isRelationshipSupported: true },
+ );
+
+ expect(componentText).not.toContain('cannot be unlinked because');
+ expect(componentText).not.toContain('cannot be linked to ');
+ expect(componentText).toMatchSnapshot();
+ expect(declaration).toMatchSnapshot();
+ });
});
it('should render form for child of bidirectional 1:m when field defined on parent', () => {
diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
index c3d3a0e2..e39a00ab 100644
--- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
@@ -39,18 +39,6 @@ describe('amplify render tests', () => {
expect(generatedCode.componentText).toMatchSnapshot();
});
- it('should generate a simple badge component', () => {});
-
- it('should generate a simple card component', () => {});
-
- it('should generate a simple divider component', () => {});
-
- it('should generate a simple flex component', () => {});
-
- it('should generate a simple image component', () => {});
-
- it('should generate a simple string component', () => {});
-
it('should generate a simple component without variant specific generation', () => {
const generatedCode = generateWithAmplifyRenderer('buttonGolden');
expect(generatedCode.componentText.includes('restProp')).toBe(false);
diff --git a/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts b/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
index 70d41002..1fdc03ef 100644
--- a/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
+++ b/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
@@ -40,6 +40,8 @@ import { DATA_TYPE_TO_TYPESCRIPT_MAP, FIELD_TYPE_TO_TYPESCRIPT_MAP } from './typ
import { ImportCollection, ImportSource } from '../../imports';
import { PRIMITIVE_OVERRIDE_PROPS } from '../../primitive';
import { COMPOSITE_PRIMARY_KEY_PROP_NAME } from '../../utils/constants';
+import { ReactRenderConfig } from '../../react-render-config';
+import { isGraphqlConfig } from '../../utils/graphql';
type Node = {
[n: string]: T | Node;
@@ -51,13 +53,21 @@ type GetTypeNodeParam = {
isArray: boolean;
isValidation: boolean;
importCollection?: ImportCollection;
+ renderConfig?: ReactRenderConfig;
};
/**
* based on the provided dataType (appsync scalar)
* converts to the correct typescript type
* default assumption is string type
*/
-const getTypeNode = ({ componentType, dataType, isArray, isValidation, importCollection }: GetTypeNodeParam) => {
+const getTypeNode = ({
+ componentType,
+ dataType,
+ isArray,
+ isValidation,
+ importCollection,
+ renderConfig,
+}: GetTypeNodeParam) => {
let typeNode: KeywordTypeNode | TypeReferenceNode = factory.createKeywordTypeNode(SyntaxKind.StringKeyword);
if (componentType in FIELD_TYPE_TO_TYPESCRIPT_MAP) {
@@ -71,7 +81,11 @@ const getTypeNode = ({ componentType, dataType, isArray, isValidation, importCol
if (dataType && typeof dataType === 'object' && 'model' in dataType) {
const modelName = dataType.model;
const aliasedModel = importCollection?.addModelImport(modelName);
- typeNode = factory.createTypeReferenceNode(factory.createIdentifier(aliasedModel || modelName));
+ let identifier = aliasedModel || modelName;
+ if (isGraphqlConfig(renderConfig?.apiConfiguration) && !renderConfig?.apiConfiguration.typesFilePath) {
+ identifier = 'any';
+ }
+ typeNode = factory.createTypeReferenceNode(factory.createIdentifier(identifier));
}
if (isValidation) {
@@ -157,13 +171,21 @@ export const generateFieldTypes = (
type: 'input' | 'validation',
fieldConfigs: Record,
importCollection?: ImportCollection,
+ renderConfig?: ReactRenderConfig,
) => {
const nestedPaths: [fieldName: string, getTypeNodeParam: GetTypeNodeParam][] = [];
const typeNodes: TypeElement[] = [];
const isValidation = type === 'validation';
const typeName = isValidation ? getValidationTypeName(formName) : getInputValuesTypeName(formName);
Object.entries(fieldConfigs).forEach(([fieldName, { dataType, componentType, isArray }]) => {
- const getTypeNodeParam = { dataType, componentType, isArray: !!isArray, isValidation, importCollection };
+ const getTypeNodeParam = {
+ dataType,
+ componentType,
+ isArray: !!isArray,
+ isValidation,
+ importCollection,
+ renderConfig,
+ };
const hasNestedFieldPath = fieldName.split('.').length > 1;
if (hasNestedFieldPath) {
nestedPaths.push([fieldName, getTypeNodeParam]);
diff --git a/packages/codegen-ui-react/lib/forms/react-form-renderer.ts b/packages/codegen-ui-react/lib/forms/react-form-renderer.ts
index 79f72ca2..9f945812 100644
--- a/packages/codegen-ui-react/lib/forms/react-form-renderer.ts
+++ b/packages/codegen-ui-react/lib/forms/react-form-renderer.ts
@@ -101,7 +101,7 @@ import {
} from './form-renderer-helper/type-helper';
import { buildSelectedRecordsIdSet } from './form-renderer-helper/model-values';
import { COMPOSITE_PRIMARY_KEY_PROP_NAME } from '../utils/constants';
-import { getFetchRelatedRecordsCallbacks } from '../utils/graphql';
+import { getFetchRelatedRecordsCallbacks, isGraphqlConfig } from '../utils/graphql';
type RenderComponentOnlyResponse = {
compText: string;
@@ -343,12 +343,16 @@ export abstract class ReactFormTemplateRenderer extends StudioTemplateRenderer<
modelName = this.importCollection.addModelImport(dataTypeName);
}
+ if (isGraphqlConfig(this.renderConfig.apiConfiguration) && !this.renderConfig.apiConfiguration.typesFilePath) {
+ modelName = 'any';
+ }
+
return [
validationResponseType,
validationFunctionType,
// pass in importCollection once to collect models to import
- generateFieldTypes(formName, 'input', fieldConfigs, this.importCollection),
- generateFieldTypes(formName, 'validation', fieldConfigs, this.importCollection),
+ generateFieldTypes(formName, 'input', fieldConfigs, this.importCollection, this.renderConfig),
+ generateFieldTypes(formName, 'validation', fieldConfigs, this.importCollection, this.renderConfig),
primitiveOverrideProp,
overrideTypeAliasDeclaration,
factory.createTypeAliasDeclaration(
diff --git a/packages/codegen-ui-react/lib/imports/import-collection.ts b/packages/codegen-ui-react/lib/imports/import-collection.ts
index 72ff4417..b9bb9df1 100644
--- a/packages/codegen-ui-react/lib/imports/import-collection.ts
+++ b/packages/codegen-ui-react/lib/imports/import-collection.ts
@@ -200,46 +200,48 @@ export class ImportCollection {
],
)
.concat(
- Array.from(this.#collection).map(([moduleName, imports]) => {
- const namedImports = [...imports].filter((namedImport) => namedImport !== 'default').sort();
- const aliasMap = this.importAlias.get(moduleName);
- if (aliasMap) {
- const importClause = factory.createImportClause(
- false,
- undefined,
- factory.createNamedImports(
- [...imports].map((item) => {
- const alias = aliasMap.get(item);
- return factory.createImportSpecifier(
- alias && alias !== item ? factory.createIdentifier(item) : undefined,
- factory.createIdentifier(alias ?? item),
- );
- }),
- ),
- );
+ Array.from(this.#collection)
+ .filter(([moduleName]) => moduleName)
+ .map(([moduleName, imports]) => {
+ const namedImports = [...imports].filter((namedImport) => namedImport !== 'default').sort();
+ const aliasMap = this.importAlias.get(moduleName);
+ if (aliasMap) {
+ const importClause = factory.createImportClause(
+ false,
+ undefined,
+ factory.createNamedImports(
+ [...imports].map((item) => {
+ const alias = aliasMap.get(item);
+ return factory.createImportSpecifier(
+ alias && alias !== item ? factory.createIdentifier(item) : undefined,
+ factory.createIdentifier(alias ?? item),
+ );
+ }),
+ ),
+ );
+ return factory.createImportDeclaration(
+ undefined,
+ undefined,
+ importClause,
+ factory.createStringLiteral(moduleName),
+ );
+ }
return factory.createImportDeclaration(
undefined,
undefined,
- importClause,
+ factory.createImportClause(
+ false,
+ // use module name as default import name
+ [...imports].indexOf('default') >= 0 ? factory.createIdentifier(path.basename(moduleName)) : undefined,
+ factory.createNamedImports(
+ namedImports.map((item) => {
+ return factory.createImportSpecifier(undefined, factory.createIdentifier(item));
+ }),
+ ),
+ ),
factory.createStringLiteral(moduleName),
);
- }
- return factory.createImportDeclaration(
- undefined,
- undefined,
- factory.createImportClause(
- false,
- // use module name as default import name
- [...imports].indexOf('default') >= 0 ? factory.createIdentifier(path.basename(moduleName)) : undefined,
- factory.createNamedImports(
- namedImports.map((item) => {
- return factory.createImportSpecifier(undefined, factory.createIdentifier(item));
- }),
- ),
- ),
- factory.createStringLiteral(moduleName),
- );
- }),
+ }),
);
return importDeclarations;
diff --git a/packages/codegen-ui-react/lib/utils/graphql.ts b/packages/codegen-ui-react/lib/utils/graphql.ts
index b673a6ea..00f560a1 100644
--- a/packages/codegen-ui-react/lib/utils/graphql.ts
+++ b/packages/codegen-ui-react/lib/utils/graphql.ts
@@ -29,6 +29,7 @@ import { ImportCollection, ImportValue } from '../imports';
import { capitalizeFirstLetter, getSetNameIdentifier, lowerCaseFirst } from '../helpers';
import { isBoundProperty, isConcatenatedProperty } from '../react-component-render-helper';
import { Primitive } from '../primitive';
+import { DataStoreRenderConfig, GraphqlRenderConfig } from '../react-render-config';
export enum ActionType {
CREATE = 'create',
@@ -39,6 +40,13 @@ export enum ActionType {
GET_BY_RELATIONSHIP = 'getByRelationship',
}
+/* istanbul ignore next */
+export const isGraphqlConfig = (
+ apiConfiguration?: GraphqlRenderConfig | DataStoreRenderConfig,
+): apiConfiguration is GraphqlRenderConfig => {
+ return apiConfiguration?.dataApi === 'GraphQL';
+};
+
export const getGraphqlQueryForModel = (action: ActionType, model: string, byFieldName = ''): string => {
switch (action) {
case ActionType.CREATE: