// Jest Snapshot v1, https://goo.gl/fbAQLP
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,
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 { listDogs } from \\"../graphql/queries\\";
import { createOwner, updateDog, updateOwner } 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 CreateOwnerForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
Dog: undefined,
};
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 = () => {
setName(initialValues.name);
setDog(initialValues.Dog);
setCurrentDogValue(undefined);
setCurrentDogDisplayValue(\\"\\");
setErrors({});
};
const [currentDogDisplayValue, setCurrentDogDisplayValue] =
React.useState(\\"\\");
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 = {
name: [{ type: \\"Required\\" }],
Dog: [],
};
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 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?.items;
var loaded = result.filter(
(item) => !DogIdSet.has(getIDValue.Dog?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setDogRecords(newOptions.slice(0, autocompleteLength));
setDogLoading(false);
};
React.useEffect(() => {
fetchDogRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
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,
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 === \\"\\") {
modelFields[key] = null;
}
});
const owner = await API.graphql({
query: createOwner,
variables: {
input: {
...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);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CreateOwnerForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
Dog,
};
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,
Dog: value,
};
const result = onChange(modelFields);
value = result?.Dog ?? value;
}
setDog(value);
setCurrentDogValue(undefined);
setCurrentDogDisplayValue(\\"\\");
}}
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);
}}
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;
fetchDogRecords(value);
if (errors.Dog?.hasError) {
runValidationTasks(\\"Dog\\", value);
}
setCurrentDogDisplayValue(value);
setCurrentDogValue(undefined);
}}
onBlur={() => runValidationTasks(\\"Dog\\", currentDogDisplayValue)}
errorMessage={errors.Dog?.errorMessage}
hasError={errors.Dog?.hasError}
ref={DogRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Dog\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should 1:1 relationships without types file path - Create 2`] = `
"import * as React from \\"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 CreateOwnerFormInputValues = {
name?: string;
Dog?: any;
};
export declare type CreateOwnerFormValidationValues = {
name?: ValidationFunction;
Dog?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CreateOwnerFormOverridesProps = {
CreateOwnerFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
Dog?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CreateOwnerFormProps = React.PropsWithChildren<{
overrides?: CreateOwnerFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
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 CreateOwnerForm(props: CreateOwnerFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate a create form 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
Badge,
Button,
Divider,
Flex,
Grid,
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\\";
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 MyPostForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
caption: \\"\\",
username: \\"\\",
post_url: \\"\\",
metadata: \\"\\",
profile_url: \\"\\",
nonModelField: \\"\\",
nonModelFieldArray: [],
};
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 = () => {
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 [currentNonModelFieldArrayValue, setCurrentNonModelFieldArrayValue] =
React.useState(\\"\\");
const nonModelFieldArrayRef = React.createRef();
const validations = {
caption: [],
username: [],
post_url: [{ type: \\"URL\\" }],
metadata: [{ type: \\"JSON\\" }],
profile_url: [{ type: \\"URL\\" }],
nonModelField: [{ type: \\"JSON\\" }],
nonModelFieldArray: [{ type: \\"JSON\\" }],
};
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;
};
return (
{
event.preventDefault();
let modelFields = {
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)
)
);
return promises;
}
promises.push(
runValidationTasks(fieldName, modelFields[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 === \\"\\") {
modelFields[key] = null;
}
});
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,
variables: {
input: {
...modelFieldsToSave,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"MyPostForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
caption: value,
username,
post_url,
metadata,
profile_url,
nonModelField,
nonModelFieldArray,
};
const result = onChange(modelFields);
value = result?.caption ?? value;
}
if (errors.caption?.hasError) {
runValidationTasks(\\"caption\\", value);
}
setCaption(value);
}}
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 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={currentNonModelFieldArrayValue}
label={\\"Non model field array\\"}
items={nonModelFieldArray}
hasError={errors?.nonModelFieldArray?.hasError}
errorMessage={errors?.nonModelFieldArray?.errorMessage}
setFieldValue={setCurrentNonModelFieldArrayValue}
inputFieldRef={nonModelFieldArrayRef}
defaultFieldValue={\\"\\"}
>
{
let { value } = e.target;
if (errors.nonModelFieldArray?.hasError) {
runValidationTasks(\\"nonModelFieldArray\\", value);
}
setCurrentNonModelFieldArrayValue(value);
}}
onBlur={() =>
runValidationTasks(
\\"nonModelFieldArray\\",
currentNonModelFieldArrayValue
)
}
errorMessage={errors.nonModelFieldArray?.errorMessage}
hasError={errors.nonModelFieldArray?.hasError}
ref={nonModelFieldArrayRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"nonModelFieldArray\\")}
>
);
}
"
`;
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?.listTeams?.items;
var loaded = result.filter((item) => teamID !== item.id);
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?.items;
var loaded = result.filter(
(item) => !TeamIdSet.has(getIDValue.Team?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setTeamRecords(newOptions.slice(0, autocompleteLength));
setTeamLoading(false);
};
React.useEffect(() => {
fetchTeamIDRecords(\\"\\");
fetchTeamRecords(\\"\\");
}, []);
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 === \\"\\") {
modelFields[key] = null;
}
});
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(teamIDRecords.find((r) => r.id === value))
: \\"\\"
}
setFieldValue={(value) => {
setCurrentTeamIDDisplayValue(
value
? getDisplayValue.teamID(
teamIDRecords.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;
}
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?.items;
var loaded = result.filter(
(item) => !StudentsIdSet.has(getIDValue.Students?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setStudentsRecords(newOptions.slice(0, autocompleteLength));
setStudentsLoading(false);
};
React.useEffect(() => {
fetchStudentsRecords(\\"\\");
}, []);
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 === \\"\\") {
modelFields[key] = null;
}
});
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;
}
setStudents(values);
setCurrentStudentsValue(undefined);
setCurrentStudentsDisplayValue(\\"\\");
}}
currentFieldValue={currentStudentsValue}
label={\\"Students\\"}
items={Students}
hasError={errors?.Students?.hasError}
errorMessage={errors?.Students?.errorMessage}
getBadgeText={getDisplayValue.Students}
setFieldValue={(model) => {
setCurrentStudentsDisplayValue(
model ? getDisplayValue.Students(model) : \\"\\"
);
setCurrentStudentsValue(model);
}}
inputFieldRef={StudentsRef}
defaultFieldValue={\\"\\"}
>
!StudentsIdSet.has(getIDValue.Students?.(r))
).map((r) => ({
id: getIDValue.Students?.(r),
label: getDisplayValue.Students?.(r),
}))}
isLoading={StudentsLoading}
onSelect={({ id, label }) => {
setCurrentStudentsValue(
StudentsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentStudentsDisplayValue(label);
runValidationTasks(\\"Students\\", label);
}}
onClear={() => {
setCurrentStudentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchStudentsRecords(value);
if (errors.Students?.hasError) {
runValidationTasks(\\"Students\\", value);
}
setCurrentStudentsDisplayValue(value);
setCurrentStudentsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"Students\\", currentStudentsDisplayValue)
}
errorMessage={errors.Students?.errorMessage}
hasError={errors.Students?.hasError}
ref={StudentsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Students\\")}
>
);
}
"
`;
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 { Student } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type SchoolCreateFormInputValues = {
name?: string;
Students?: Student[];
};
export declare type SchoolCreateFormValidationValues = {
name?: ValidationFunction;
Students?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type SchoolCreateFormOverridesProps = {
SchoolCreateFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
Students?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type SchoolCreateFormProps = React.PropsWithChildren<{
overrides?: SchoolCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
onSuccess?: (fields: SchoolCreateFormInputValues) => void;
onError?: (fields: SchoolCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
onChange?: (fields: SchoolCreateFormInputValues) => SchoolCreateFormInputValues;
onValidate?: SchoolCreateFormValidationValues;
} & React.CSSProperties>;
export default function SchoolCreateForm(props: SchoolCreateFormProps): React.ReactElement;
"
`;
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 {
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 { listAuthors } from \\"../graphql/queries\\";
import { createBook } 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 BookCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
primaryAuthor: undefined,
};
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 autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
setName(initialValues.name);
setPrimaryAuthor(initialValues.primaryAuthor);
setCurrentPrimaryAuthorValue(undefined);
setCurrentPrimaryAuthorDisplayValue(\\"\\");
setErrors({});
};
const [
currentPrimaryAuthorDisplayValue,
setCurrentPrimaryAuthorDisplayValue,
] = React.useState(\\"\\");
const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
React.useState(undefined);
const primaryAuthorRef = React.createRef();
const getIDValue = {
primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
};
const primaryAuthorIdSet = new Set(
Array.isArray(primaryAuthor)
? primaryAuthor.map((r) => getIDValue.primaryAuthor?.(r))
: getIDValue.primaryAuthor?.(primaryAuthor)
);
const getDisplayValue = {
primaryAuthor: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
name: [],
primaryAuthor: [],
};
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 } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listAuthors,
variables,
})
)?.data?.listAuthors?.items;
var loaded = result.filter(
(item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPrimaryAuthorRecords(newOptions.slice(0, autocompleteLength));
setPrimaryAuthorLoading(false);
};
React.useEffect(() => {
fetchPrimaryAuthorRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
primaryAuthor,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
await API.graphql({
query: createBook,
variables: {
input: {
...modelFields,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"BookCreateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
primaryAuthor,
};
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,
primaryAuthor: value,
};
const result = onChange(modelFields);
value = result?.primaryAuthor ?? value;
}
setPrimaryAuthor(value);
setCurrentPrimaryAuthorValue(undefined);
setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
currentFieldValue={currentPrimaryAuthorValue}
label={\\"Primary author\\"}
items={primaryAuthor ? [primaryAuthor] : []}
hasError={errors?.primaryAuthor?.hasError}
errorMessage={errors?.primaryAuthor?.errorMessage}
getBadgeText={getDisplayValue.primaryAuthor}
setFieldValue={(model) => {
setCurrentPrimaryAuthorDisplayValue(
model ? getDisplayValue.primaryAuthor(model) : \\"\\"
);
setCurrentPrimaryAuthorValue(model);
}}
inputFieldRef={primaryAuthorRef}
defaultFieldValue={\\"\\"}
>
!primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
)
.map((r) => ({
id: getIDValue.primaryAuthor?.(r),
label: getDisplayValue.primaryAuthor?.(r),
}))}
isLoading={primaryAuthorLoading}
onSelect={({ id, label }) => {
setCurrentPrimaryAuthorValue(
primaryAuthorRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPrimaryAuthorDisplayValue(label);
runValidationTasks(\\"primaryAuthor\\", label);
}}
onClear={() => {
setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchPrimaryAuthorRecords(value);
if (errors.primaryAuthor?.hasError) {
runValidationTasks(\\"primaryAuthor\\", value);
}
setCurrentPrimaryAuthorDisplayValue(value);
setCurrentPrimaryAuthorValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"primaryAuthor\\",
currentPrimaryAuthorDisplayValue
)
}
errorMessage={errors.primaryAuthor?.errorMessage}
hasError={errors.primaryAuthor?.hasError}
ref={primaryAuthorRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"primaryAuthor\\")}
>
);
}
"
`;
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 { Author } 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 BookCreateFormValidationValues = {
name?: ValidationFunction;
primaryAuthor?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type BookCreateFormOverridesProps = {
BookCreateFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
primaryAuthor?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type BookCreateFormProps = React.PropsWithChildren<{
overrides?: BookCreateFormOverridesProps | 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;
} & React.CSSProperties>;
export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
"
`;
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 {
Autocomplete,
Badge,
Button,
Divider,
Flex,
Grid,
Icon,
ScrollView,
SelectField,
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 { listPosts } from \\"../graphql/queries\\";
import { createTag, createTagPost } 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 TagCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
label: \\"\\",
Posts: [],
statuses: [],
};
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 = () => {
setLabel(initialValues.label);
setPosts(initialValues.Posts);
setCurrentPostsValue(undefined);
setCurrentPostsDisplayValue(\\"\\");
setStatuses(initialValues.statuses);
setCurrentStatusesValue(\\"\\");
setErrors({});
};
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 = {
Posts: (r) => JSON.stringify({ id: r?.id }),
};
const PostsIdSet = new Set(
Array.isArray(Posts)
? Posts.map((r) => getIDValue.Posts?.(r))
: getIDValue.Posts?.(Posts)
);
const getDisplayValue = {
Posts: (r) => r?.title,
statuses: (r) => {
const enumDisplayValueMap = {
PENDING: \\"Pending\\",
POSTED: \\"Posted\\",
IN_REVIEW: \\"In review\\",
};
return enumDisplayValueMap[r];
},
};
const validations = {
label: [],
Posts: [],
statuses: [],
};
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 fetchPostsRecords = async (value) => {
setPostsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: { or: [{ title: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter(
(item) => !PostsIdSet.has(getIDValue.Posts?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostsRecords(newOptions.slice(0, autocompleteLength));
setPostsLoading(false);
};
React.useEffect(() => {
fetchPostsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
label,
Posts,
statuses,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
label: modelFields.label,
statuses: modelFields.statuses,
};
const tag = await API.graphql({
query: createTag,
variables: {
input: {
...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);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"TagCreateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
label: value,
Posts,
statuses,
};
const result = onChange(modelFields);
value = result?.label ?? value;
}
if (errors.label?.hasError) {
runValidationTasks(\\"label\\", value);
}
setLabel(value);
}}
onBlur={() => runValidationTasks(\\"label\\", label)}
errorMessage={errors.label?.errorMessage}
hasError={errors.label?.hasError}
{...getOverrideProps(overrides, \\"label\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
label,
Posts: values,
statuses,
};
const result = onChange(modelFields);
values = result?.Posts ?? values;
}
setPosts(values);
setCurrentPostsValue(undefined);
setCurrentPostsDisplayValue(\\"\\");
}}
currentFieldValue={currentPostsValue}
label={\\"Posts\\"}
items={Posts}
hasError={errors?.Posts?.hasError}
errorMessage={errors?.Posts?.errorMessage}
getBadgeText={getDisplayValue.Posts}
setFieldValue={(model) => {
setCurrentPostsDisplayValue(
model ? getDisplayValue.Posts(model) : \\"\\"
);
setCurrentPostsValue(model);
}}
inputFieldRef={PostsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.Posts?.(r),
label: getDisplayValue.Posts?.(r),
}))}
isLoading={PostsLoading}
onSelect={({ id, label }) => {
setCurrentPostsValue(
PostsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPostsDisplayValue(label);
runValidationTasks(\\"Posts\\", label);
}}
onClear={() => {
setCurrentPostsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchPostsRecords(value);
if (errors.Posts?.hasError) {
runValidationTasks(\\"Posts\\", value);
}
setCurrentPostsDisplayValue(value);
setCurrentPostsValue(undefined);
}}
onBlur={() => runValidationTasks(\\"Posts\\", currentPostsDisplayValue)}
errorMessage={errors.Posts?.errorMessage}
hasError={errors.Posts?.hasError}
ref={PostsRef}
labelHidden={true}
{...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 manyToMany relationship 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, SelectFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
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 TagCreateFormInputValues = {
label?: string;
Posts?: Post[];
statuses?: string[];
};
export declare type TagCreateFormValidationValues = {
label?: ValidationFunction;
Posts?: ValidationFunction;
statuses?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type TagCreateFormOverridesProps = {
TagCreateFormGrid?: PrimitiveOverrideProps;
label?: PrimitiveOverrideProps;
Posts?: PrimitiveOverrideProps;
statuses?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type TagCreateFormProps = React.PropsWithChildren<{
overrides?: TagCreateFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
onSuccess?: (fields: TagCreateFormInputValues) => void;
onError?: (fields: TagCreateFormInputValues, errorMessage: string) => void;
onCancel?: () => void;
onChange?: (fields: TagCreateFormInputValues) => TagCreateFormInputValues;
onValidate?: TagCreateFormValidationValues;
} & React.CSSProperties>;
export default function TagCreateForm(props: TagCreateFormProps): React.ReactElement;
"
`;
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 {
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 { listAuthors, listTitles } from \\"../graphql/queries\\";
import { createBook } 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 BookCreateForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
primaryAuthor: undefined,
primaryTitle: undefined,
};
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 = () => {
setName(initialValues.name);
setPrimaryAuthor(initialValues.primaryAuthor);
setCurrentPrimaryAuthorValue(undefined);
setCurrentPrimaryAuthorDisplayValue(\\"\\");
setPrimaryTitle(initialValues.primaryTitle);
setCurrentPrimaryTitleValue(undefined);
setCurrentPrimaryTitleDisplayValue(\\"\\");
setErrors({});
};
const [
currentPrimaryAuthorDisplayValue,
setCurrentPrimaryAuthorDisplayValue,
] = React.useState(\\"\\");
const [currentPrimaryAuthorValue, setCurrentPrimaryAuthorValue] =
React.useState(undefined);
const primaryAuthorRef = React.createRef();
const [currentPrimaryTitleDisplayValue, setCurrentPrimaryTitleDisplayValue] =
React.useState(\\"\\");
const [currentPrimaryTitleValue, setCurrentPrimaryTitleValue] =
React.useState(undefined);
const primaryTitleRef = React.createRef();
const getIDValue = {
primaryAuthor: (r) => JSON.stringify({ id: r?.id }),
primaryTitle: (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 getDisplayValue = {
primaryAuthor: (r) => r?.name,
primaryTitle: (r) => r?.name,
};
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?.listAuthors?.items;
var loaded = result.filter(
(item) => !primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
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?.listTitles?.items;
var loaded = result.filter(
(item) => !primaryTitleIdSet.has(getIDValue.primaryTitle?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPrimaryTitleRecords(newOptions.slice(0, autocompleteLength));
setPrimaryTitleLoading(false);
};
React.useEffect(() => {
fetchPrimaryAuthorRecords(\\"\\");
fetchPrimaryTitleRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
primaryAuthor,
primaryTitle,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
await API.graphql({
query: createBook,
variables: {
input: {
...modelFields,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"BookCreateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
primaryAuthor,
primaryTitle,
};
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,
primaryAuthor: value,
primaryTitle,
};
const result = onChange(modelFields);
value = result?.primaryAuthor ?? value;
}
setPrimaryAuthor(value);
setCurrentPrimaryAuthorValue(undefined);
setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
currentFieldValue={currentPrimaryAuthorValue}
label={\\"Primary author\\"}
items={primaryAuthor ? [primaryAuthor] : []}
hasError={errors?.primaryAuthor?.hasError}
errorMessage={errors?.primaryAuthor?.errorMessage}
getBadgeText={getDisplayValue.primaryAuthor}
setFieldValue={(model) => {
setCurrentPrimaryAuthorDisplayValue(
model ? getDisplayValue.primaryAuthor(model) : \\"\\"
);
setCurrentPrimaryAuthorValue(model);
}}
inputFieldRef={primaryAuthorRef}
defaultFieldValue={\\"\\"}
>
!primaryAuthorIdSet.has(getIDValue.primaryAuthor?.(r))
)
.map((r) => ({
id: getIDValue.primaryAuthor?.(r),
label: getDisplayValue.primaryAuthor?.(r),
}))}
isLoading={primaryAuthorLoading}
onSelect={({ id, label }) => {
setCurrentPrimaryAuthorValue(
primaryAuthorRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPrimaryAuthorDisplayValue(label);
runValidationTasks(\\"primaryAuthor\\", label);
}}
onClear={() => {
setCurrentPrimaryAuthorDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchPrimaryAuthorRecords(value);
if (errors.primaryAuthor?.hasError) {
runValidationTasks(\\"primaryAuthor\\", value);
}
setCurrentPrimaryAuthorDisplayValue(value);
setCurrentPrimaryAuthorValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"primaryAuthor\\",
currentPrimaryAuthorDisplayValue
)
}
errorMessage={errors.primaryAuthor?.errorMessage}
hasError={errors.primaryAuthor?.hasError}
ref={primaryAuthorRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"primaryAuthor\\")}
>
{
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(
primaryTitleRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPrimaryTitleDisplayValue(label);
runValidationTasks(\\"primaryTitle\\", label);
}}
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 multiple hasOne relationships 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\\";
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 BookCreateFormValidationValues = {
name?: ValidationFunction;
primaryAuthor?: ValidationFunction;
primaryTitle?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type BookCreateFormOverridesProps = {
BookCreateFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
primaryAuthor?: PrimitiveOverrideProps;
primaryTitle?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type BookCreateFormProps = React.PropsWithChildren<{
overrides?: BookCreateFormOverridesProps | 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;
} & React.CSSProperties>;
export default function BookCreateForm(props: BookCreateFormProps): React.ReactElement;
"
`;
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 {
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 { getPost, listComments } from \\"../graphql/queries\\";
import { updateComment, updatePost } 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 PostUpdateForm(props) {
const {
id: idProp,
post: postModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
title: \\"\\",
body: \\"\\",
publishDate: \\"\\",
Comments: [],
};
const [title, setTitle] = React.useState(initialValues.title);
const [body, setBody] = React.useState(initialValues.body);
const [publishDate, setPublishDate] = React.useState(
initialValues.publishDate
);
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;
setTitle(cleanValues.title);
setBody(cleanValues.body);
setPublishDate(cleanValues.publishDate);
setComments(cleanValues.Comments ?? []);
setCurrentCommentsValue(undefined);
setCurrentCommentsDisplayValue(\\"\\");
setErrors({});
};
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: { id: idProp },
})
)?.data?.getPost
: postModelProp;
const linkedComments = record?.Comment?.items ?? [];
setLinkedComments(linkedComments);
setPostRecord(record);
};
queryData();
}, [idProp, postModelProp]);
React.useEffect(resetStateValues, [postRecord, linkedComments]);
const [currentCommentsDisplayValue, setCurrentCommentsDisplayValue] =
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 validations = {
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);
}
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?.items;
var loaded = result.filter(
(item) => !CommentsIdSet.has(getIDValue.Comments?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCommentsRecords(newOptions.slice(0, autocompleteLength));
setCommentsLoading(false);
};
React.useEffect(() => {
fetchCommentsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
title,
body,
publishDate,
Comments,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
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: updateComment,
variables: {
input: {
id: original.id,
postID: null,
},
},
})
);
});
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);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"PostUpdateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
title: value,
body,
publishDate,
Comments,
};
const result = onChange(modelFields);
value = result?.title ?? value;
}
if (errors.title?.hasError) {
runValidationTasks(\\"title\\", value);
}
setTitle(value);
}}
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 values = items;
if (onChange) {
const modelFields = {
title,
body,
publishDate,
Comments: values,
};
const result = onChange(modelFields);
values = result?.Comments ?? 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);
}}
inputFieldRef={CommentsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.Comments?.(r),
label: getDisplayValue.Comments?.(r),
}))}
isLoading={CommentsLoading}
onSelect={({ id, label }) => {
setCurrentCommentsValue(
CommentsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCommentsDisplayValue(label);
runValidationTasks(\\"Comments\\", label);
}}
onClear={() => {
setCurrentCommentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCommentsRecords(value);
if (errors.Comments?.hasError) {
runValidationTasks(\\"Comments\\", value);
}
setCurrentCommentsDisplayValue(value);
setCurrentCommentsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"Comments\\", currentCommentsDisplayValue)
}
errorMessage={errors.Comments?.errorMessage}
hasError={errors.Comments?.hasError}
ref={CommentsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Comments\\")}
>
);
}
"
`;
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 { 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 PostUpdateFormInputValues = {
title?: string;
body?: string;
publishDate?: string;
Comments?: Comment[];
};
export declare type PostUpdateFormValidationValues = {
title?: ValidationFunction;
body?: ValidationFunction;
publishDate?: ValidationFunction;
Comments?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type PostUpdateFormOverridesProps = {
PostUpdateFormGrid?: PrimitiveOverrideProps;
title?: PrimitiveOverrideProps;
body?: PrimitiveOverrideProps;
publishDate?: PrimitiveOverrideProps;
Comments?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type PostUpdateFormProps = React.PropsWithChildren<{
overrides?: PostUpdateFormOverridesProps | undefined | null;
} & {
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 PostUpdateForm(props: PostUpdateFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate a update form without relationships 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
Badge,
Button,
Divider,
Flex,
Grid,
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 { getPost } from \\"../graphql/queries\\";
import { updatePost } 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 MyPostForm(props) {
const {
id: idProp,
post: postModelProp,
onSuccess,
onError,
onSubmit,
onCancel,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
TextAreaFieldbbd63464: \\"\\",
caption: \\"\\",
username: \\"\\",
profile_url: \\"\\",
post_url: \\"\\",
metadata: \\"\\",
nonModelField: \\"\\",
nonModelFieldArray: [],
};
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 [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = postRecord
? { ...initialValues, ...postRecord }
: initialValues;
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 === null
? cleanValues.metadata
: JSON.stringify(cleanValues.metadata)
);
setNonModelField(
typeof cleanValues.nonModelField === \\"string\\" ||
cleanValues.nonModelField === null
? 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);
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getPost,
variables: { id: idProp },
})
)?.data?.getPost
: postModelProp;
setPostRecord(record);
};
queryData();
}, [idProp, postModelProp]);
React.useEffect(resetStateValues, [postRecord]);
const [currentNonModelFieldArrayValue, setCurrentNonModelFieldArrayValue] =
React.useState(\\"\\");
const nonModelFieldArrayRef = React.createRef();
const validations = {
TextAreaFieldbbd63464: [],
caption: [],
username: [],
profile_url: [{ type: \\"URL\\" }],
post_url: [{ type: \\"URL\\" }],
metadata: [{ type: \\"JSON\\" }],
nonModelField: [{ type: \\"JSON\\" }],
nonModelFieldArray: [{ type: \\"JSON\\" }],
};
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;
};
return (
{
event.preventDefault();
let modelFields = {
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)
)
);
return promises;
}
promises.push(
runValidationTasks(fieldName, modelFields[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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
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,
};
await API.graphql({
query: updatePost,
variables: {
input: {
id: postRecord.id,
...modelFieldsToSave,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...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 = {
TextAreaFieldbbd63464,
caption: value,
username,
profile_url,
post_url,
metadata,
nonModelField,
nonModelFieldArray,
};
const result = onChange(modelFields);
value = result?.caption ?? value;
}
if (errors.caption?.hasError) {
runValidationTasks(\\"caption\\", value);
}
setCaption(value);
}}
onBlur={() => runValidationTasks(\\"caption\\", caption)}
errorMessage={errors.caption?.errorMessage}
hasError={errors.caption?.hasError}
{...getOverrideProps(overrides, \\"caption\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
TextAreaFieldbbd63464,
caption,
username: value,
profile_url,
post_url,
metadata,
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 = {
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?.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 values = items;
if (onChange) {
const modelFields = {
TextAreaFieldbbd63464,
caption,
username,
profile_url,
post_url,
metadata,
nonModelField,
nonModelFieldArray: values,
};
const result = onChange(modelFields);
values = result?.nonModelFieldArray ?? values;
}
setNonModelFieldArray(values);
setCurrentNonModelFieldArrayValue(\\"\\");
}}
currentFieldValue={currentNonModelFieldArrayValue}
label={\\"Non model field array\\"}
items={nonModelFieldArray}
hasError={errors?.nonModelFieldArray?.hasError}
errorMessage={errors?.nonModelFieldArray?.errorMessage}
setFieldValue={setCurrentNonModelFieldArrayValue}
inputFieldRef={nonModelFieldArrayRef}
defaultFieldValue={\\"\\"}
>
{
let { value } = e.target;
if (errors.nonModelFieldArray?.hasError) {
runValidationTasks(\\"nonModelFieldArray\\", value);
}
setCurrentNonModelFieldArrayValue(value);
}}
onBlur={() =>
runValidationTasks(
\\"nonModelFieldArray\\",
currentNonModelFieldArrayValue
)
}
errorMessage={errors.nonModelFieldArray?.errorMessage}
hasError={errors.nonModelFieldArray?.hasError}
ref={nonModelFieldArrayRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"nonModelFieldArray\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate a update form without relationships 2`] = `
"import * as React from \\"react\\";
import { GridProps, TextAreaFieldProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
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 MyPostFormInputValues = {
TextAreaFieldbbd63464?: string;
caption?: string;
username?: string;
profile_url?: string;
post_url?: string;
metadata?: string;
nonModelField?: string;
nonModelFieldArray?: 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 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;
} & EscapeHatchProps;
export declare type MyPostFormProps = React.PropsWithChildren<{
overrides?: MyPostFormOverridesProps | 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;
} & React.CSSProperties>;
export default function MyPostForm(props: MyPostFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update form with composite primary key 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 {
getMovie,
listMovieTags,
listTags,
movieTagsByMovieMovieKeyAndMovietitleAndMoviegenre,
} from \\"../graphql/queries\\";
import { API } from \\"aws-amplify\\";
import {
createMovieTags,
deleteMovieTags,
updateMovie,
} 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 MovieUpdateForm(props) {
const {
id: idProp,
movie: movieModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
movieKey: \\"\\",
title: \\"\\",
genre: \\"\\",
rating: \\"\\",
tags: [],
};
const [movieKey, setMovieKey] = React.useState(initialValues.movieKey);
const [title, setTitle] = React.useState(initialValues.title);
const [genre, setGenre] = React.useState(initialValues.genre);
const [rating, setRating] = React.useState(initialValues.rating);
const [tags, setTags] = React.useState(initialValues.tags);
const [tagsLoading, setTagsLoading] = React.useState(false);
const [tagsRecords, setTagsRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = movieRecord
? { ...initialValues, ...movieRecord, tags: linkedTags }
: initialValues;
setMovieKey(cleanValues.movieKey);
setTitle(cleanValues.title);
setGenre(cleanValues.genre);
setRating(cleanValues.rating);
setTags(cleanValues.tags ?? []);
setCurrentTagsValue(undefined);
setCurrentTagsDisplayValue(\\"\\");
setErrors({});
};
const [movieRecord, setMovieRecord] = React.useState(movieModelProp);
const [linkedTags, setLinkedTags] = React.useState([]);
const canUnlinkTags = false;
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getMovie,
variables: { ...idProp },
})
)?.data?.getMovie
: movieModelProp;
const linkedTags = record
? (
await API.graphql({
query: movieTagsByMovieMovieKeyAndMovietitleAndMoviegenre,
variables: {
movieMovieKey: record.movieKey,
movietitle: record.title,
moviegenre: record.genre,
},
})
).data.movieTagsByMovieMovieKeyAndMovietitleAndMoviegenre.items.map(
(t) => t.tag
)
: [];
setLinkedTags(linkedTags);
setMovieRecord(record);
};
queryData();
}, [idProp, movieModelProp]);
React.useEffect(resetStateValues, [movieRecord, linkedTags]);
const [currentTagsDisplayValue, setCurrentTagsDisplayValue] =
React.useState(\\"\\");
const [currentTagsValue, setCurrentTagsValue] = React.useState(undefined);
const tagsRef = React.createRef();
const getIDValue = {
tags: (r) => JSON.stringify({ id: r?.id }),
};
const tagsIdSet = new Set(
Array.isArray(tags)
? tags.map((r) => getIDValue.tags?.(r))
: getIDValue.tags?.(tags)
);
const getDisplayValue = {
tags: (r) => \`\${r?.label ? r?.label + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
movieKey: [{ type: \\"Required\\" }],
title: [{ type: \\"Required\\" }],
genre: [{ type: \\"Required\\" }],
rating: [],
tags: [],
};
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 fetchTagsRecords = async (value) => {
setTagsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ label: { contains: value } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listTags,
variables,
})
)?.data?.listTags?.items;
var loaded = result.filter(
(item) => !tagsIdSet.has(getIDValue.tags?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setTagsRecords(newOptions.slice(0, autocompleteLength));
setTagsLoading(false);
};
React.useEffect(() => {
fetchTagsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
movieKey,
title,
genre,
rating,
tags,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const promises = [];
const tagsToLinkMap = new Map();
const tagsToUnLinkMap = new Map();
const tagsMap = new Map();
const linkedTagsMap = new Map();
tags.forEach((r) => {
const count = tagsMap.get(getIDValue.tags?.(r));
const newCount = count ? count + 1 : 1;
tagsMap.set(getIDValue.tags?.(r), newCount);
});
linkedTags.forEach((r) => {
const count = linkedTagsMap.get(getIDValue.tags?.(r));
const newCount = count ? count + 1 : 1;
linkedTagsMap.set(getIDValue.tags?.(r), newCount);
});
linkedTagsMap.forEach((count, id) => {
const newCount = tagsMap.get(id);
if (newCount) {
const diffCount = count - newCount;
if (diffCount > 0) {
tagsToUnLinkMap.set(id, diffCount);
}
} else {
tagsToUnLinkMap.set(id, count);
}
});
tagsMap.forEach((count, id) => {
const originalCount = linkedTagsMap.get(id);
if (originalCount) {
const diffCount = count - originalCount;
if (diffCount > 0) {
tagsToLinkMap.set(id, diffCount);
}
} else {
tagsToLinkMap.set(id, count);
}
});
tagsToUnLinkMap.forEach(async (count, id) => {
const recordKeys = JSON.parse(id);
const movieTagsRecords = (
await API.graphql({
query: listMovieTags,
variables: {
filter: {
and: [
{ tagId: { eq: recordKeys.id } },
{ movieMovieKey: { eq: movieRecord.movieKey } },
{ movietitle: { eq: movieRecord.title } },
{ moviegenre: { eq: movieRecord.genre } },
],
},
},
})
)?.data?.listMovieTags?.items;
for (let i = 0; i < count; i++) {
promises.push(
API.graphql({
query: deleteMovieTags,
variables: {
input: {
id: movieTagsRecords[i].id,
},
},
})
);
}
});
tagsToLinkMap.forEach((count, id) => {
const tagToLink = tagRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
);
for (let i = count; i > 0; i--) {
promises.push(
API.graphql({
query: createMovieTags,
variables: {
input: {
movieMovieKey: movieRecord.movieKey,
movietitle: movieRecord.title,
moviegenre: movieRecord.genre,
tagId: tagToLink.id,
},
},
})
);
}
});
const modelFieldsToSave = {
movieKey: modelFields.movieKey,
title: modelFields.title,
genre: modelFields.genre,
rating: modelFields.rating,
};
promises.push(
API.graphql({
query: updateMovie,
variables: {
input: {
movieKey: movieRecord.movieKey,
title: movieRecord.title,
genre: movieRecord.genre,
...modelFieldsToSave,
},
},
})
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"MovieUpdateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
movieKey: value,
title,
genre,
rating,
tags,
};
const result = onChange(modelFields);
value = result?.movieKey ?? value;
}
if (errors.movieKey?.hasError) {
runValidationTasks(\\"movieKey\\", value);
}
setMovieKey(value);
}}
onBlur={() => runValidationTasks(\\"movieKey\\", movieKey)}
errorMessage={errors.movieKey?.errorMessage}
hasError={errors.movieKey?.hasError}
{...getOverrideProps(overrides, \\"movieKey\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
movieKey,
title: value,
genre,
rating,
tags,
};
const result = onChange(modelFields);
value = result?.title ?? value;
}
if (errors.title?.hasError) {
runValidationTasks(\\"title\\", value);
}
setTitle(value);
}}
onBlur={() => runValidationTasks(\\"title\\", title)}
errorMessage={errors.title?.errorMessage}
hasError={errors.title?.hasError}
{...getOverrideProps(overrides, \\"title\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
movieKey,
title,
genre: value,
rating,
tags,
};
const result = onChange(modelFields);
value = result?.genre ?? value;
}
if (errors.genre?.hasError) {
runValidationTasks(\\"genre\\", value);
}
setGenre(value);
}}
onBlur={() => runValidationTasks(\\"genre\\", genre)}
errorMessage={errors.genre?.errorMessage}
hasError={errors.genre?.hasError}
{...getOverrideProps(overrides, \\"genre\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
movieKey,
title,
genre,
rating: value,
tags,
};
const result = onChange(modelFields);
value = result?.rating ?? value;
}
if (errors.rating?.hasError) {
runValidationTasks(\\"rating\\", value);
}
setRating(value);
}}
onBlur={() => runValidationTasks(\\"rating\\", rating)}
errorMessage={errors.rating?.errorMessage}
hasError={errors.rating?.hasError}
{...getOverrideProps(overrides, \\"rating\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
movieKey,
title,
genre,
rating,
tags: values,
};
const result = onChange(modelFields);
values = result?.tags ?? values;
}
setTags(values);
setCurrentTagsValue(undefined);
setCurrentTagsDisplayValue(\\"\\");
}}
currentFieldValue={currentTagsValue}
label={\\"Tags\\"}
items={tags}
hasError={errors?.tags?.hasError}
errorMessage={errors?.tags?.errorMessage}
getBadgeText={getDisplayValue.tags}
setFieldValue={(model) => {
setCurrentTagsDisplayValue(model ? getDisplayValue.tags(model) : \\"\\");
setCurrentTagsValue(model);
}}
inputFieldRef={tagsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.tags?.(r),
label: getDisplayValue.tags?.(r),
}))}
isLoading={tagsLoading}
onSelect={({ id, label }) => {
setCurrentTagsValue(
tagsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentTagsDisplayValue(label);
runValidationTasks(\\"tags\\", label);
}}
onClear={() => {
setCurrentTagsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchTagsRecords(value);
if (errors.tags?.hasError) {
runValidationTasks(\\"tags\\", value);
}
setCurrentTagsDisplayValue(value);
setCurrentTagsValue(undefined);
}}
onBlur={() => runValidationTasks(\\"tags\\", currentTagsDisplayValue)}
errorMessage={errors.tags?.errorMessage}
hasError={errors.tags?.hasError}
ref={tagsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"tags\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update form with composite primary key 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
import { Movie, Tag } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type MovieUpdateFormInputValues = {
movieKey?: string;
title?: string;
genre?: string;
rating?: string;
tags?: Tag[];
};
export declare type MovieUpdateFormValidationValues = {
movieKey?: ValidationFunction;
title?: ValidationFunction;
genre?: ValidationFunction;
rating?: ValidationFunction;
tags?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type MovieUpdateFormOverridesProps = {
MovieUpdateFormGrid?: PrimitiveOverrideProps;
movieKey?: PrimitiveOverrideProps;
title?: PrimitiveOverrideProps;
genre?: PrimitiveOverrideProps;
rating?: PrimitiveOverrideProps;
tags?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type MovieUpdateFormProps = React.PropsWithChildren<{
overrides?: MovieUpdateFormOverridesProps | undefined | null;
} & {
id?: {
movieKey: string;
title: string;
genre: string;
};
movie?: Movie;
onSubmit?: (fields: MovieUpdateFormInputValues) => MovieUpdateFormInputValues;
onSuccess?: (fields: MovieUpdateFormInputValues) => void;
onError?: (fields: MovieUpdateFormInputValues, errorMessage: string) => void;
onChange?: (fields: MovieUpdateFormInputValues) => MovieUpdateFormInputValues;
onValidate?: MovieUpdateFormValidationValues;
} & React.CSSProperties>;
export default function MovieUpdateForm(props: MovieUpdateFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update 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 { getComment, getPost, listPosts } from \\"../graphql/queries\\";
import { updateComment } 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 CommentUpdateForm(props) {
const {
id: idProp,
comment: commentModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
content: \\"\\",
postID: undefined,
Post: undefined,
post: \\"\\",
};
const [content, setContent] = React.useState(initialValues.content);
const [postID, setPostID] = React.useState(initialValues.postID);
const [postIDLoading, setPostIDLoading] = React.useState(false);
const [postIDRecords, setPostIDRecords] = React.useState([]);
const [Post, setPost] = React.useState(initialValues.Post);
const [PostLoading, setPostLoading] = React.useState(false);
const [PostRecords, setPostRecords] = React.useState([]);
const [post1, setPost1] = React.useState(initialValues.post);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = commentRecord
? { ...initialValues, ...commentRecord, postID, Post }
: initialValues;
setContent(cleanValues.content);
setPostID(cleanValues.postID);
setCurrentPostIDValue(undefined);
setCurrentPostIDDisplayValue(\\"\\");
setPost(cleanValues.Post);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
setPost1(cleanValues.post);
setErrors({});
};
const [commentRecord, setCommentRecord] = React.useState(commentModelProp);
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getComment,
variables: { id: idProp },
})
)?.data?.getComment
: commentModelProp;
const postIDRecord = record ? record.postID : undefined;
const postRecord = postIDRecord
? (
await API.graphql({
query: getPost,
variables: { id: postIDRecord },
})
)?.data?.getPost
: undefined;
setPostID(postIDRecord);
setPostIDRecords([postRecord]);
const PostRecord = record ? await record.Post : undefined;
setPost(PostRecord);
setCommentRecord(record);
};
queryData();
}, [idProp, commentModelProp]);
React.useEffect(resetStateValues, [commentRecord, postID, Post]);
const [currentPostIDDisplayValue, setCurrentPostIDDisplayValue] =
React.useState(\\"\\");
const [currentPostIDValue, setCurrentPostIDValue] = React.useState(undefined);
const postIDRef = React.createRef();
const [currentPostDisplayValue, setCurrentPostDisplayValue] =
React.useState(\\"\\");
const [currentPostValue, setCurrentPostValue] = React.useState(undefined);
const PostRef = React.createRef();
const getIDValue = {
Post: (r) => JSON.stringify({ id: r?.id }),
};
const PostIdSet = new Set(
Array.isArray(Post)
? Post.map((r) => getIDValue.Post?.(r))
: getIDValue.Post?.(Post)
);
const getDisplayValue = {
postID: (r) => \`\${r?.title ? r?.title + \\" - \\" : \\"\\"}\${r?.id}\`,
Post: (r) => \`\${r?.title ? r?.title + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
content: [],
postID: [{ type: \\"Required\\" }],
Post: [],
post: [],
};
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 fetchPostIDRecords = async (value) => {
setPostIDLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ title: { contains: value } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter((item) => postID !== item.id);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostIDRecords(newOptions.slice(0, autocompleteLength));
setPostIDLoading(false);
};
const fetchPostRecords = async (value) => {
setPostLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ title: { contains: value } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter(
(item) => !PostIdSet.has(getIDValue.Post?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostRecords(newOptions.slice(0, autocompleteLength));
setPostLoading(false);
};
React.useEffect(() => {
fetchPostIDRecords(\\"\\");
fetchPostRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
content,
postID,
Post,
post: post1,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
content: modelFields.content,
postID: modelFields.postID,
Post: modelFields.Post,
};
await API.graphql({
query: updateComment,
variables: {
input: {
id: commentRecord.id,
...modelFieldsToSave,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CommentUpdateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
content: value,
postID,
Post,
post: post1,
};
const result = onChange(modelFields);
value = result?.content ?? value;
}
if (errors.content?.hasError) {
runValidationTasks(\\"content\\", value);
}
setContent(value);
}}
onBlur={() => runValidationTasks(\\"content\\", content)}
errorMessage={errors.content?.errorMessage}
hasError={errors.content?.hasError}
{...getOverrideProps(overrides, \\"content\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
content,
postID: value,
Post,
post: post1,
};
const result = onChange(modelFields);
value = result?.postID ?? value;
}
setPostID(value);
setCurrentPostIDValue(undefined);
}}
currentFieldValue={currentPostIDValue}
label={\\"Post id\\"}
items={postID ? [postID] : []}
hasError={errors?.postID?.hasError}
errorMessage={errors?.postID?.errorMessage}
getBadgeText={(value) =>
value
? getDisplayValue.postID(postIDRecords.find((r) => r.id === value))
: \\"\\"
}
setFieldValue={(value) => {
setCurrentPostIDDisplayValue(
value
? getDisplayValue.postID(
postIDRecords.find((r) => r.id === value)
)
: \\"\\"
);
setCurrentPostIDValue(value);
}}
inputFieldRef={postIDRef}
defaultFieldValue={\\"\\"}
>
arr.findIndex((member) => member?.id === r?.id) === i
)
.map((r) => ({
id: r?.id,
label: getDisplayValue.postID?.(r),
}))}
isLoading={postIDLoading}
onSelect={({ id, label }) => {
setCurrentPostIDValue(id);
setCurrentPostIDDisplayValue(label);
runValidationTasks(\\"postID\\", label);
}}
onClear={() => {
setCurrentPostIDDisplayValue(\\"\\");
}}
defaultValue={postID}
onChange={(e) => {
let { value } = e.target;
fetchPostIDRecords(value);
if (errors.postID?.hasError) {
runValidationTasks(\\"postID\\", value);
}
setCurrentPostIDDisplayValue(value);
setCurrentPostIDValue(undefined);
}}
onBlur={() => runValidationTasks(\\"postID\\", currentPostIDValue)}
errorMessage={errors.postID?.errorMessage}
hasError={errors.postID?.hasError}
ref={postIDRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"postID\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
content,
postID,
Post: value,
post: post1,
};
const result = onChange(modelFields);
value = result?.Post ?? value;
}
setPost(value);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
}}
currentFieldValue={currentPostValue}
label={\\"Post\\"}
items={Post ? [Post] : []}
hasError={errors?.Post?.hasError}
errorMessage={errors?.Post?.errorMessage}
getBadgeText={getDisplayValue.Post}
setFieldValue={(model) => {
setCurrentPostDisplayValue(model ? getDisplayValue.Post(model) : \\"\\");
setCurrentPostValue(model);
}}
inputFieldRef={PostRef}
defaultFieldValue={\\"\\"}
>
!PostIdSet.has(getIDValue.Post?.(r))
).map((r) => ({
id: getIDValue.Post?.(r),
label: getDisplayValue.Post?.(r),
}))}
isLoading={PostLoading}
onSelect={({ id, label }) => {
setCurrentPostValue(
PostRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPostDisplayValue(label);
runValidationTasks(\\"Post\\", label);
}}
onClear={() => {
setCurrentPostDisplayValue(\\"\\");
}}
defaultValue={Post}
onChange={(e) => {
let { value } = e.target;
fetchPostRecords(value);
if (errors.Post?.hasError) {
runValidationTasks(\\"Post\\", value);
}
setCurrentPostDisplayValue(value);
setCurrentPostValue(undefined);
}}
onBlur={() => runValidationTasks(\\"Post\\", currentPostDisplayValue)}
errorMessage={errors.Post?.errorMessage}
hasError={errors.Post?.hasError}
ref={PostRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Post\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
content,
postID,
Post,
post: value,
};
const result = onChange(modelFields);
value = result?.post ?? value;
}
if (errors.post?.hasError) {
runValidationTasks(\\"post\\", value);
}
setPost1(value);
}}
onBlur={() => runValidationTasks(\\"post\\", post1)}
errorMessage={errors.post?.errorMessage}
hasError={errors.post?.hasError}
{...getOverrideProps(overrides, \\"post\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update 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 { 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 CommentUpdateFormInputValues = {
content?: string;
postID?: string;
Post?: Post;
post?: string;
};
export declare type CommentUpdateFormValidationValues = {
content?: ValidationFunction;
postID?: ValidationFunction;
Post?: ValidationFunction;
post?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CommentUpdateFormOverridesProps = {
CommentUpdateFormGrid?: PrimitiveOverrideProps;
content?: PrimitiveOverrideProps;
postID?: PrimitiveOverrideProps;
Post?: PrimitiveOverrideProps;
post?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CommentUpdateFormProps = React.PropsWithChildren<{
overrides?: CommentUpdateFormOverridesProps | undefined | null;
} & {
id?: string;
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 CommentUpdateForm(props: CommentUpdateFormProps): React.ReactElement;
"
`;
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 {
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 { getComment, getPost, listPosts } from \\"../graphql/queries\\";
import { updateComment } 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 CommentUpdateForm(props) {
const {
id: idProp,
comment: commentModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
content: \\"\\",
postID: undefined,
Post: undefined,
post: \\"\\",
};
const [content, setContent] = React.useState(initialValues.content);
const [postID, setPostID] = React.useState(initialValues.postID);
const [postIDLoading, setPostIDLoading] = React.useState(false);
const [postIDRecords, setPostIDRecords] = React.useState([]);
const [Post, setPost] = React.useState(initialValues.Post);
const [PostLoading, setPostLoading] = React.useState(false);
const [PostRecords, setPostRecords] = React.useState([]);
const [post1, setPost1] = React.useState(initialValues.post);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = commentRecord
? { ...initialValues, ...commentRecord, postID, Post }
: initialValues;
setContent(cleanValues.content);
setPostID(cleanValues.postID);
setCurrentPostIDValue(undefined);
setCurrentPostIDDisplayValue(\\"\\");
setPost(cleanValues.Post);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
setPost1(cleanValues.post);
setErrors({});
};
const [commentRecord, setCommentRecord] = React.useState(commentModelProp);
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getComment,
variables: { id: idProp },
})
)?.data?.getComment
: commentModelProp;
const postIDRecord = record ? record.postID : undefined;
const postRecord = postIDRecord
? (
await API.graphql({
query: getPost,
variables: { id: postIDRecord },
})
)?.data?.getPost
: undefined;
setPostID(postIDRecord);
setPostIDRecords([postRecord]);
const PostRecord = record ? await record.Post : undefined;
setPost(PostRecord);
setCommentRecord(record);
};
queryData();
}, [idProp, commentModelProp]);
React.useEffect(resetStateValues, [commentRecord, postID, Post]);
const [currentPostIDDisplayValue, setCurrentPostIDDisplayValue] =
React.useState(\\"\\");
const [currentPostIDValue, setCurrentPostIDValue] = React.useState(undefined);
const postIDRef = React.createRef();
const [currentPostDisplayValue, setCurrentPostDisplayValue] =
React.useState(\\"\\");
const [currentPostValue, setCurrentPostValue] = React.useState(undefined);
const PostRef = React.createRef();
const getIDValue = {
Post: (r) => JSON.stringify({ id: r?.id }),
};
const PostIdSet = new Set(
Array.isArray(Post)
? Post.map((r) => getIDValue.Post?.(r))
: getIDValue.Post?.(Post)
);
const getDisplayValue = {
postID: (r) => \`\${r?.title ? r?.title + \\" - \\" : \\"\\"}\${r?.id}\`,
Post: (r) => \`\${r?.title ? r?.title + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
content: [],
postID: [{ type: \\"Required\\" }],
Post: [],
post: [],
};
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 fetchPostIDRecords = async (value) => {
setPostIDLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ title: { contains: value } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter((item) => postID !== item.id);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostIDRecords(newOptions.slice(0, autocompleteLength));
setPostIDLoading(false);
};
const fetchPostRecords = async (value) => {
setPostLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ title: { contains: value } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter(
(item) => !PostIdSet.has(getIDValue.Post?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostRecords(newOptions.slice(0, autocompleteLength));
setPostLoading(false);
};
React.useEffect(() => {
fetchPostIDRecords(\\"\\");
fetchPostRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
content,
postID,
Post,
post: post1,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
content: modelFields.content,
postID: modelFields.postID,
Post: modelFields.Post,
};
await API.graphql({
query: updateComment,
variables: {
input: {
id: commentRecord.id,
...modelFieldsToSave,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CommentUpdateForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
content: value,
postID,
Post,
post: post1,
};
const result = onChange(modelFields);
value = result?.content ?? value;
}
if (errors.content?.hasError) {
runValidationTasks(\\"content\\", value);
}
setContent(value);
}}
onBlur={() => runValidationTasks(\\"content\\", content)}
errorMessage={errors.content?.errorMessage}
hasError={errors.content?.hasError}
{...getOverrideProps(overrides, \\"content\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
content,
postID: value,
Post,
post: post1,
};
const result = onChange(modelFields);
value = result?.postID ?? value;
}
setPostID(value);
setCurrentPostIDValue(undefined);
}}
currentFieldValue={currentPostIDValue}
label={\\"Post id\\"}
items={postID ? [postID] : []}
hasError={errors?.postID?.hasError}
errorMessage={errors?.postID?.errorMessage}
getBadgeText={(value) =>
value
? getDisplayValue.postID(postIDRecords.find((r) => r.id === value))
: \\"\\"
}
setFieldValue={(value) => {
setCurrentPostIDDisplayValue(
value
? getDisplayValue.postID(
postIDRecords.find((r) => r.id === value)
)
: \\"\\"
);
setCurrentPostIDValue(value);
}}
inputFieldRef={postIDRef}
defaultFieldValue={\\"\\"}
>
arr.findIndex((member) => member?.id === r?.id) === i
)
.map((r) => ({
id: r?.id,
label: getDisplayValue.postID?.(r),
}))}
isLoading={postIDLoading}
onSelect={({ id, label }) => {
setCurrentPostIDValue(id);
setCurrentPostIDDisplayValue(label);
runValidationTasks(\\"postID\\", label);
}}
onClear={() => {
setCurrentPostIDDisplayValue(\\"\\");
}}
defaultValue={postID}
onChange={(e) => {
let { value } = e.target;
fetchPostIDRecords(value);
if (errors.postID?.hasError) {
runValidationTasks(\\"postID\\", value);
}
setCurrentPostIDDisplayValue(value);
setCurrentPostIDValue(undefined);
}}
onBlur={() => runValidationTasks(\\"postID\\", currentPostIDValue)}
errorMessage={errors.postID?.errorMessage}
hasError={errors.postID?.hasError}
ref={postIDRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"postID\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
content,
postID,
Post: value,
post: post1,
};
const result = onChange(modelFields);
value = result?.Post ?? value;
}
setPost(value);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
}}
currentFieldValue={currentPostValue}
label={\\"Post\\"}
items={Post ? [Post] : []}
hasError={errors?.Post?.hasError}
errorMessage={errors?.Post?.errorMessage}
getBadgeText={getDisplayValue.Post}
setFieldValue={(model) => {
setCurrentPostDisplayValue(model ? getDisplayValue.Post(model) : \\"\\");
setCurrentPostValue(model);
}}
inputFieldRef={PostRef}
defaultFieldValue={\\"\\"}
>
!PostIdSet.has(getIDValue.Post?.(r))
).map((r) => ({
id: getIDValue.Post?.(r),
label: getDisplayValue.Post?.(r),
}))}
isLoading={PostLoading}
onSelect={({ id, label }) => {
setCurrentPostValue(
PostRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPostDisplayValue(label);
runValidationTasks(\\"Post\\", label);
}}
onClear={() => {
setCurrentPostDisplayValue(\\"\\");
}}
defaultValue={Post}
onChange={(e) => {
let { value } = e.target;
fetchPostRecords(value);
if (errors.Post?.hasError) {
runValidationTasks(\\"Post\\", value);
}
setCurrentPostDisplayValue(value);
setCurrentPostValue(undefined);
}}
onBlur={() => runValidationTasks(\\"Post\\", currentPostDisplayValue)}
errorMessage={errors.Post?.errorMessage}
hasError={errors.Post?.hasError}
ref={PostRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Post\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
content,
postID,
Post,
post: value,
};
const result = onChange(modelFields);
value = result?.post ?? value;
}
if (errors.post?.hasError) {
runValidationTasks(\\"post\\", value);
}
setPost1(value);
}}
onBlur={() => runValidationTasks(\\"post\\", post1)}
errorMessage={errors.post?.errorMessage}
hasError={errors.post?.hasError}
{...getOverrideProps(overrides, \\"post\\")}
>
);
}
"
`;
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\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type CommentUpdateFormInputValues = {
content?: string;
postID?: string;
Post?: any;
post?: string;
};
export declare type CommentUpdateFormValidationValues = {
content?: ValidationFunction;
postID?: ValidationFunction;
Post?: ValidationFunction;
post?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CommentUpdateFormOverridesProps = {
CommentUpdateFormGrid?: PrimitiveOverrideProps;
content?: PrimitiveOverrideProps;
postID?: PrimitiveOverrideProps;
Post?: PrimitiveOverrideProps;
post?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CommentUpdateFormProps = React.PropsWithChildren<{
overrides?: CommentUpdateFormOverridesProps | undefined | null;
} & {
id?: string;
comment?: any;
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 CommentUpdateForm(props: CommentUpdateFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update form with many to many relationship 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import {
Autocomplete,
Badge,
Button,
Divider,
Flex,
Grid,
Icon,
ScrollView,
Text,
useTheme,
} from \\"@aws-amplify/ui-react\\";
import { getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { fetchByPath, validateField } from \\"./utils\\";
import {
getClass,
listStudentClasses,
listStudents,
studentClassByClassId,
} from \\"../graphql/queries\\";
import { API } from \\"aws-amplify\\";
import {
createStudentClass,
deleteStudentClass,
updateClass,
} 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 ClassUpdateForm(props) {
const {
id: idProp,
class: classModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
students: [],
};
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 = () => {
const cleanValues = classRecord
? { ...initialValues, ...classRecord, students: linkedStudents }
: initialValues;
setStudents(cleanValues.students ?? []);
setCurrentStudentsValue(undefined);
setCurrentStudentsDisplayValue(\\"\\");
setErrors({});
};
const [classRecord, setClassRecord] = React.useState(classModelProp);
const [linkedStudents, setLinkedStudents] = React.useState([]);
const canUnlinkStudents = false;
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getClass,
variables: { id: idProp },
})
)?.data?.getClass
: classModelProp;
const linkedStudents = record
? (
await API.graphql({
query: studentClassByClassId,
variables: {
classId: record.id,
},
})
).data.studentClassByClassId.items.map((t) => t.student)
: [];
setLinkedStudents(linkedStudents);
setClassRecord(record);
};
queryData();
}, [idProp, classModelProp]);
React.useEffect(resetStateValues, [classRecord, linkedStudents]);
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?.id,
};
const validations = {
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: [{ id: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listStudents,
variables,
})
)?.data?.listStudents?.items;
var loaded = result.filter(
(item) => !studentsIdSet.has(getIDValue.students?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setStudentsRecords(newOptions.slice(0, autocompleteLength));
setStudentsLoading(false);
};
React.useEffect(() => {
fetchStudentsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
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 === \\"\\") {
modelFields[key] = null;
}
});
const promises = [];
const studentsToLinkMap = new Map();
const studentsToUnLinkMap = new Map();
const studentsMap = new Map();
const linkedStudentsMap = new Map();
students.forEach((r) => {
const count = studentsMap.get(getIDValue.students?.(r));
const newCount = count ? count + 1 : 1;
studentsMap.set(getIDValue.students?.(r), newCount);
});
linkedStudents.forEach((r) => {
const count = linkedStudentsMap.get(getIDValue.students?.(r));
const newCount = count ? count + 1 : 1;
linkedStudentsMap.set(getIDValue.students?.(r), newCount);
});
linkedStudentsMap.forEach((count, id) => {
const newCount = studentsMap.get(id);
if (newCount) {
const diffCount = count - newCount;
if (diffCount > 0) {
studentsToUnLinkMap.set(id, diffCount);
}
} else {
studentsToUnLinkMap.set(id, count);
}
});
studentsMap.forEach((count, id) => {
const originalCount = linkedStudentsMap.get(id);
if (originalCount) {
const diffCount = count - originalCount;
if (diffCount > 0) {
studentsToLinkMap.set(id, diffCount);
}
} else {
studentsToLinkMap.set(id, count);
}
});
studentsToUnLinkMap.forEach(async (count, id) => {
const recordKeys = JSON.parse(id);
const studentClassRecords = (
await API.graphql({
query: listStudentClasses,
variables: {
filter: {
and: [
{ studentId: { eq: recordKeys.id } },
{ classId: { eq: classRecord.id } },
],
},
},
})
)?.data?.listStudentClasses?.items;
for (let i = 0; i < count; i++) {
promises.push(
API.graphql({
query: deleteStudentClass,
variables: {
input: {
id: studentClassRecords[i].id,
},
},
})
);
}
});
studentsToLinkMap.forEach((count, id) => {
const studentToLink = studentRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
);
for (let i = count; i > 0; i--) {
promises.push(
API.graphql({
query: createStudentClass,
variables: {
input: {
classId: classRecord.id,
studentId: studentToLink.id,
},
},
})
);
}
});
const modelFieldsToSave = {};
promises.push(
API.graphql({
query: updateClass,
variables: {
input: {
id: classRecord.id,
...modelFieldsToSave,
},
},
})
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"ClassUpdateForm\\")}
{...rest}
>
{
let values = items;
if (onChange) {
const modelFields = {
students: values,
};
const result = onChange(modelFields);
values = result?.students ?? values;
}
setStudents(values);
setCurrentStudentsValue(undefined);
setCurrentStudentsDisplayValue(\\"\\");
}}
currentFieldValue={currentStudentsValue}
label={\\"Students\\"}
items={students}
hasError={errors?.students?.hasError}
errorMessage={errors?.students?.errorMessage}
getBadgeText={getDisplayValue.students}
setFieldValue={(model) => {
setCurrentStudentsDisplayValue(
model ? getDisplayValue.students(model) : \\"\\"
);
setCurrentStudentsValue(model);
}}
inputFieldRef={studentsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.students?.(r),
label: getDisplayValue.students?.(r),
}))}
isLoading={studentsLoading}
onSelect={({ id, label }) => {
setCurrentStudentsValue(
studentsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentStudentsDisplayValue(label);
runValidationTasks(\\"students\\", label);
}}
onClear={() => {
setCurrentStudentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchStudentsRecords(value);
if (errors.students?.hasError) {
runValidationTasks(\\"students\\", value);
}
setCurrentStudentsDisplayValue(value);
setCurrentStudentsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"students\\", currentStudentsDisplayValue)
}
errorMessage={errors.students?.errorMessage}
hasError={errors.students?.hasError}
ref={studentsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"students\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an update form with many to many relationship 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
import { Class, Student } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type ClassUpdateFormInputValues = {
students?: Student[];
};
export declare type ClassUpdateFormValidationValues = {
students?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type ClassUpdateFormOverridesProps = {
ClassUpdateFormGrid?: PrimitiveOverrideProps;
students?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type ClassUpdateFormProps = React.PropsWithChildren<{
overrides?: ClassUpdateFormOverridesProps | undefined | null;
} & {
id?: string;
class?: Class;
onSubmit?: (fields: ClassUpdateFormInputValues) => ClassUpdateFormInputValues;
onSuccess?: (fields: ClassUpdateFormInputValues) => void;
onError?: (fields: ClassUpdateFormInputValues, errorMessage: string) => void;
onChange?: (fields: ClassUpdateFormInputValues) => ClassUpdateFormInputValues;
onValidate?: ClassUpdateFormValidationValues;
} & React.CSSProperties>;
export default function ClassUpdateForm(props: ClassUpdateFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an upgrade form with multiple relationship & cpk 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 {
cPKTeacherCPKClassByCPKTeacherSpecialTeacherId,
getCPKTeacher,
listCPKClasses,
listCPKProjects,
listCPKStudents,
listCPKTeacherCPKClasses,
} from \\"../graphql/queries\\";
import { API } from \\"aws-amplify\\";
import {
createCPKTeacherCPKClass,
deleteCPKTeacherCPKClass,
updateCPKProject,
updateCPKTeacher,
} 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 UpdateCPKTeacherForm(props) {
const {
specialTeacherId: specialTeacherIdProp,
cPKTeacher: cPKTeacherModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
specialTeacherId: \\"\\",
CPKStudent: undefined,
CPKClasses: [],
CPKProjects: [],
};
const [specialTeacherId, setSpecialTeacherId] = React.useState(
initialValues.specialTeacherId
);
const [CPKStudent, setCPKStudent] = React.useState(initialValues.CPKStudent);
const [CPKStudentLoading, setCPKStudentLoading] = React.useState(false);
const [CPKStudentRecords, setCPKStudentRecords] = React.useState([]);
const [CPKClasses, setCPKClasses] = React.useState(initialValues.CPKClasses);
const [CPKClassesLoading, setCPKClassesLoading] = React.useState(false);
const [CPKClassesRecords, setCPKClassesRecords] = React.useState([]);
const [CPKProjects, setCPKProjects] = React.useState(
initialValues.CPKProjects
);
const [CPKProjectsLoading, setCPKProjectsLoading] = React.useState(false);
const [CPKProjectsRecords, setCPKProjectsRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
const cleanValues = cPKTeacherRecord
? {
...initialValues,
...cPKTeacherRecord,
CPKStudent,
CPKClasses: linkedCPKClasses,
CPKProjects: linkedCPKProjects,
}
: initialValues;
setSpecialTeacherId(cleanValues.specialTeacherId);
setCPKStudent(cleanValues.CPKStudent);
setCurrentCPKStudentValue(undefined);
setCurrentCPKStudentDisplayValue(\\"\\");
setCPKClasses(cleanValues.CPKClasses ?? []);
setCurrentCPKClassesValue(undefined);
setCurrentCPKClassesDisplayValue(\\"\\");
setCPKProjects(cleanValues.CPKProjects ?? []);
setCurrentCPKProjectsValue(undefined);
setCurrentCPKProjectsDisplayValue(\\"\\");
setErrors({});
};
const [cPKTeacherRecord, setCPKTeacherRecord] =
React.useState(cPKTeacherModelProp);
const [linkedCPKClasses, setLinkedCPKClasses] = React.useState([]);
const canUnlinkCPKClasses = false;
const [linkedCPKProjects, setLinkedCPKProjects] = React.useState([]);
const canUnlinkCPKProjects = true;
React.useEffect(() => {
const queryData = async () => {
const record = specialTeacherIdProp
? (
await API.graphql({
query: getCPKTeacher,
variables: { id: specialTeacherIdProp },
})
)?.data?.getCPKTeacher
: cPKTeacherModelProp;
const CPKStudentRecord = record ? await record.CPKStudent : undefined;
setCPKStudent(CPKStudentRecord);
const linkedCPKClasses = record
? (
await API.graphql({
query: cPKTeacherCPKClassByCPKTeacherSpecialTeacherId,
variables: {
cPKTeacherSpecialTeacherId: record.specialTeacherId,
},
})
).data.cPKTeacherCPKClassByCPKTeacherSpecialTeacherId.items.map(
(t) => t.cpkClass
)
: [];
setLinkedCPKClasses(linkedCPKClasses);
const linkedCPKProjects = record?.CPKProject?.items ?? [];
setLinkedCPKProjects(linkedCPKProjects);
setCPKTeacherRecord(record);
};
queryData();
}, [specialTeacherIdProp, cPKTeacherModelProp]);
React.useEffect(resetStateValues, [
cPKTeacherRecord,
CPKStudent,
linkedCPKClasses,
linkedCPKProjects,
]);
const [currentCPKStudentDisplayValue, setCurrentCPKStudentDisplayValue] =
React.useState(\\"\\");
const [currentCPKStudentValue, setCurrentCPKStudentValue] =
React.useState(undefined);
const CPKStudentRef = React.createRef();
const [currentCPKClassesDisplayValue, setCurrentCPKClassesDisplayValue] =
React.useState(\\"\\");
const [currentCPKClassesValue, setCurrentCPKClassesValue] =
React.useState(undefined);
const CPKClassesRef = React.createRef();
const [currentCPKProjectsDisplayValue, setCurrentCPKProjectsDisplayValue] =
React.useState(\\"\\");
const [currentCPKProjectsValue, setCurrentCPKProjectsValue] =
React.useState(undefined);
const CPKProjectsRef = React.createRef();
const getIDValue = {
CPKStudent: (r) =>
JSON.stringify({ specialStudentId: r?.specialStudentId }),
CPKClasses: (r) => JSON.stringify({ specialClassId: r?.specialClassId }),
CPKProjects: (r) =>
JSON.stringify({ specialProjectId: r?.specialProjectId }),
};
const CPKStudentIdSet = new Set(
Array.isArray(CPKStudent)
? CPKStudent.map((r) => getIDValue.CPKStudent?.(r))
: getIDValue.CPKStudent?.(CPKStudent)
);
const CPKClassesIdSet = new Set(
Array.isArray(CPKClasses)
? CPKClasses.map((r) => getIDValue.CPKClasses?.(r))
: getIDValue.CPKClasses?.(CPKClasses)
);
const CPKProjectsIdSet = new Set(
Array.isArray(CPKProjects)
? CPKProjects.map((r) => getIDValue.CPKProjects?.(r))
: getIDValue.CPKProjects?.(CPKProjects)
);
const getDisplayValue = {
CPKStudent: (r) => r?.specialStudentId,
CPKClasses: (r) => r?.specialClassId,
CPKProjects: (r) => r?.specialProjectId,
};
const validations = {
specialTeacherId: [{ type: \\"Required\\" }],
CPKStudent: [],
CPKClasses: [],
CPKProjects: [],
};
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 fetchCPKStudentRecords = async (value) => {
setCPKStudentLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: { or: [{ specialStudentId: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCPKStudents,
variables,
})
)?.data?.listCPKStudents?.items;
var loaded = result.filter(
(item) => !CPKStudentIdSet.has(getIDValue.CPKStudent?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCPKStudentRecords(newOptions.slice(0, autocompleteLength));
setCPKStudentLoading(false);
};
const fetchCPKClassesRecords = async (value) => {
setCPKClassesLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: { or: [{ specialClassId: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCPKClasses,
variables,
})
)?.data?.listCPKClasses?.items;
var loaded = result.filter(
(item) => !CPKClassesIdSet.has(getIDValue.CPKClasses?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCPKClassesRecords(newOptions.slice(0, autocompleteLength));
setCPKClassesLoading(false);
};
const fetchCPKProjectsRecords = async (value) => {
setCPKProjectsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: { or: [{ specialProjectId: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCPKProjects,
variables,
})
)?.data?.listCPKProjects?.items;
var loaded = result.filter(
(item) => !CPKProjectsIdSet.has(getIDValue.CPKProjects?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCPKProjectsRecords(newOptions.slice(0, autocompleteLength));
setCPKProjectsLoading(false);
};
React.useEffect(() => {
fetchCPKStudentRecords(\\"\\");
fetchCPKClassesRecords(\\"\\");
fetchCPKProjectsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
specialTeacherId,
CPKStudent,
CPKClasses,
CPKProjects,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const promises = [];
const cPKClassesToLinkMap = new Map();
const cPKClassesToUnLinkMap = new Map();
const cPKClassesMap = new Map();
const linkedCPKClassesMap = new Map();
CPKClasses.forEach((r) => {
const count = cPKClassesMap.get(getIDValue.CPKClasses?.(r));
const newCount = count ? count + 1 : 1;
cPKClassesMap.set(getIDValue.CPKClasses?.(r), newCount);
});
linkedCPKClasses.forEach((r) => {
const count = linkedCPKClassesMap.get(getIDValue.CPKClasses?.(r));
const newCount = count ? count + 1 : 1;
linkedCPKClassesMap.set(getIDValue.CPKClasses?.(r), newCount);
});
linkedCPKClassesMap.forEach((count, id) => {
const newCount = cPKClassesMap.get(id);
if (newCount) {
const diffCount = count - newCount;
if (diffCount > 0) {
cPKClassesToUnLinkMap.set(id, diffCount);
}
} else {
cPKClassesToUnLinkMap.set(id, count);
}
});
cPKClassesMap.forEach((count, id) => {
const originalCount = linkedCPKClassesMap.get(id);
if (originalCount) {
const diffCount = count - originalCount;
if (diffCount > 0) {
cPKClassesToLinkMap.set(id, diffCount);
}
} else {
cPKClassesToLinkMap.set(id, count);
}
});
cPKClassesToUnLinkMap.forEach(async (count, id) => {
const recordKeys = JSON.parse(id);
const cPKTeacherCPKClassRecords = (
await API.graphql({
query: listCPKTeacherCPKClasses,
variables: {
filter: {
and: [
{
cPKClassSpecialClassId: {
eq: recordKeys.specialClassId,
},
},
{
cPKTeacherSpecialTeacherId: {
eq: cPKTeacherRecord.specialTeacherId,
},
},
],
},
},
})
)?.data?.listCPKTeacherCPKClasses?.items;
for (let i = 0; i < count; i++) {
promises.push(
API.graphql({
query: deleteCPKTeacherCPKClass,
variables: {
input: {
id: cPKTeacherCPKClassRecords[i].id,
},
},
})
);
}
});
cPKClassesToLinkMap.forEach((count, id) => {
const cPKClassToLink = cPKClassRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
);
for (let i = count; i > 0; i--) {
promises.push(
API.graphql({
query: createCPKTeacherCPKClass,
variables: {
input: {
cPKTeacherSpecialTeacherId:
cPKTeacherRecord.specialTeacherId,
cPKClassSpecialClassId: cPKClassToLink.specialClassId,
},
},
})
);
}
});
const cPKProjectsToLink = [];
const cPKProjectsToUnLink = [];
const cPKProjectsSet = new Set();
const linkedCPKProjectsSet = new Set();
CPKProjects.forEach((r) =>
cPKProjectsSet.add(getIDValue.CPKProjects?.(r))
);
linkedCPKProjects.forEach((r) =>
linkedCPKProjectsSet.add(getIDValue.CPKProjects?.(r))
);
linkedCPKProjects.forEach((r) => {
if (!cPKProjectsSet.has(getIDValue.CPKProjects?.(r))) {
cPKProjectsToUnLink.push(r);
}
});
CPKProjects.forEach((r) => {
if (!linkedCPKProjectsSet.has(getIDValue.CPKProjects?.(r))) {
cPKProjectsToLink.push(r);
}
});
cPKProjectsToUnLink.forEach((original) => {
if (!canUnlinkCPKProjects) {
throw Error(
\`CPKProject \${original.specialProjectId} cannot be unlinked from CPKTeacher because cPKTeacherID is a required field.\`
);
}
promises.push(
API.graphql({
query: updateCPKProject,
variables: {
input: {
specialProjectId: original.specialProjectId,
cPKTeacherID: null,
},
},
})
);
});
cPKProjectsToLink.forEach((original) => {
promises.push(
API.graphql({
query: updateCPKProject,
variables: {
input: {
specialProjectId: original.specialProjectId,
cPKTeacherID: cPKTeacherRecord.specialTeacherId,
},
},
})
);
});
const modelFieldsToSave = {
specialTeacherId: modelFields.specialTeacherId,
CPKStudent: modelFields.CPKStudent,
};
promises.push(
API.graphql({
query: updateCPKTeacher,
variables: {
input: {
specialTeacherId: cPKTeacherRecord.specialTeacherId,
...modelFieldsToSave,
},
},
})
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"UpdateCPKTeacherForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
specialTeacherId: value,
CPKStudent,
CPKClasses,
CPKProjects,
};
const result = onChange(modelFields);
value = result?.specialTeacherId ?? value;
}
if (errors.specialTeacherId?.hasError) {
runValidationTasks(\\"specialTeacherId\\", value);
}
setSpecialTeacherId(value);
}}
onBlur={() => runValidationTasks(\\"specialTeacherId\\", specialTeacherId)}
errorMessage={errors.specialTeacherId?.errorMessage}
hasError={errors.specialTeacherId?.hasError}
{...getOverrideProps(overrides, \\"specialTeacherId\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
specialTeacherId,
CPKStudent: value,
CPKClasses,
CPKProjects,
};
const result = onChange(modelFields);
value = result?.CPKStudent ?? value;
}
setCPKStudent(value);
setCurrentCPKStudentValue(undefined);
setCurrentCPKStudentDisplayValue(\\"\\");
}}
currentFieldValue={currentCPKStudentValue}
label={\\"Cpk student\\"}
items={CPKStudent ? [CPKStudent] : []}
hasError={errors?.CPKStudent?.hasError}
errorMessage={errors?.CPKStudent?.errorMessage}
getBadgeText={getDisplayValue.CPKStudent}
setFieldValue={(model) => {
setCurrentCPKStudentDisplayValue(
model ? getDisplayValue.CPKStudent(model) : \\"\\"
);
setCurrentCPKStudentValue(model);
}}
inputFieldRef={CPKStudentRef}
defaultFieldValue={\\"\\"}
>
!CPKStudentIdSet.has(getIDValue.CPKStudent?.(r))
).map((r) => ({
id: getIDValue.CPKStudent?.(r),
label: getDisplayValue.CPKStudent?.(r),
}))}
isLoading={CPKStudentLoading}
onSelect={({ id, label }) => {
setCurrentCPKStudentValue(
CPKStudentRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCPKStudentDisplayValue(label);
runValidationTasks(\\"CPKStudent\\", label);
}}
onClear={() => {
setCurrentCPKStudentDisplayValue(\\"\\");
}}
defaultValue={CPKStudent}
onChange={(e) => {
let { value } = e.target;
fetchCPKStudentRecords(value);
if (errors.CPKStudent?.hasError) {
runValidationTasks(\\"CPKStudent\\", value);
}
setCurrentCPKStudentDisplayValue(value);
setCurrentCPKStudentValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"CPKStudent\\", currentCPKStudentDisplayValue)
}
errorMessage={errors.CPKStudent?.errorMessage}
hasError={errors.CPKStudent?.hasError}
ref={CPKStudentRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CPKStudent\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
specialTeacherId,
CPKStudent,
CPKClasses: values,
CPKProjects,
};
const result = onChange(modelFields);
values = result?.CPKClasses ?? values;
}
setCPKClasses(values);
setCurrentCPKClassesValue(undefined);
setCurrentCPKClassesDisplayValue(\\"\\");
}}
currentFieldValue={currentCPKClassesValue}
label={\\"Cpk classes\\"}
items={CPKClasses}
hasError={errors?.CPKClasses?.hasError}
errorMessage={errors?.CPKClasses?.errorMessage}
getBadgeText={getDisplayValue.CPKClasses}
setFieldValue={(model) => {
setCurrentCPKClassesDisplayValue(
model ? getDisplayValue.CPKClasses(model) : \\"\\"
);
setCurrentCPKClassesValue(model);
}}
inputFieldRef={CPKClassesRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.CPKClasses?.(r),
label: getDisplayValue.CPKClasses?.(r),
}))}
isLoading={CPKClassesLoading}
onSelect={({ id, label }) => {
setCurrentCPKClassesValue(
CPKClassesRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCPKClassesDisplayValue(label);
runValidationTasks(\\"CPKClasses\\", label);
}}
onClear={() => {
setCurrentCPKClassesDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCPKClassesRecords(value);
if (errors.CPKClasses?.hasError) {
runValidationTasks(\\"CPKClasses\\", value);
}
setCurrentCPKClassesDisplayValue(value);
setCurrentCPKClassesValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"CPKClasses\\", currentCPKClassesDisplayValue)
}
errorMessage={errors.CPKClasses?.errorMessage}
hasError={errors.CPKClasses?.hasError}
ref={CPKClassesRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CPKClasses\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
specialTeacherId,
CPKStudent,
CPKClasses,
CPKProjects: values,
};
const result = onChange(modelFields);
values = result?.CPKProjects ?? values;
}
setCPKProjects(values);
setCurrentCPKProjectsValue(undefined);
setCurrentCPKProjectsDisplayValue(\\"\\");
}}
currentFieldValue={currentCPKProjectsValue}
label={\\"Cpk projects\\"}
items={CPKProjects}
hasError={errors?.CPKProjects?.hasError}
errorMessage={errors?.CPKProjects?.errorMessage}
getBadgeText={getDisplayValue.CPKProjects}
setFieldValue={(model) => {
setCurrentCPKProjectsDisplayValue(
model ? getDisplayValue.CPKProjects(model) : \\"\\"
);
setCurrentCPKProjectsValue(model);
}}
inputFieldRef={CPKProjectsRef}
defaultFieldValue={\\"\\"}
>
!CPKProjectsIdSet.has(getIDValue.CPKProjects?.(r))
).map((r) => ({
id: getIDValue.CPKProjects?.(r),
label: getDisplayValue.CPKProjects?.(r),
}))}
isLoading={CPKProjectsLoading}
onSelect={({ id, label }) => {
setCurrentCPKProjectsValue(
CPKProjectsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCPKProjectsDisplayValue(label);
runValidationTasks(\\"CPKProjects\\", label);
}}
onClear={() => {
setCurrentCPKProjectsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCPKProjectsRecords(value);
if (errors.CPKProjects?.hasError) {
runValidationTasks(\\"CPKProjects\\", value);
}
setCurrentCPKProjectsDisplayValue(value);
setCurrentCPKProjectsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"CPKProjects\\", currentCPKProjectsDisplayValue)
}
errorMessage={errors.CPKProjects?.errorMessage}
hasError={errors.CPKProjects?.hasError}
ref={CPKProjectsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CPKProjects\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should generate an upgrade form with multiple relationship & cpk 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
import { CPKClass, CPKProject, CPKStudent, CPKTeacher } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type UpdateCPKTeacherFormInputValues = {
specialTeacherId?: string;
CPKStudent?: CPKStudent;
CPKClasses?: CPKClass[];
CPKProjects?: CPKProject[];
};
export declare type UpdateCPKTeacherFormValidationValues = {
specialTeacherId?: ValidationFunction;
CPKStudent?: ValidationFunction;
CPKClasses?: ValidationFunction;
CPKProjects?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type UpdateCPKTeacherFormOverridesProps = {
UpdateCPKTeacherFormGrid?: PrimitiveOverrideProps;
specialTeacherId?: PrimitiveOverrideProps;
CPKStudent?: PrimitiveOverrideProps;
CPKClasses?: PrimitiveOverrideProps;
CPKProjects?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type UpdateCPKTeacherFormProps = React.PropsWithChildren<{
overrides?: UpdateCPKTeacherFormOverridesProps | undefined | null;
} & {
specialTeacherId?: string;
cPKTeacher?: CPKTeacher;
onSubmit?: (fields: UpdateCPKTeacherFormInputValues) => UpdateCPKTeacherFormInputValues;
onSuccess?: (fields: UpdateCPKTeacherFormInputValues) => void;
onError?: (fields: UpdateCPKTeacherFormInputValues, errorMessage: string) => void;
onChange?: (fields: UpdateCPKTeacherFormInputValues) => UpdateCPKTeacherFormInputValues;
onValidate?: UpdateCPKTeacherFormValidationValues;
} & React.CSSProperties>;
export default function UpdateCPKTeacherForm(props: UpdateCPKTeacherFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for child of 1:m 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 { listCompositeDogs } from \\"../graphql/queries\\";
import { createCompositeToy } 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 CreateCompositeToyForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
kind: \\"\\",
color: \\"\\",
compositeDogCompositeToysName: undefined,
compositeDogCompositeToysDescription: undefined,
};
const [kind, setKind] = React.useState(initialValues.kind);
const [color, setColor] = React.useState(initialValues.color);
const [compositeDogCompositeToysName, setCompositeDogCompositeToysName] =
React.useState(initialValues.compositeDogCompositeToysName);
const [
compositeDogCompositeToysNameLoading,
setCompositeDogCompositeToysNameLoading,
] = React.useState(false);
const [
compositeDogCompositeToysNameRecords,
setCompositeDogCompositeToysNameRecords,
] = React.useState([]);
const [
compositeDogCompositeToysDescription,
setCompositeDogCompositeToysDescription,
] = React.useState(initialValues.compositeDogCompositeToysDescription);
const [
compositeDogCompositeToysDescriptionLoading,
setCompositeDogCompositeToysDescriptionLoading,
] = React.useState(false);
const [
compositeDogCompositeToysDescriptionRecords,
setCompositeDogCompositeToysDescriptionRecords,
] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
setKind(initialValues.kind);
setColor(initialValues.color);
setCompositeDogCompositeToysName(
initialValues.compositeDogCompositeToysName
);
setCurrentCompositeDogCompositeToysNameValue(undefined);
setCurrentCompositeDogCompositeToysNameDisplayValue(\\"\\");
setCompositeDogCompositeToysDescription(
initialValues.compositeDogCompositeToysDescription
);
setCurrentCompositeDogCompositeToysDescriptionValue(undefined);
setCurrentCompositeDogCompositeToysDescriptionDisplayValue(\\"\\");
setErrors({});
};
const [
currentCompositeDogCompositeToysNameDisplayValue,
setCurrentCompositeDogCompositeToysNameDisplayValue,
] = React.useState(\\"\\");
const [
currentCompositeDogCompositeToysNameValue,
setCurrentCompositeDogCompositeToysNameValue,
] = React.useState(undefined);
const compositeDogCompositeToysNameRef = React.createRef();
const [
currentCompositeDogCompositeToysDescriptionDisplayValue,
setCurrentCompositeDogCompositeToysDescriptionDisplayValue,
] = React.useState(\\"\\");
const [
currentCompositeDogCompositeToysDescriptionValue,
setCurrentCompositeDogCompositeToysDescriptionValue,
] = React.useState(undefined);
const compositeDogCompositeToysDescriptionRef = React.createRef();
const getDisplayValue = {
compositeDogCompositeToysName: (r) => r?.name,
compositeDogCompositeToysDescription: (r) => r?.description,
};
const validations = {
kind: [{ type: \\"Required\\" }],
color: [{ type: \\"Required\\" }],
compositeDogCompositeToysName: [],
compositeDogCompositeToysDescription: [],
};
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 fetchCompositeDogCompositeToysNameRecords = async (value) => {
setCompositeDogCompositeToysNameLoading(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: listCompositeDogs,
variables,
})
)?.data?.listCompositeDogs?.items;
var loaded = result.filter(
(item) => compositeDogCompositeToysName !== item.id
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeDogCompositeToysNameRecords(
newOptions.slice(0, autocompleteLength)
);
setCompositeDogCompositeToysNameLoading(false);
};
const fetchCompositeDogCompositeToysDescriptionRecords = async (value) => {
setCompositeDogCompositeToysDescriptionLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: { or: [{ description: { contains: value } }] },
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCompositeDogs,
variables,
})
)?.data?.listCompositeDogs?.items;
var loaded = result.filter(
(item) => compositeDogCompositeToysDescription !== item.id
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeDogCompositeToysDescriptionRecords(
newOptions.slice(0, autocompleteLength)
);
setCompositeDogCompositeToysDescriptionLoading(false);
};
React.useEffect(() => {
fetchCompositeDogCompositeToysNameRecords(\\"\\");
fetchCompositeDogCompositeToysDescriptionRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
kind,
color,
compositeDogCompositeToysName,
compositeDogCompositeToysDescription,
};
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)
)
);
return promises;
}
promises.push(
runValidationTasks(fieldName, modelFields[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 === \\"\\") {
modelFields[key] = null;
}
});
await API.graphql({
query: createCompositeToy,
variables: {
input: {
...modelFields,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CreateCompositeToyForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
kind: value,
color,
compositeDogCompositeToysName,
compositeDogCompositeToysDescription,
};
const result = onChange(modelFields);
value = result?.kind ?? value;
}
if (errors.kind?.hasError) {
runValidationTasks(\\"kind\\", value);
}
setKind(value);
}}
onBlur={() => runValidationTasks(\\"kind\\", kind)}
errorMessage={errors.kind?.errorMessage}
hasError={errors.kind?.hasError}
{...getOverrideProps(overrides, \\"kind\\")}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
kind,
color: value,
compositeDogCompositeToysName,
compositeDogCompositeToysDescription,
};
const result = onChange(modelFields);
value = result?.color ?? value;
}
if (errors.color?.hasError) {
runValidationTasks(\\"color\\", value);
}
setColor(value);
}}
onBlur={() => runValidationTasks(\\"color\\", color)}
errorMessage={errors.color?.errorMessage}
hasError={errors.color?.hasError}
{...getOverrideProps(overrides, \\"color\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
kind,
color,
compositeDogCompositeToysName: value,
compositeDogCompositeToysDescription,
};
const result = onChange(modelFields);
value = result?.compositeDogCompositeToysName ?? value;
}
setCompositeDogCompositeToysName(value);
setCurrentCompositeDogCompositeToysNameValue(undefined);
}}
currentFieldValue={currentCompositeDogCompositeToysNameValue}
label={\\"Composite dog composite toys name\\"}
items={
compositeDogCompositeToysName ? [compositeDogCompositeToysName] : []
}
hasError={errors?.compositeDogCompositeToysName?.hasError}
errorMessage={errors?.compositeDogCompositeToysName?.errorMessage}
getBadgeText={(value) =>
value
? getDisplayValue.compositeDogCompositeToysName(
compositeDogCompositeToysNameRecords.find(
(r) => r.name === value
)
)
: \\"\\"
}
setFieldValue={(value) => {
setCurrentCompositeDogCompositeToysNameDisplayValue(
value
? getDisplayValue.compositeDogCompositeToysName(
compositeDogCompositeToysNameRecords.find(
(r) => r.name === value
)
)
: \\"\\"
);
setCurrentCompositeDogCompositeToysNameValue(value);
}}
inputFieldRef={compositeDogCompositeToysNameRef}
defaultFieldValue={\\"\\"}
>
arr.findIndex((member) => member?.name === r?.name) === i
)
.map((r) => ({
id: r?.name,
label: getDisplayValue.compositeDogCompositeToysName?.(r),
}))}
isLoading={compositeDogCompositeToysNameLoading}
onSelect={({ id, label }) => {
setCurrentCompositeDogCompositeToysNameValue(id);
setCurrentCompositeDogCompositeToysNameDisplayValue(label);
runValidationTasks(\\"compositeDogCompositeToysName\\", label);
}}
onClear={() => {
setCurrentCompositeDogCompositeToysNameDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeDogCompositeToysNameRecords(value);
if (errors.compositeDogCompositeToysName?.hasError) {
runValidationTasks(\\"compositeDogCompositeToysName\\", value);
}
setCurrentCompositeDogCompositeToysNameDisplayValue(value);
setCurrentCompositeDogCompositeToysNameValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"compositeDogCompositeToysName\\",
currentCompositeDogCompositeToysNameValue
)
}
errorMessage={errors.compositeDogCompositeToysName?.errorMessage}
hasError={errors.compositeDogCompositeToysName?.hasError}
ref={compositeDogCompositeToysNameRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"compositeDogCompositeToysName\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
kind,
color,
compositeDogCompositeToysName,
compositeDogCompositeToysDescription: value,
};
const result = onChange(modelFields);
value = result?.compositeDogCompositeToysDescription ?? value;
}
setCompositeDogCompositeToysDescription(value);
setCurrentCompositeDogCompositeToysDescriptionValue(undefined);
}}
currentFieldValue={currentCompositeDogCompositeToysDescriptionValue}
label={\\"Composite dog composite toys description\\"}
items={
compositeDogCompositeToysDescription
? [compositeDogCompositeToysDescription]
: []
}
hasError={errors?.compositeDogCompositeToysDescription?.hasError}
errorMessage={
errors?.compositeDogCompositeToysDescription?.errorMessage
}
getBadgeText={(value) =>
value
? getDisplayValue.compositeDogCompositeToysDescription(
compositeDogCompositeToysDescriptionRecords.find(
(r) => r.description === value
)
)
: \\"\\"
}
setFieldValue={(value) => {
setCurrentCompositeDogCompositeToysDescriptionDisplayValue(
value
? getDisplayValue.compositeDogCompositeToysDescription(
compositeDogCompositeToysDescriptionRecords.find(
(r) => r.description === value
)
)
: \\"\\"
);
setCurrentCompositeDogCompositeToysDescriptionValue(value);
}}
inputFieldRef={compositeDogCompositeToysDescriptionRef}
defaultFieldValue={\\"\\"}
>
arr.findIndex(
(member) => member?.description === r?.description
) === i
)
.map((r) => ({
id: r?.description,
label: getDisplayValue.compositeDogCompositeToysDescription?.(r),
}))}
isLoading={compositeDogCompositeToysDescriptionLoading}
onSelect={({ id, label }) => {
setCurrentCompositeDogCompositeToysDescriptionValue(id);
setCurrentCompositeDogCompositeToysDescriptionDisplayValue(label);
runValidationTasks(\\"compositeDogCompositeToysDescription\\", label);
}}
onClear={() => {
setCurrentCompositeDogCompositeToysDescriptionDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeDogCompositeToysDescriptionRecords(value);
if (errors.compositeDogCompositeToysDescription?.hasError) {
runValidationTasks(\\"compositeDogCompositeToysDescription\\", value);
}
setCurrentCompositeDogCompositeToysDescriptionDisplayValue(value);
setCurrentCompositeDogCompositeToysDescriptionValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"compositeDogCompositeToysDescription\\",
currentCompositeDogCompositeToysDescriptionValue
)
}
errorMessage={
errors.compositeDogCompositeToysDescription?.errorMessage
}
hasError={errors.compositeDogCompositeToysDescription?.hasError}
ref={compositeDogCompositeToysDescriptionRef}
labelHidden={true}
{...getOverrideProps(
overrides,
\\"compositeDogCompositeToysDescription\\"
)}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for child of 1:m relationship 2`] = `
"import * as React from \\"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 CreateCompositeToyFormInputValues = {
kind?: string;
color?: string;
compositeDogCompositeToysName?: string;
compositeDogCompositeToysDescription?: string;
};
export declare type CreateCompositeToyFormValidationValues = {
kind?: ValidationFunction;
color?: ValidationFunction;
compositeDogCompositeToysName?: ValidationFunction;
compositeDogCompositeToysDescription?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CreateCompositeToyFormOverridesProps = {
CreateCompositeToyFormGrid?: PrimitiveOverrideProps;
kind?: PrimitiveOverrideProps;
color?: PrimitiveOverrideProps;
compositeDogCompositeToysName?: PrimitiveOverrideProps;
compositeDogCompositeToysDescription?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CreateCompositeToyFormProps = React.PropsWithChildren<{
overrides?: CreateCompositeToyFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: CreateCompositeToyFormInputValues) => CreateCompositeToyFormInputValues;
onSuccess?: (fields: CreateCompositeToyFormInputValues) => void;
onError?: (fields: CreateCompositeToyFormInputValues, errorMessage: string) => void;
onChange?: (fields: CreateCompositeToyFormInputValues) => CreateCompositeToyFormInputValues;
onValidate?: CreateCompositeToyFormValidationValues;
} & React.CSSProperties>;
export default function CreateCompositeToyForm(props: CreateCompositeToyFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for child of 1:m-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 { listOrgs, listPosts, listUsers } from \\"../graphql/queries\\";
import { createComment } 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 CreateCommentForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
post: undefined,
User: undefined,
Org: undefined,
postCommentsId: undefined,
};
const [name, setName] = React.useState(initialValues.name);
const [post, setPost] = React.useState(initialValues.post);
const [postLoading, setPostLoading] = React.useState(false);
const [postRecords, setPostRecords] = React.useState([]);
const [User, setUser] = React.useState(initialValues.User);
const [UserLoading, setUserLoading] = React.useState(false);
const [UserRecords, setUserRecords] = React.useState([]);
const [Org, setOrg] = React.useState(initialValues.Org);
const [OrgLoading, setOrgLoading] = React.useState(false);
const [OrgRecords, setOrgRecords] = React.useState([]);
const [postCommentsId, setPostCommentsId] = React.useState(
initialValues.postCommentsId
);
const [postCommentsIdLoading, setPostCommentsIdLoading] =
React.useState(false);
const [postCommentsIdRecords, setPostCommentsIdRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
setName(initialValues.name);
setPost(initialValues.post);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
setUser(initialValues.User);
setCurrentUserValue(undefined);
setCurrentUserDisplayValue(\\"\\");
setOrg(initialValues.Org);
setCurrentOrgValue(undefined);
setCurrentOrgDisplayValue(\\"\\");
setPostCommentsId(initialValues.postCommentsId);
setCurrentPostCommentsIdValue(undefined);
setCurrentPostCommentsIdDisplayValue(\\"\\");
setErrors({});
};
const [currentPostDisplayValue, setCurrentPostDisplayValue] =
React.useState(\\"\\");
const [currentPostValue, setCurrentPostValue] = React.useState(undefined);
const postRef = React.createRef();
const [currentUserDisplayValue, setCurrentUserDisplayValue] =
React.useState(\\"\\");
const [currentUserValue, setCurrentUserValue] = React.useState(undefined);
const UserRef = React.createRef();
const [currentOrgDisplayValue, setCurrentOrgDisplayValue] =
React.useState(\\"\\");
const [currentOrgValue, setCurrentOrgValue] = React.useState(undefined);
const OrgRef = React.createRef();
const [
currentPostCommentsIdDisplayValue,
setCurrentPostCommentsIdDisplayValue,
] = React.useState(\\"\\");
const [currentPostCommentsIdValue, setCurrentPostCommentsIdValue] =
React.useState(undefined);
const postCommentsIdRef = React.createRef();
const getIDValue = {
post: (r) => JSON.stringify({ id: r?.id }),
User: (r) => JSON.stringify({ id: r?.id }),
Org: (r) => JSON.stringify({ id: r?.id }),
};
const postIdSet = new Set(
Array.isArray(post)
? post.map((r) => getIDValue.post?.(r))
: getIDValue.post?.(post)
);
const UserIdSet = new Set(
Array.isArray(User)
? User.map((r) => getIDValue.User?.(r))
: getIDValue.User?.(User)
);
const OrgIdSet = new Set(
Array.isArray(Org)
? Org.map((r) => getIDValue.Org?.(r))
: getIDValue.Org?.(Org)
);
const getDisplayValue = {
post: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
User: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
Org: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
postCommentsId: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
name: [{ type: \\"Required\\" }],
post: [],
User: [],
Org: [{ type: \\"Required\\", validationMessage: \\"Org is required.\\" }],
postCommentsId: [],
};
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 fetchPostRecords = async (value) => {
setPostLoading(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: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter(
(item) => !postIdSet.has(getIDValue.post?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostRecords(newOptions.slice(0, autocompleteLength));
setPostLoading(false);
};
const fetchUserRecords = async (value) => {
setUserLoading(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: listUsers,
variables,
})
)?.data?.listUsers?.items;
var loaded = result.filter(
(item) => !UserIdSet.has(getIDValue.User?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setUserRecords(newOptions.slice(0, autocompleteLength));
setUserLoading(false);
};
const fetchOrgRecords = async (value) => {
setOrgLoading(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: listOrgs,
variables,
})
)?.data?.listOrgs?.items;
var loaded = result.filter(
(item) => !OrgIdSet.has(getIDValue.Org?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setOrgRecords(newOptions.slice(0, autocompleteLength));
setOrgLoading(false);
};
const fetchPostCommentsIdRecords = async (value) => {
setPostCommentsIdLoading(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: listPosts,
variables,
})
)?.data?.listPosts?.items;
var loaded = result.filter((item) => postCommentsId !== item.id);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setPostCommentsIdRecords(newOptions.slice(0, autocompleteLength));
setPostCommentsIdLoading(false);
};
React.useEffect(() => {
fetchPostRecords(\\"\\");
fetchUserRecords(\\"\\");
fetchOrgRecords(\\"\\");
fetchPostCommentsIdRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
post,
User,
Org,
postCommentsId,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
await API.graphql({
query: createComment,
variables: {
input: {
...modelFields,
},
},
});
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CreateCommentForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
post,
User,
Org,
postCommentsId,
};
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,
post: value,
User,
Org,
postCommentsId,
};
const result = onChange(modelFields);
value = result?.post ?? value;
}
setPost(value);
setCurrentPostValue(undefined);
setCurrentPostDisplayValue(\\"\\");
}}
currentFieldValue={currentPostValue}
label={\\"Post\\"}
items={post ? [post] : []}
hasError={errors?.post?.hasError}
errorMessage={errors?.post?.errorMessage}
getBadgeText={getDisplayValue.post}
setFieldValue={(model) => {
setCurrentPostDisplayValue(model ? getDisplayValue.post(model) : \\"\\");
setCurrentPostValue(model);
}}
inputFieldRef={postRef}
defaultFieldValue={\\"\\"}
>
!postIdSet.has(getIDValue.post?.(r)))
.map((r) => ({
id: getIDValue.post?.(r),
label: getDisplayValue.post?.(r),
}))}
isLoading={postLoading}
onSelect={({ id, label }) => {
setCurrentPostValue(
postRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentPostDisplayValue(label);
runValidationTasks(\\"post\\", label);
}}
onClear={() => {
setCurrentPostDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchPostRecords(value);
if (errors.post?.hasError) {
runValidationTasks(\\"post\\", value);
}
setCurrentPostDisplayValue(value);
setCurrentPostValue(undefined);
}}
onBlur={() => runValidationTasks(\\"post\\", currentPostDisplayValue)}
errorMessage={errors.post?.errorMessage}
hasError={errors.post?.hasError}
ref={postRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"post\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
name,
post,
User: value,
Org,
postCommentsId,
};
const result = onChange(modelFields);
value = result?.User ?? value;
}
setUser(value);
setCurrentUserValue(undefined);
setCurrentUserDisplayValue(\\"\\");
}}
currentFieldValue={currentUserValue}
label={\\"User\\"}
items={User ? [User] : []}
hasError={errors?.User?.hasError}
errorMessage={errors?.User?.errorMessage}
getBadgeText={getDisplayValue.User}
setFieldValue={(model) => {
setCurrentUserDisplayValue(model ? getDisplayValue.User(model) : \\"\\");
setCurrentUserValue(model);
}}
inputFieldRef={UserRef}
defaultFieldValue={\\"\\"}
>
!UserIdSet.has(getIDValue.User?.(r))
).map((r) => ({
id: getIDValue.User?.(r),
label: getDisplayValue.User?.(r),
}))}
isLoading={UserLoading}
onSelect={({ id, label }) => {
setCurrentUserValue(
UserRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentUserDisplayValue(label);
runValidationTasks(\\"User\\", label);
}}
onClear={() => {
setCurrentUserDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchUserRecords(value);
if (errors.User?.hasError) {
runValidationTasks(\\"User\\", value);
}
setCurrentUserDisplayValue(value);
setCurrentUserValue(undefined);
}}
onBlur={() => runValidationTasks(\\"User\\", currentUserDisplayValue)}
errorMessage={errors.User?.errorMessage}
hasError={errors.User?.hasError}
ref={UserRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"User\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
name,
post,
User,
Org: value,
postCommentsId,
};
const result = onChange(modelFields);
value = result?.Org ?? value;
}
setOrg(value);
setCurrentOrgValue(undefined);
setCurrentOrgDisplayValue(\\"\\");
}}
currentFieldValue={currentOrgValue}
label={\\"Org\\"}
items={Org ? [Org] : []}
hasError={errors?.Org?.hasError}
errorMessage={errors?.Org?.errorMessage}
getBadgeText={getDisplayValue.Org}
setFieldValue={(model) => {
setCurrentOrgDisplayValue(model ? getDisplayValue.Org(model) : \\"\\");
setCurrentOrgValue(model);
}}
inputFieldRef={OrgRef}
defaultFieldValue={\\"\\"}
>
!OrgIdSet.has(getIDValue.Org?.(r))
).map((r) => ({
id: getIDValue.Org?.(r),
label: getDisplayValue.Org?.(r),
}))}
isLoading={OrgLoading}
onSelect={({ id, label }) => {
setCurrentOrgValue(
OrgRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentOrgDisplayValue(label);
runValidationTasks(\\"Org\\", label);
}}
onClear={() => {
setCurrentOrgDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchOrgRecords(value);
if (errors.Org?.hasError) {
runValidationTasks(\\"Org\\", value);
}
setCurrentOrgDisplayValue(value);
setCurrentOrgValue(undefined);
}}
onBlur={() => runValidationTasks(\\"Org\\", currentOrgDisplayValue)}
errorMessage={errors.Org?.errorMessage}
hasError={errors.Org?.hasError}
ref={OrgRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"Org\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
name,
post,
User,
Org,
postCommentsId: value,
};
const result = onChange(modelFields);
value = result?.postCommentsId ?? value;
}
setPostCommentsId(value);
setCurrentPostCommentsIdValue(undefined);
}}
currentFieldValue={currentPostCommentsIdValue}
label={\\"Post comments id\\"}
items={postCommentsId ? [postCommentsId] : []}
hasError={errors?.postCommentsId?.hasError}
errorMessage={errors?.postCommentsId?.errorMessage}
getBadgeText={(value) =>
value
? getDisplayValue.postCommentsId(
postCommentsIdRecords.find((r) => r.id === value)
)
: \\"\\"
}
setFieldValue={(value) => {
setCurrentPostCommentsIdDisplayValue(
value
? getDisplayValue.postCommentsId(
postCommentsIdRecords.find((r) => r.id === value)
)
: \\"\\"
);
setCurrentPostCommentsIdValue(value);
}}
inputFieldRef={postCommentsIdRef}
defaultFieldValue={\\"\\"}
>
arr.findIndex((member) => member?.id === r?.id) === i
)
.map((r) => ({
id: r?.id,
label: getDisplayValue.postCommentsId?.(r),
}))}
isLoading={postCommentsIdLoading}
onSelect={({ id, label }) => {
setCurrentPostCommentsIdValue(id);
setCurrentPostCommentsIdDisplayValue(label);
runValidationTasks(\\"postCommentsId\\", label);
}}
onClear={() => {
setCurrentPostCommentsIdDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchPostCommentsIdRecords(value);
if (errors.postCommentsId?.hasError) {
runValidationTasks(\\"postCommentsId\\", value);
}
setCurrentPostCommentsIdDisplayValue(value);
setCurrentPostCommentsIdValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"postCommentsId\\", currentPostCommentsIdValue)
}
errorMessage={errors.postCommentsId?.errorMessage}
hasError={errors.postCommentsId?.hasError}
ref={postCommentsIdRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"postCommentsId\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for child of 1:m-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 { Org, Post, User } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type CreateCommentFormInputValues = {
name?: string;
post?: Post;
User?: User;
Org?: Org;
postCommentsId?: string;
};
export declare type CreateCommentFormValidationValues = {
name?: ValidationFunction;
post?: ValidationFunction;
User?: ValidationFunction;
Org?: ValidationFunction;
postCommentsId?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CreateCommentFormOverridesProps = {
CreateCommentFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
post?: PrimitiveOverrideProps;
User?: PrimitiveOverrideProps;
Org?: PrimitiveOverrideProps;
postCommentsId?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CreateCommentFormProps = React.PropsWithChildren<{
overrides?: CreateCommentFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: CreateCommentFormInputValues) => CreateCommentFormInputValues;
onSuccess?: (fields: CreateCommentFormInputValues) => void;
onError?: (fields: CreateCommentFormInputValues, errorMessage: string) => void;
onChange?: (fields: CreateCommentFormInputValues) => CreateCommentFormInputValues;
onValidate?: CreateCommentFormValidationValues;
} & React.CSSProperties>;
export default function CreateCommentForm(props: CreateCommentFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for model with composite keys 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 {
listCompositeBowls,
listCompositeOwners,
listCompositeToys,
listCompositeVets,
} from \\"../graphql/queries\\";
import {
createCompositeDog,
createCompositeDogCompositeVet,
updateCompositeDog,
updateCompositeOwner,
} 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 CreateCompositeDogForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
description: \\"\\",
CompositeBowl: undefined,
CompositeOwner: undefined,
CompositeToys: [],
CompositeVets: [],
};
const [name, setName] = React.useState(initialValues.name);
const [description, setDescription] = React.useState(
initialValues.description
);
const [CompositeBowl, setCompositeBowl] = React.useState(
initialValues.CompositeBowl
);
const [CompositeBowlLoading, setCompositeBowlLoading] = React.useState(false);
const [CompositeBowlRecords, setCompositeBowlRecords] = React.useState([]);
const [CompositeOwner, setCompositeOwner] = React.useState(
initialValues.CompositeOwner
);
const [CompositeOwnerLoading, setCompositeOwnerLoading] =
React.useState(false);
const [CompositeOwnerRecords, setCompositeOwnerRecords] = React.useState([]);
const [CompositeToys, setCompositeToys] = React.useState(
initialValues.CompositeToys
);
const [CompositeToysLoading, setCompositeToysLoading] = React.useState(false);
const [CompositeToysRecords, setCompositeToysRecords] = React.useState([]);
const [CompositeVets, setCompositeVets] = React.useState(
initialValues.CompositeVets
);
const [CompositeVetsLoading, setCompositeVetsLoading] = React.useState(false);
const [CompositeVetsRecords, setCompositeVetsRecords] = React.useState([]);
const autocompleteLength = 10;
const [errors, setErrors] = React.useState({});
const resetStateValues = () => {
setName(initialValues.name);
setDescription(initialValues.description);
setCompositeBowl(initialValues.CompositeBowl);
setCurrentCompositeBowlValue(undefined);
setCurrentCompositeBowlDisplayValue(\\"\\");
setCompositeOwner(initialValues.CompositeOwner);
setCurrentCompositeOwnerValue(undefined);
setCurrentCompositeOwnerDisplayValue(\\"\\");
setCompositeToys(initialValues.CompositeToys);
setCurrentCompositeToysValue(undefined);
setCurrentCompositeToysDisplayValue(\\"\\");
setCompositeVets(initialValues.CompositeVets);
setCurrentCompositeVetsValue(undefined);
setCurrentCompositeVetsDisplayValue(\\"\\");
setErrors({});
};
const [
currentCompositeBowlDisplayValue,
setCurrentCompositeBowlDisplayValue,
] = React.useState(\\"\\");
const [currentCompositeBowlValue, setCurrentCompositeBowlValue] =
React.useState(undefined);
const CompositeBowlRef = React.createRef();
const [
currentCompositeOwnerDisplayValue,
setCurrentCompositeOwnerDisplayValue,
] = React.useState(\\"\\");
const [currentCompositeOwnerValue, setCurrentCompositeOwnerValue] =
React.useState(undefined);
const CompositeOwnerRef = React.createRef();
const [
currentCompositeToysDisplayValue,
setCurrentCompositeToysDisplayValue,
] = React.useState(\\"\\");
const [currentCompositeToysValue, setCurrentCompositeToysValue] =
React.useState(undefined);
const CompositeToysRef = React.createRef();
const [
currentCompositeVetsDisplayValue,
setCurrentCompositeVetsDisplayValue,
] = React.useState(\\"\\");
const [currentCompositeVetsValue, setCurrentCompositeVetsValue] =
React.useState(undefined);
const CompositeVetsRef = React.createRef();
const getIDValue = {
CompositeBowl: (r) => JSON.stringify({ shape: r?.shape, size: r?.size }),
CompositeOwner: (r) =>
JSON.stringify({ lastName: r?.lastName, firstName: r?.firstName }),
CompositeToys: (r) => JSON.stringify({ kind: r?.kind, color: r?.color }),
CompositeVets: (r) =>
JSON.stringify({ specialty: r?.specialty, city: r?.city }),
};
const CompositeBowlIdSet = new Set(
Array.isArray(CompositeBowl)
? CompositeBowl.map((r) => getIDValue.CompositeBowl?.(r))
: getIDValue.CompositeBowl?.(CompositeBowl)
);
const CompositeOwnerIdSet = new Set(
Array.isArray(CompositeOwner)
? CompositeOwner.map((r) => getIDValue.CompositeOwner?.(r))
: getIDValue.CompositeOwner?.(CompositeOwner)
);
const CompositeToysIdSet = new Set(
Array.isArray(CompositeToys)
? CompositeToys.map((r) => getIDValue.CompositeToys?.(r))
: getIDValue.CompositeToys?.(CompositeToys)
);
const CompositeVetsIdSet = new Set(
Array.isArray(CompositeVets)
? CompositeVets.map((r) => getIDValue.CompositeVets?.(r))
: getIDValue.CompositeVets?.(CompositeVets)
);
const getDisplayValue = {
CompositeBowl: (r) => \`\${r?.shape}\${\\"-\\"}\${r?.size}\`,
CompositeOwner: (r) => \`\${r?.lastName}\${\\"-\\"}\${r?.firstName}\`,
CompositeToys: (r) => \`\${r?.kind}\${\\"-\\"}\${r?.color}\`,
CompositeVets: (r) => \`\${r?.specialty}\${\\"-\\"}\${r?.city}\`,
};
const validations = {
name: [{ type: \\"Required\\" }],
description: [{ type: \\"Required\\" }],
CompositeBowl: [],
CompositeOwner: [],
CompositeToys: [],
CompositeVets: [],
};
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 fetchCompositeBowlRecords = async (value) => {
setCompositeBowlLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ shape: { contains: value } }, { size: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCompositeBowls,
variables,
})
)?.data?.listCompositeBowls?.items;
var loaded = result.filter(
(item) => !CompositeBowlIdSet.has(getIDValue.CompositeBowl?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeBowlRecords(newOptions.slice(0, autocompleteLength));
setCompositeBowlLoading(false);
};
const fetchCompositeOwnerRecords = async (value) => {
setCompositeOwnerLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [
{ lastName: { contains: value } },
{ firstName: { contains: value } },
],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCompositeOwners,
variables,
})
)?.data?.listCompositeOwners?.items;
var loaded = result.filter(
(item) => !CompositeOwnerIdSet.has(getIDValue.CompositeOwner?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeOwnerRecords(newOptions.slice(0, autocompleteLength));
setCompositeOwnerLoading(false);
};
const fetchCompositeToysRecords = async (value) => {
setCompositeToysLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [{ kind: { contains: value } }, { color: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCompositeToys,
variables,
})
)?.data?.listCompositeToys?.items;
var loaded = result.filter(
(item) => !CompositeToysIdSet.has(getIDValue.CompositeToys?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeToysRecords(newOptions.slice(0, autocompleteLength));
setCompositeToysLoading(false);
};
const fetchCompositeVetsRecords = async (value) => {
setCompositeVetsLoading(true);
const newOptions = [];
let newNext = \\"\\";
while (newOptions.length < autocompleteLength && newNext != null) {
const variables = {
limit: autocompleteLength * 5,
filter: {
or: [
{ specialty: { contains: value } },
{ city: { contains: value } },
],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listCompositeVets,
variables,
})
)?.data?.listCompositeVets?.items;
var loaded = result.filter(
(item) => !CompositeVetsIdSet.has(getIDValue.CompositeVets?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCompositeVetsRecords(newOptions.slice(0, autocompleteLength));
setCompositeVetsLoading(false);
};
React.useEffect(() => {
fetchCompositeBowlRecords(\\"\\");
fetchCompositeOwnerRecords(\\"\\");
fetchCompositeToysRecords(\\"\\");
fetchCompositeVetsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
description,
CompositeBowl,
CompositeOwner,
CompositeToys,
CompositeVets,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
name: modelFields.name,
description: modelFields.description,
CompositeBowl: modelFields.CompositeBowl,
CompositeOwner: modelFields.CompositeOwner,
};
const compositeDog = await API.graphql({
query: createCompositeDog,
variables: {
input: {
...modelFieldsToSave,
},
},
});
const promises = [];
const compositeOwnerToLink = modelFields.CompositeOwner;
if (compositeOwnerToLink) {
promises.push(
API.graphql({
query: updateCompositeOwner,
variables: {
input: {
...CompositeOwner,
CompositeDog: compositeDog,
},
},
})
);
const compositeDogToUnlink =
await compositeOwnerToLink.CompositeDog;
if (compositeDogToUnlink) {
promises.push(
API.graphql({
query: updateCompositeDog,
variables: {
input: {
...compositeDogToUnlink,
CompositeOwner: undefined,
compositeDogCompositeOwnerLastName: undefined,
compositeDogCompositeOwnerFirstName: undefined,
},
},
})
);
}
}
promises.push(
...CompositeToys.reduce((promises, original) => {
promises.push(
API.graphql({
query: updateCompositeDog,
variables: {
input: {
...original,
compositeDogCompositeToysName: compositeDog.name,
compositeDogCompositeToysDescription:
compositeDog.description,
},
},
})
);
return promises;
}, [])
);
promises.push(
...CompositeVets.reduce((promises, compositeVet) => {
promises.push(
API.graphql({
query: createCompositeDogCompositeVet,
variables: {
input: {
compositeDog,
compositeVet,
},
},
})
);
return promises;
}, [])
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CreateCompositeDogForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
description,
CompositeBowl,
CompositeOwner,
CompositeToys,
CompositeVets,
};
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 } = e.target;
if (onChange) {
const modelFields = {
name,
description: value,
CompositeBowl,
CompositeOwner,
CompositeToys,
CompositeVets,
};
const result = onChange(modelFields);
value = result?.description ?? value;
}
if (errors.description?.hasError) {
runValidationTasks(\\"description\\", value);
}
setDescription(value);
}}
onBlur={() => runValidationTasks(\\"description\\", description)}
errorMessage={errors.description?.errorMessage}
hasError={errors.description?.hasError}
{...getOverrideProps(overrides, \\"description\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
name,
description,
CompositeBowl: value,
CompositeOwner,
CompositeToys,
CompositeVets,
};
const result = onChange(modelFields);
value = result?.CompositeBowl ?? value;
}
setCompositeBowl(value);
setCurrentCompositeBowlValue(undefined);
setCurrentCompositeBowlDisplayValue(\\"\\");
}}
currentFieldValue={currentCompositeBowlValue}
label={\\"Composite bowl\\"}
items={CompositeBowl ? [CompositeBowl] : []}
hasError={errors?.CompositeBowl?.hasError}
errorMessage={errors?.CompositeBowl?.errorMessage}
getBadgeText={getDisplayValue.CompositeBowl}
setFieldValue={(model) => {
setCurrentCompositeBowlDisplayValue(
model ? getDisplayValue.CompositeBowl(model) : \\"\\"
);
setCurrentCompositeBowlValue(model);
}}
inputFieldRef={CompositeBowlRef}
defaultFieldValue={\\"\\"}
>
!CompositeBowlIdSet.has(getIDValue.CompositeBowl?.(r))
).map((r) => ({
id: getIDValue.CompositeBowl?.(r),
label: getDisplayValue.CompositeBowl?.(r),
}))}
isLoading={CompositeBowlLoading}
onSelect={({ id, label }) => {
setCurrentCompositeBowlValue(
CompositeBowlRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCompositeBowlDisplayValue(label);
runValidationTasks(\\"CompositeBowl\\", label);
}}
onClear={() => {
setCurrentCompositeBowlDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeBowlRecords(value);
if (errors.CompositeBowl?.hasError) {
runValidationTasks(\\"CompositeBowl\\", value);
}
setCurrentCompositeBowlDisplayValue(value);
setCurrentCompositeBowlValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"CompositeBowl\\",
currentCompositeBowlDisplayValue
)
}
errorMessage={errors.CompositeBowl?.errorMessage}
hasError={errors.CompositeBowl?.hasError}
ref={CompositeBowlRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CompositeBowl\\")}
>
{
let value = items[0];
if (onChange) {
const modelFields = {
name,
description,
CompositeBowl,
CompositeOwner: value,
CompositeToys,
CompositeVets,
};
const result = onChange(modelFields);
value = result?.CompositeOwner ?? value;
}
setCompositeOwner(value);
setCurrentCompositeOwnerValue(undefined);
setCurrentCompositeOwnerDisplayValue(\\"\\");
}}
currentFieldValue={currentCompositeOwnerValue}
label={\\"Composite owner\\"}
items={CompositeOwner ? [CompositeOwner] : []}
hasError={errors?.CompositeOwner?.hasError}
errorMessage={errors?.CompositeOwner?.errorMessage}
getBadgeText={getDisplayValue.CompositeOwner}
setFieldValue={(model) => {
setCurrentCompositeOwnerDisplayValue(
model ? getDisplayValue.CompositeOwner(model) : \\"\\"
);
setCurrentCompositeOwnerValue(model);
}}
inputFieldRef={CompositeOwnerRef}
defaultFieldValue={\\"\\"}
>
!CompositeOwnerIdSet.has(getIDValue.CompositeOwner?.(r))
).map((r) => ({
id: getIDValue.CompositeOwner?.(r),
label: getDisplayValue.CompositeOwner?.(r),
}))}
isLoading={CompositeOwnerLoading}
onSelect={({ id, label }) => {
setCurrentCompositeOwnerValue(
CompositeOwnerRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCompositeOwnerDisplayValue(label);
runValidationTasks(\\"CompositeOwner\\", label);
}}
onClear={() => {
setCurrentCompositeOwnerDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeOwnerRecords(value);
if (errors.CompositeOwner?.hasError) {
runValidationTasks(\\"CompositeOwner\\", value);
}
setCurrentCompositeOwnerDisplayValue(value);
setCurrentCompositeOwnerValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"CompositeOwner\\",
currentCompositeOwnerDisplayValue
)
}
errorMessage={errors.CompositeOwner?.errorMessage}
hasError={errors.CompositeOwner?.hasError}
ref={CompositeOwnerRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CompositeOwner\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
name,
description,
CompositeBowl,
CompositeOwner,
CompositeToys: values,
CompositeVets,
};
const result = onChange(modelFields);
values = result?.CompositeToys ?? values;
}
setCompositeToys(values);
setCurrentCompositeToysValue(undefined);
setCurrentCompositeToysDisplayValue(\\"\\");
}}
currentFieldValue={currentCompositeToysValue}
label={\\"Composite toys\\"}
items={CompositeToys}
hasError={errors?.CompositeToys?.hasError}
errorMessage={errors?.CompositeToys?.errorMessage}
getBadgeText={getDisplayValue.CompositeToys}
setFieldValue={(model) => {
setCurrentCompositeToysDisplayValue(
model ? getDisplayValue.CompositeToys(model) : \\"\\"
);
setCurrentCompositeToysValue(model);
}}
inputFieldRef={CompositeToysRef}
defaultFieldValue={\\"\\"}
>
!CompositeToysIdSet.has(getIDValue.CompositeToys?.(r))
).map((r) => ({
id: getIDValue.CompositeToys?.(r),
label: getDisplayValue.CompositeToys?.(r),
}))}
isLoading={CompositeToysLoading}
onSelect={({ id, label }) => {
setCurrentCompositeToysValue(
CompositeToysRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCompositeToysDisplayValue(label);
runValidationTasks(\\"CompositeToys\\", label);
}}
onClear={() => {
setCurrentCompositeToysDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeToysRecords(value);
if (errors.CompositeToys?.hasError) {
runValidationTasks(\\"CompositeToys\\", value);
}
setCurrentCompositeToysDisplayValue(value);
setCurrentCompositeToysValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"CompositeToys\\",
currentCompositeToysDisplayValue
)
}
errorMessage={errors.CompositeToys?.errorMessage}
hasError={errors.CompositeToys?.hasError}
ref={CompositeToysRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CompositeToys\\")}
>
{
let values = items;
if (onChange) {
const modelFields = {
name,
description,
CompositeBowl,
CompositeOwner,
CompositeToys,
CompositeVets: values,
};
const result = onChange(modelFields);
values = result?.CompositeVets ?? values;
}
setCompositeVets(values);
setCurrentCompositeVetsValue(undefined);
setCurrentCompositeVetsDisplayValue(\\"\\");
}}
currentFieldValue={currentCompositeVetsValue}
label={\\"Composite vets\\"}
items={CompositeVets}
hasError={errors?.CompositeVets?.hasError}
errorMessage={errors?.CompositeVets?.errorMessage}
getBadgeText={getDisplayValue.CompositeVets}
setFieldValue={(model) => {
setCurrentCompositeVetsDisplayValue(
model ? getDisplayValue.CompositeVets(model) : \\"\\"
);
setCurrentCompositeVetsValue(model);
}}
inputFieldRef={CompositeVetsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.CompositeVets?.(r),
label: getDisplayValue.CompositeVets?.(r),
}))}
isLoading={CompositeVetsLoading}
onSelect={({ id, label }) => {
setCurrentCompositeVetsValue(
CompositeVetsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCompositeVetsDisplayValue(label);
runValidationTasks(\\"CompositeVets\\", label);
}}
onClear={() => {
setCurrentCompositeVetsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCompositeVetsRecords(value);
if (errors.CompositeVets?.hasError) {
runValidationTasks(\\"CompositeVets\\", value);
}
setCurrentCompositeVetsDisplayValue(value);
setCurrentCompositeVetsValue(undefined);
}}
onBlur={() =>
runValidationTasks(
\\"CompositeVets\\",
currentCompositeVetsDisplayValue
)
}
errorMessage={errors.CompositeVets?.errorMessage}
hasError={errors.CompositeVets?.hasError}
ref={CompositeVetsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"CompositeVets\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for model with composite keys 2`] = `
"import * as React from \\"react\\";
import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
import { CompositeBowl, CompositeOwner, CompositeToy, CompositeVet } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type CreateCompositeDogFormInputValues = {
name?: string;
description?: string;
CompositeBowl?: CompositeBowl;
CompositeOwner?: CompositeOwner;
CompositeToys?: CompositeToy[];
CompositeVets?: CompositeVet[];
};
export declare type CreateCompositeDogFormValidationValues = {
name?: ValidationFunction;
description?: ValidationFunction;
CompositeBowl?: ValidationFunction;
CompositeOwner?: ValidationFunction;
CompositeToys?: ValidationFunction;
CompositeVets?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CreateCompositeDogFormOverridesProps = {
CreateCompositeDogFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
description?: PrimitiveOverrideProps;
CompositeBowl?: PrimitiveOverrideProps;
CompositeOwner?: PrimitiveOverrideProps;
CompositeToys?: PrimitiveOverrideProps;
CompositeVets?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CreateCompositeDogFormProps = React.PropsWithChildren<{
overrides?: CreateCompositeDogFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: CreateCompositeDogFormInputValues) => CreateCompositeDogFormInputValues;
onSuccess?: (fields: CreateCompositeDogFormInputValues) => void;
onError?: (fields: CreateCompositeDogFormInputValues, errorMessage: string) => void;
onChange?: (fields: CreateCompositeDogFormInputValues) => CreateCompositeDogFormInputValues;
onValidate?: CreateCompositeDogFormValidationValues;
} & React.CSSProperties>;
export default function CreateCompositeDogForm(props: CreateCompositeDogFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for parent of 1:m-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 { listComments } from \\"../graphql/queries\\";
import { createPost, updatePost } 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 CreatePostForm(props) {
const {
clearOnSuccess = true,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
comments: [],
};
const [name, setName] = React.useState(initialValues.name);
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);
setComments(initialValues.comments);
setCurrentCommentsValue(undefined);
setCurrentCommentsDisplayValue(\\"\\");
setErrors({});
};
const [currentCommentsDisplayValue, setCurrentCommentsDisplayValue] =
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?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
name: [],
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);
}
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
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 } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listComments,
variables,
})
)?.data?.listComments?.items;
var loaded = result.filter(
(item) => !commentsIdSet.has(getIDValue.comments?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCommentsRecords(newOptions.slice(0, autocompleteLength));
setCommentsLoading(false);
};
React.useEffect(() => {
fetchCommentsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
comments,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
const modelFieldsToSave = {
name: modelFields.name,
};
const post = await API.graphql({
query: createPost,
variables: {
input: {
...modelFieldsToSave,
},
},
});
const promises = [];
promises.push(
...comments.reduce((promises, original) => {
promises.push(
API.graphql({
query: updatePost,
variables: {
input: {
...original,
postCommentsId: post.id,
post: post,
},
},
})
);
return promises;
}, [])
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
if (clearOnSuccess) {
resetStateValues();
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"CreatePostForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
comments,
};
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,
comments: values,
};
const result = onChange(modelFields);
values = result?.comments ?? 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);
}}
inputFieldRef={commentsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.comments?.(r),
label: getDisplayValue.comments?.(r),
}))}
isLoading={commentsLoading}
onSelect={({ id, label }) => {
setCurrentCommentsValue(
commentsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCommentsDisplayValue(label);
runValidationTasks(\\"comments\\", label);
}}
onClear={() => {
setCurrentCommentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCommentsRecords(value);
if (errors.comments?.hasError) {
runValidationTasks(\\"comments\\", value);
}
setCurrentCommentsDisplayValue(value);
setCurrentCommentsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"comments\\", currentCommentsDisplayValue)
}
errorMessage={errors.comments?.errorMessage}
hasError={errors.comments?.hasError}
ref={commentsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"comments\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a create form for parent of 1:m-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 { Comment } from \\"../API\\";
export declare type ValidationResponse = {
hasError: boolean;
errorMessage?: string;
};
export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
export declare type CreatePostFormInputValues = {
name?: string;
comments?: Comment[];
};
export declare type CreatePostFormValidationValues = {
name?: ValidationFunction;
comments?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type CreatePostFormOverridesProps = {
CreatePostFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps;
comments?: PrimitiveOverrideProps;
} & EscapeHatchProps;
export declare type CreatePostFormProps = React.PropsWithChildren<{
overrides?: CreatePostFormOverridesProps | undefined | null;
} & {
clearOnSuccess?: boolean;
onSubmit?: (fields: CreatePostFormInputValues) => CreatePostFormInputValues;
onSuccess?: (fields: CreatePostFormInputValues) => void;
onError?: (fields: CreatePostFormInputValues, errorMessage: string) => void;
onChange?: (fields: CreatePostFormInputValues) => CreatePostFormInputValues;
onValidate?: CreatePostFormValidationValues;
} & React.CSSProperties>;
export default function CreatePostForm(props: CreatePostFormProps): React.ReactElement;
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a update form for parent of 1:m-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 { getPost, listComments } from \\"../graphql/queries\\";
import { updateComment, updatePost } 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 UpdatePostForm(props) {
const {
id: idProp,
post: postModelProp,
onSuccess,
onError,
onSubmit,
onValidate,
onChange,
overrides,
...rest
} = props;
const initialValues = {
name: \\"\\",
comments: [],
};
const [name, setName] = React.useState(initialValues.name);
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;
setName(cleanValues.name);
setComments(cleanValues.comments ?? []);
setCurrentCommentsValue(undefined);
setCurrentCommentsDisplayValue(\\"\\");
setErrors({});
};
const [postRecord, setPostRecord] = React.useState(postModelProp);
const [linkedComments, setLinkedComments] = React.useState([]);
const canUnlinkComments = true;
React.useEffect(() => {
const queryData = async () => {
const record = idProp
? (
await API.graphql({
query: getPost,
variables: { id: idProp },
})
)?.data?.getPost
: postModelProp;
const linkedComments = record?.Comment?.items ?? [];
setLinkedComments(linkedComments);
setPostRecord(record);
};
queryData();
}, [idProp, postModelProp]);
React.useEffect(resetStateValues, [postRecord, linkedComments]);
const [currentCommentsDisplayValue, setCurrentCommentsDisplayValue] =
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?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
};
const validations = {
name: [],
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);
}
setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
return validationResponse;
};
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 } }, { id: { contains: value } }],
},
};
if (newNext) {
variables[\\"nextToken\\"] = newNext;
}
const result = (
await API.graphql({
query: listComments,
variables,
})
)?.data?.listComments?.items;
var loaded = result.filter(
(item) => !commentsIdSet.has(getIDValue.comments?.(item))
);
newOptions.push(...loaded);
newNext = result.nextToken;
}
setCommentsRecords(newOptions.slice(0, autocompleteLength));
setCommentsLoading(false);
};
React.useEffect(() => {
fetchCommentsRecords(\\"\\");
}, []);
return (
{
event.preventDefault();
let modelFields = {
name,
comments,
};
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 === \\"\\") {
modelFields[key] = null;
}
});
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 postCommentsId is a required field.\`
);
}
promises.push(
API.graphql({
query: updateComment,
variables: {
input: {
id: original.id,
postCommentsId: null,
},
},
})
);
});
commentsToLink.forEach((original) => {
promises.push(
API.graphql({
query: updateComment,
variables: {
input: {
id: original.id,
postCommentsId: postRecord.id,
},
},
})
);
});
const modelFieldsToSave = {
name: modelFields.name,
};
promises.push(
API.graphql({
query: updatePost,
variables: {
input: {
id: postRecord.id,
...modelFieldsToSave,
},
},
})
);
await Promise.all(promises);
if (onSuccess) {
onSuccess(modelFields);
}
} catch (err) {
if (onError) {
onError(modelFields, err.message);
}
}
}}
{...getOverrideProps(overrides, \\"UpdatePostForm\\")}
{...rest}
>
{
let { value } = e.target;
if (onChange) {
const modelFields = {
name: value,
comments,
};
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,
comments: values,
};
const result = onChange(modelFields);
values = result?.comments ?? 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);
}}
inputFieldRef={commentsRef}
defaultFieldValue={\\"\\"}
>
({
id: getIDValue.comments?.(r),
label: getDisplayValue.comments?.(r),
}))}
isLoading={commentsLoading}
onSelect={({ id, label }) => {
setCurrentCommentsValue(
commentsRecords.find((r) =>
Object.entries(JSON.parse(id)).every(
([key, value]) => r[key] === value
)
)
);
setCurrentCommentsDisplayValue(label);
runValidationTasks(\\"comments\\", label);
}}
onClear={() => {
setCurrentCommentsDisplayValue(\\"\\");
}}
onChange={(e) => {
let { value } = e.target;
fetchCommentsRecords(value);
if (errors.comments?.hasError) {
runValidationTasks(\\"comments\\", value);
}
setCurrentCommentsDisplayValue(value);
setCurrentCommentsValue(undefined);
}}
onBlur={() =>
runValidationTasks(\\"comments\\", currentCommentsDisplayValue)
}
errorMessage={errors.comments?.errorMessage}
hasError={errors.comments?.hasError}
ref={commentsRef}
labelHidden={true}
{...getOverrideProps(overrides, \\"comments\\")}
>
);
}
"
`;
exports[`amplify form renderer tests GraphQL form tests should render a update form for parent of 1:m-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 { 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 UpdatePostFormInputValues = {
name?: string;
comments?: Comment[];
};
export declare type UpdatePostFormValidationValues = {
name?: ValidationFunction;
comments?: ValidationFunction;
};
export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
export declare type UpdatePostFormOverridesProps = {
UpdatePostFormGrid?: PrimitiveOverrideProps;
name?: PrimitiveOverrideProps