diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 3c4b1428..560e0775 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -41,8 +41,7 @@ jobs:
- name: Build amplify-cli
working-directory: amplify-cli
run: |
- yarn policies set-version 1.18.0
- yarn --network-concurrency 1
+ yarn install
yarn setup-dev
- name: Install updated codegen libraries
working-directory: amplify-cli/packages/amplify-util-uibuilder
@@ -52,9 +51,9 @@ jobs:
- name: Build amplify-cli with updated codegen libraries
working-directory: amplify-cli
run: |
- yarn policies set-version 1.18.0
- yarn --network-concurrency 1
- yarn dev-build
+ yarn install
+ yarn build
+ echo "$HOME/work/amplify-codegen-ui/amplify-codegen-ui/amplify-cli/.bin" >> $GITHUB_PATH
- name: Create a test react app
run: npx create-react-app e2e-test-app
- name: Install test app dependencies
@@ -112,7 +111,7 @@ jobs:
- name: Install packages
run: npm ci
- name: Lerna bootstrap
- run: lerna bootstrap
+ run: npm run bootstrap
- name: Setup Integration Test
run: npm run integ:setup
- name: Cypress run
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f103f7f9..1deea961 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.14.2](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.1...v2.14.2) (2023-06-06)
+
+### Bug Fixes
+
+- add getOverrideProps to StorageManager ([#1020](https://github.com/aws-amplify/amplify-codegen-ui/issues/1020)) ([8ff282f](https://github.com/aws-amplify/amplify-codegen-ui/commit/8ff282f5a5b2f42dbbb20737d1060a3f5e60cc90))
+
+## [2.14.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.0...v2.14.1) (2023-05-23)
+
+### Bug Fixes
+
+- fix storage field prop import to storagemanager ([#1016](https://github.com/aws-amplify/amplify-codegen-ui/issues/1016)) ([adf26f4](https://github.com/aws-amplify/amplify-codegen-ui/commit/adf26f43fe6823ba15480a81a2513bb2a98bd7b2))
+
+# [2.14.0](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.14.0) (2023-05-22)
+
+### Bug Fixes
+
+- **codegen-ui:** fix multiple has one relationships ([#1005](https://github.com/aws-amplify/amplify-codegen-ui/issues/1005)) ([96b7b9d](https://github.com/aws-amplify/amplify-codegen-ui/commit/96b7b9dc3e9e70e1d8527d9abb59334b0bb56ca7))
+- parse operand value when field is number type ([#1013](https://github.com/aws-amplify/amplify-codegen-ui/issues/1013)) ([ad9ba60](https://github.com/aws-amplify/amplify-codegen-ui/commit/ad9ba606ab381b2b4759f19f9310a0901dd10fa8))
+- upgrade node and pin lerna version in circleci ([#1002](https://github.com/aws-amplify/amplify-codegen-ui/issues/1002)) ([2c70073](https://github.com/aws-amplify/amplify-codegen-ui/commit/2c700733928c28348ab100832b3c9e4fb56ef8a5))
+
+### Features
+
+- exporting processFile to be used in studio ([#1001](https://github.com/aws-amplify/amplify-codegen-ui/issues/1001)) ([ff1ef27](https://github.com/aws-amplify/amplify-codegen-ui/commit/ff1ef272dd0b2192217419300353f8b7388aa26c))
+
## [2.13.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.13.1) (2023-05-02)
### Bug Fixes
diff --git a/lerna.json b/lerna.json
index 141c6f59..980574f9 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,7 +1,7 @@
{
"packages": ["packages/*"],
"exact": true,
- "version": "2.13.1",
+ "version": "2.14.2",
"command": {
"version": {
"message": "chore(release): %s"
diff --git a/package.json b/package.json
index 666d1042..fc5ad20d 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,8 @@
"integ:test": "run-script-os",
"integ:test:default": "./scripts/integ-test.sh",
"integ:test:win32": "scripts\\integ-test.bat",
- "integ:clean": "npx rimraf packages/integration-test"
+ "integ:clean": "npx rimraf packages/integration-test",
+ "bootstrap": "lerna bootstrap"
},
"files": [],
"devDependencies": {
diff --git a/packages/codegen-ui-golden-files/CHANGELOG.md b/packages/codegen-ui-golden-files/CHANGELOG.md
index 39b7e69a..eb7b5a90 100644
--- a/packages/codegen-ui-golden-files/CHANGELOG.md
+++ b/packages/codegen-ui-golden-files/CHANGELOG.md
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.14.2](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.1...v2.14.2) (2023-06-06)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-golden-files
+
+## [2.14.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.0...v2.14.1) (2023-05-23)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-golden-files
+
+# [2.14.0](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.14.0) (2023-05-22)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-golden-files
+
## [2.13.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.13.1) (2023-05-02)
**Note:** Version bump only for package @aws-amplify/codegen-ui-golden-files
diff --git a/packages/codegen-ui-golden-files/package-lock.json b/packages/codegen-ui-golden-files/package-lock.json
index 13f99621..1d307298 100644
--- a/packages/codegen-ui-golden-files/package-lock.json
+++ b/packages/codegen-ui-golden-files/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@aws-amplify/codegen-ui-golden-files",
- "version": "2.13.1",
+ "version": "2.14.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@aws-amplify/codegen-ui-golden-files",
- "version": "2.13.1",
+ "version": "2.14.2",
"license": "Apache-2.0",
"dependencies": {
"@aws-amplify/datastore": "^3.12.12",
diff --git a/packages/codegen-ui-golden-files/package.json b/packages/codegen-ui-golden-files/package.json
index 813209ce..ab3769e2 100644
--- a/packages/codegen-ui-golden-files/package.json
+++ b/packages/codegen-ui-golden-files/package.json
@@ -1,6 +1,6 @@
{
"name": "@aws-amplify/codegen-ui-golden-files",
- "version": "2.13.1",
+ "version": "2.14.2",
"description": "Models of outputs to customer project",
"author": "Amazon Web Services",
"homepage": "https://docs.amplify.aws/",
@@ -11,7 +11,7 @@
"typescript": "^4.8.4"
},
"dependencies": {
- "@aws-amplify/codegen-ui": "2.13.1",
+ "@aws-amplify/codegen-ui": "2.14.2",
"@aws-amplify/datastore": "^3.12.12",
"@aws-amplify/ui-react": "^3.5.7",
"aws-amplify": "^4.3.37",
diff --git a/packages/codegen-ui-react/CHANGELOG.md b/packages/codegen-ui-react/CHANGELOG.md
index b211d7a4..f58efef2 100644
--- a/packages/codegen-ui-react/CHANGELOG.md
+++ b/packages/codegen-ui-react/CHANGELOG.md
@@ -3,6 +3,29 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.14.2](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.1...v2.14.2) (2023-06-06)
+
+### Bug Fixes
+
+- add getOverrideProps to StorageManager ([#1020](https://github.com/aws-amplify/amplify-codegen-ui/issues/1020)) ([8ff282f](https://github.com/aws-amplify/amplify-codegen-ui/commit/8ff282f5a5b2f42dbbb20737d1060a3f5e60cc90))
+
+## [2.14.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.0...v2.14.1) (2023-05-23)
+
+### Bug Fixes
+
+- fix storage field prop import to storagemanager ([#1016](https://github.com/aws-amplify/amplify-codegen-ui/issues/1016)) ([adf26f4](https://github.com/aws-amplify/amplify-codegen-ui/commit/adf26f43fe6823ba15480a81a2513bb2a98bd7b2))
+
+# [2.14.0](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.14.0) (2023-05-22)
+
+### Bug Fixes
+
+- **codegen-ui:** fix multiple has one relationships ([#1005](https://github.com/aws-amplify/amplify-codegen-ui/issues/1005)) ([96b7b9d](https://github.com/aws-amplify/amplify-codegen-ui/commit/96b7b9dc3e9e70e1d8527d9abb59334b0bb56ca7))
+- parse operand value when field is number type ([#1013](https://github.com/aws-amplify/amplify-codegen-ui/issues/1013)) ([ad9ba60](https://github.com/aws-amplify/amplify-codegen-ui/commit/ad9ba606ab381b2b4759f19f9310a0901dd10fa8))
+
+### Features
+
+- exporting processFile to be used in studio ([#1001](https://github.com/aws-amplify/amplify-codegen-ui/issues/1001)) ([ff1ef27](https://github.com/aws-amplify/amplify-codegen-ui/commit/ff1ef272dd0b2192217419300353f8b7388aa26c))
+
## [2.13.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.13.1) (2023-05-02)
**Note:** Version bump only for package @aws-amplify/codegen-ui-react
diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-theme-studio-template-renderer.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-theme-studio-template-renderer.test.ts.snap
index 9ee9d578..cff61c2a 100644
--- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-theme-studio-template-renderer.test.ts.snap
+++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-theme-studio-template-renderer.test.ts.snap
@@ -91,6 +91,12 @@ export default createTheme({
"
`;
+exports[`react theme renderer tests theme should render the theme with ES5 2`] = `
+"declare const _default: any;
+export default _default;
+"
+`;
+
exports[`react theme renderer tests theme should render the theme with TSX 1`] = `
"/* eslint-disable */
import { createTheme } from \\"@aws-amplify/ui-react\\";
diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
index 71bdedf3..f99e3880 100644
--- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
+++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap
@@ -26223,6 +26223,619 @@ export default function SchoolUpdateForm(props: SchoolUpdateFormProps): React.Re
"
`;
+exports[`amplify form renderer tests datastore form tests should generate a update form with hasMany relationship with model name collision 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,
+ useDataStoreBinding,
+} from \\"@aws-amplify/ui-react/internal\\";
+import { School, Student as Student0 } from \\"../models\\";
+import { fetchByPath, validateField } from \\"./utils\\";
+import { DataStore } from \\"aws-amplify\\";
+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 SchoolUpdateForm(props) {
+ const {
+ id: idProp,
+ school: schoolModelProp,
+ onSuccess,
+ onError,
+ onSubmit,
+ onCancel,
+ onValidate,
+ onChange,
+ overrides,
+ ...rest
+ } = props;
+ const initialValues = {
+ name: \\"\\",
+ Student: [],
+ Students: undefined,
+ };
+ const [name, setName] = React.useState(initialValues.name);
+ const [Student, setStudent] = React.useState(initialValues.Student);
+ const [Students, setStudents] = React.useState(initialValues.Students);
+ const [errors, setErrors] = React.useState({});
+ const resetStateValues = () => {
+ const cleanValues = schoolRecord
+ ? { ...initialValues, ...schoolRecord, Student: linkedStudent }
+ : initialValues;
+ setName(cleanValues.name);
+ setStudent(cleanValues.Student ?? []);
+ setCurrentStudentValue(undefined);
+ setCurrentStudentDisplayValue(\\"\\");
+ setStudents(cleanValues.Students);
+ setErrors({});
+ };
+ const [schoolRecord, setSchoolRecord] = React.useState(schoolModelProp);
+ const [linkedStudent, setLinkedStudent] = React.useState([]);
+ const canUnlinkStudent = false;
+ React.useEffect(() => {
+ const queryData = async () => {
+ const record = idProp
+ ? await DataStore.query(School, idProp)
+ : schoolModelProp;
+ setSchoolRecord(record);
+ const linkedStudent = record ? await record.Student.toArray() : [];
+ setLinkedStudent(linkedStudent);
+ };
+ queryData();
+ }, [idProp, schoolModelProp]);
+ React.useEffect(resetStateValues, [schoolRecord, linkedStudent]);
+ const [currentStudentDisplayValue, setCurrentStudentDisplayValue] =
+ React.useState(\\"\\");
+ const [currentStudentValue, setCurrentStudentValue] =
+ React.useState(undefined);
+ const StudentRef = React.createRef();
+ const getIDValue = {
+ Student: (r) => JSON.stringify({ id: r?.id }),
+ };
+ const StudentIdSet = new Set(
+ Array.isArray(Student)
+ ? Student.map((r) => getIDValue.Student?.(r))
+ : getIDValue.Student?.(Student)
+ );
+ const studentRecords = useDataStoreBinding({
+ type: \\"collection\\",
+ model: Student0,
+ }).items;
+ const getDisplayValue = {
+ Student: (r) => \`\${r?.name ? r?.name + \\" - \\" : \\"\\"}\${r?.id}\`,
+ };
+ const validations = {
+ name: [],
+ Student: [],
+ 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;
+ };
+ return (
+ {
+ event.preventDefault();
+ let modelFields = {
+ name,
+ Student,
+ Students,
+ };
+ const validationResponses = await Promise.all(
+ Object.keys(validations).reduce((promises, fieldName) => {
+ if (Array.isArray(modelFields[fieldName])) {
+ promises.push(
+ ...modelFields[fieldName].map((item) =>
+ runValidationTasks(
+ fieldName,
+ item,
+ getDisplayValue[fieldName]
+ )
+ )
+ );
+ return promises;
+ }
+ promises.push(
+ runValidationTasks(
+ fieldName,
+ modelFields[fieldName],
+ getDisplayValue[fieldName]
+ )
+ );
+ return promises;
+ }, [])
+ );
+ if (validationResponses.some((r) => r.hasError)) {
+ return;
+ }
+ if (onSubmit) {
+ modelFields = onSubmit(modelFields);
+ }
+ try {
+ Object.entries(modelFields).forEach(([key, value]) => {
+ if (typeof value === \\"string\\" && value.trim() === \\"\\") {
+ modelFields[key] = undefined;
+ }
+ });
+ const promises = [];
+ const studentToLink = [];
+ const studentToUnLink = [];
+ const studentSet = new Set();
+ const linkedStudentSet = new Set();
+ Student.forEach((r) => studentSet.add(getIDValue.Student?.(r)));
+ linkedStudent.forEach((r) =>
+ linkedStudentSet.add(getIDValue.Student?.(r))
+ );
+ linkedStudent.forEach((r) => {
+ if (!studentSet.has(getIDValue.Student?.(r))) {
+ studentToUnLink.push(r);
+ }
+ });
+ Student.forEach((r) => {
+ if (!linkedStudentSet.has(getIDValue.Student?.(r))) {
+ studentToLink.push(r);
+ }
+ });
+ studentToUnLink.forEach((original) => {
+ if (!canUnlinkStudent) {
+ throw Error(
+ \`Student \${original.id} cannot be unlinked from School because schoolID is a required field.\`
+ );
+ }
+ promises.push(
+ DataStore.save(
+ Student0.copyOf(original, (updated) => {
+ updated.schoolID = null;
+ })
+ )
+ );
+ });
+ studentToLink.forEach((original) => {
+ promises.push(
+ DataStore.save(
+ Student0.copyOf(original, (updated) => {
+ updated.schoolID = schoolRecord.id;
+ })
+ )
+ );
+ });
+ const modelFieldsToSave = {
+ name: modelFields.name,
+ };
+ promises.push(
+ DataStore.save(
+ School.copyOf(schoolRecord, (updated) => {
+ Object.assign(updated, modelFieldsToSave);
+ })
+ )
+ );
+ await Promise.all(promises);
+ if (onSuccess) {
+ onSuccess(modelFields);
+ }
+ } catch (err) {
+ if (onError) {
+ onError(modelFields, err.message);
+ }
+ }
+ }}
+ {...getOverrideProps(overrides, \\"SchoolUpdateForm\\")}
+ {...rest}
+ >
+ {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ name: value,
+ Student,
+ 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,
+ Student: values,
+ Students,
+ };
+ const result = onChange(modelFields);
+ values = result?.Student ?? values;
+ }
+ setStudent(values);
+ setCurrentStudentValue(undefined);
+ setCurrentStudentDisplayValue(\\"\\");
+ }}
+ currentFieldValue={currentStudentValue}
+ label={\\"Student\\"}
+ items={Student}
+ hasError={errors?.Student?.hasError}
+ errorMessage={errors?.Student?.errorMessage}
+ getBadgeText={getDisplayValue.Student}
+ setFieldValue={(model) => {
+ setCurrentStudentDisplayValue(
+ model ? getDisplayValue.Student(model) : \\"\\"
+ );
+ setCurrentStudentValue(model);
+ }}
+ inputFieldRef={StudentRef}
+ defaultFieldValue={\\"\\"}
+ >
+ !StudentIdSet.has(getIDValue.Student?.(r)))
+ .map((r) => ({
+ id: getIDValue.Student?.(r),
+ label: getDisplayValue.Student?.(r),
+ }))}
+ onSelect={({ id, label }) => {
+ setCurrentStudentValue(
+ studentRecords.find((r) =>
+ Object.entries(JSON.parse(id)).every(
+ ([key, value]) => r[key] === value
+ )
+ )
+ );
+ setCurrentStudentDisplayValue(label);
+ runValidationTasks(\\"Student\\", label);
+ }}
+ onClear={() => {
+ setCurrentStudentDisplayValue(\\"\\");
+ }}
+ onChange={(e) => {
+ let { value } = e.target;
+ if (errors.Student?.hasError) {
+ runValidationTasks(\\"Student\\", value);
+ }
+ setCurrentStudentDisplayValue(value);
+ setCurrentStudentValue(undefined);
+ }}
+ onBlur={() =>
+ runValidationTasks(\\"Student\\", currentStudentDisplayValue)
+ }
+ errorMessage={errors.Student?.errorMessage}
+ hasError={errors.Student?.hasError}
+ ref={StudentRef}
+ labelHidden={true}
+ {...getOverrideProps(overrides, \\"Student\\")}
+ >
+
+ arr.findIndex((member) => member?.id === r?.id) === i
+ )
+ .map((r) => ({
+ id: r?.id,
+ label: getDisplayValue.Students?.(r),
+ }))}
+ onSelect={({ id, label }) => {
+ setStudents(id);
+ runValidationTasks(\\"Students\\", id);
+ }}
+ onClear={() => {
+ setStudents(\\"\\");
+ }}
+ defaultValue={Students}
+ onChange={(e) => {
+ let { value } = e.target;
+ if (onChange) {
+ const modelFields = {
+ name,
+ Student,
+ Students: value,
+ };
+ const result = onChange(modelFields);
+ value = result?.Students ?? value;
+ }
+ if (errors.Students?.hasError) {
+ runValidationTasks(\\"Students\\", value);
+ }
+ setStudents(value);
+ }}
+ onBlur={() => runValidationTasks(\\"Students\\", Students)}
+ errorMessage={errors.Students?.errorMessage}
+ hasError={errors.Students?.hasError}
+ labelHidden={false}
+ {...getOverrideProps(overrides, \\"Students\\")}
+ >
+
+
+
+
+
+
+
+
+ );
+}
+"
+`;
+
+exports[`amplify form renderer tests datastore form tests should generate a update form with hasMany relationship with model name collision 2`] = `
+"import * as React from \\"react\\";
+import { AutocompleteProps, GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
+import { School, Student as Student0 } from \\"../models\\";
+export declare type ValidationResponse = {
+ hasError: boolean;
+ errorMessage?: string;
+};
+export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
+export declare type SchoolUpdateFormInputValues = {
+ name?: string;
+ Student?: Student0[];
+ Students?: string;
+};
+export declare type SchoolUpdateFormValidationValues = {
+ name?: ValidationFunction;
+ Student?: ValidationFunction;
+ Students?: ValidationFunction;
+};
+export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
+export declare type SchoolUpdateFormOverridesProps = {
+ SchoolUpdateFormGrid?: PrimitiveOverrideProps;
+ name?: PrimitiveOverrideProps;
+ Student?: PrimitiveOverrideProps;
+ Students?: PrimitiveOverrideProps;
+} & EscapeHatchProps;
+export declare type SchoolUpdateFormProps = React.PropsWithChildren<{
+ overrides?: SchoolUpdateFormOverridesProps | undefined | null;
+} & {
+ id?: string;
+ school?: School;
+ onSubmit?: (fields: SchoolUpdateFormInputValues) => SchoolUpdateFormInputValues;
+ onSuccess?: (fields: SchoolUpdateFormInputValues) => void;
+ onError?: (fields: SchoolUpdateFormInputValues, errorMessage: string) => void;
+ onCancel?: () => void;
+ onChange?: (fields: SchoolUpdateFormInputValues) => SchoolUpdateFormInputValues;
+ onValidate?: SchoolUpdateFormValidationValues;
+} & React.CSSProperties>;
+export default function SchoolUpdateForm(props: SchoolUpdateFormProps): React.ReactElement;
+"
+`;
+
exports[`amplify form renderer tests datastore form tests should generate an update form with belongsTo relationship 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
@@ -32512,10 +33125,10 @@ exports[`amplify form renderer tests forms with StorageField tests should render
"/* eslint-disable */
import * as React from \\"react\\";
import { Button, Flex, Grid, TextField } from \\"@aws-amplify/ui-react\\";
+import { StorageManager } from \\"@aws-amplify/ui-react-storage\\";
import { Field, getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { Product } from \\"../models\\";
import { fetchByPath, processFile, validateField } from \\"./utils\\";
-import { StorageManager } from \\"@aws-amplify/ui-react-storage\\";
import { DataStore } from \\"aws-amplify\\";
export default function CreateProductForm(props) {
const {
@@ -32685,6 +33298,7 @@ export default function CreateProductForm(props) {
showThumbnails={false}
maxFileCount={5}
maxSize={1024}
+ {...getOverrideProps(overrides, \\"imgKeys\\")}
>
)}
@@ -32951,14 +33566,54 @@ export default function UpdateProductForm(props) {
"
`;
+exports[`amplify form renderer tests forms with StorageField tests should render a update form with StorageField 2`] = `
+"import * as React from \\"react\\";
+import { GridProps, TextFieldProps } from \\"@aws-amplify/ui-react\\";
+import { StorageManagerProps } from \\"@aws-amplify/ui-react-storage\\";
+import { EscapeHatchProps } from \\"@aws-amplify/ui-react/internal\\";
+import { Product } from \\"../models\\";
+export declare type ValidationResponse = {
+ hasError: boolean;
+ errorMessage?: string;
+};
+export declare type ValidationFunction = (value: T, validationResponse: ValidationResponse) => ValidationResponse | Promise;
+export declare type UpdateProductFormInputValues = {
+ name?: string;
+ imgKeys?: string[];
+};
+export declare type UpdateProductFormValidationValues = {
+ name?: ValidationFunction;
+ imgKeys?: ValidationFunction;
+};
+export declare type PrimitiveOverrideProps = Partial & React.DOMAttributes;
+export declare type UpdateProductFormOverridesProps = {
+ UpdateProductFormGrid?: PrimitiveOverrideProps;
+ name?: PrimitiveOverrideProps;
+ imgKeys?: PrimitiveOverrideProps;
+} & EscapeHatchProps;
+export declare type UpdateProductFormProps = React.PropsWithChildren<{
+ overrides?: UpdateProductFormOverridesProps | undefined | null;
+} & {
+ id?: string;
+ product?: Product;
+ onSubmit?: (fields: UpdateProductFormInputValues) => UpdateProductFormInputValues;
+ onSuccess?: (fields: UpdateProductFormInputValues) => void;
+ onError?: (fields: UpdateProductFormInputValues, errorMessage: string) => void;
+ onChange?: (fields: UpdateProductFormInputValues) => UpdateProductFormInputValues;
+ onValidate?: UpdateProductFormValidationValues;
+} & React.CSSProperties>;
+export default function UpdateProductForm(props: UpdateProductFormProps): React.ReactElement;
+"
+`;
+
exports[`amplify form renderer tests forms with StorageField tests should render a update form with StorageField on non-array field 1`] = `
"/* eslint-disable */
import * as React from \\"react\\";
import { Button, Flex, Grid, TextField } from \\"@aws-amplify/ui-react\\";
+import { StorageManager } from \\"@aws-amplify/ui-react-storage\\";
import { Field, getOverrideProps } from \\"@aws-amplify/ui-react/internal\\";
import { Product } from \\"../models\\";
import { fetchByPath, processFile, validateField } from \\"./utils\\";
-import { StorageManager } from \\"@aws-amplify/ui-react-storage\\";
import { DataStore } from \\"aws-amplify\\";
export default function UpdateProductForm(props) {
const {
@@ -33149,6 +33804,7 @@ export default function UpdateProductForm(props) {
showThumbnails={false}
maxFileCount={1}
maxSize={1024}
+ {...getOverrideProps(overrides, \\"singleImgKey\\")}
>
)}
diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap
index c0685d6f..aa2d346c 100644
--- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap
+++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap
@@ -1262,7 +1262,7 @@ export default function CollectionOfCustomButtons(
} = props;
const itemsFilterObj = {
and: [
- { field: \\"age\\", operand: \\"10\\", operator: \\"gt\\" },
+ { field: \\"age\\", operand: 10, operator: \\"eq\\" },
{ field: \\"lastName\\", operand: \\"L\\", operator: \\"beginsWith\\" },
],
};
diff --git a/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts b/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts
index 78a17003..54eedc47 100644
--- a/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts
+++ b/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts
@@ -480,3 +480,90 @@ export const compositePersonSchema: GenericDataSchema = getGenericFromDataStore(
codegenVersion: '3.3.2',
version: 'accea0d7a2f24829740c710ceb3264a8',
});
+
+export const userSchema: GenericDataSchema = getGenericFromDataStore({
+ models: {
+ User: {
+ name: 'User',
+ fields: {
+ id: {
+ name: 'id',
+ isArray: false,
+ type: 'ID',
+ isRequired: true,
+ attributes: [],
+ },
+ firstName: {
+ name: 'firstName',
+ isArray: false,
+ type: 'String',
+ isRequired: false,
+ attributes: [],
+ },
+ lastName: {
+ name: 'lastName',
+ isArray: false,
+ type: 'String',
+ isRequired: false,
+ attributes: [],
+ },
+ age: {
+ name: 'age',
+ isArray: false,
+ type: 'Int',
+ isRequired: false,
+ attributes: [],
+ },
+ isLoggedIn: {
+ name: 'isLoggedIn',
+ isArray: false,
+ type: 'Boolean',
+ isRequired: false,
+ attributes: [],
+ },
+ loggedInColor: {
+ name: 'loggedInColor',
+ isArray: false,
+ type: 'String',
+ isRequired: false,
+ attributes: [],
+ },
+ loggedOutColor: {
+ name: 'loggedOutColor',
+ isArray: false,
+ type: 'String',
+ isRequired: false,
+ attributes: [],
+ },
+ createdAt: {
+ name: 'createdAt',
+ isArray: false,
+ type: 'AWSDateTime',
+ isRequired: false,
+ attributes: [],
+ isReadOnly: true,
+ },
+ updatedAt: {
+ name: 'updatedAt',
+ isArray: false,
+ type: 'AWSDateTime',
+ isRequired: false,
+ attributes: [],
+ isReadOnly: true,
+ },
+ },
+ syncable: true,
+ pluralName: 'Users',
+ attributes: [
+ {
+ type: 'model',
+ properties: {},
+ },
+ ],
+ },
+ },
+ enums: {},
+ nonModels: {},
+ codegenVersion: '3.3.2',
+ version: 'accea0d7a2f24829740c710ceb3264a8',
+});
diff --git a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts
index 9b53eab2..c179c35d 100644
--- a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts
@@ -35,6 +35,7 @@ import {
buildConditionalExpression,
hasChildrenProp,
buildConcatExpression,
+ parseNumberOperand,
} from '../react-component-render-helper';
import { assertASTMatchesSnapshot } from './__utils__';
@@ -345,4 +346,15 @@ describe('react-component-render-helper', () => {
assertASTMatchesSnapshot(exp);
});
});
+
+ describe('parseNumberOperand', () => {
+ test('should parse int if field data type is Int', () => {
+ expect(parseNumberOperand('10', { dataType: 'Int', readOnly: false, required: false, isArray: false })).toBe(10);
+ });
+ test('should parse int if field data type is Int', () => {
+ expect(parseNumberOperand('10.01', { dataType: 'Float', readOnly: false, required: false, isArray: false })).toBe(
+ 10.01,
+ );
+ });
+ });
});
diff --git a/packages/codegen-ui-react/lib/__tests__/react-theme-studio-template-renderer.test.ts b/packages/codegen-ui-react/lib/__tests__/react-theme-studio-template-renderer.test.ts
index db76c8d2..3c179cab 100644
--- a/packages/codegen-ui-react/lib/__tests__/react-theme-studio-template-renderer.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/react-theme-studio-template-renderer.test.ts
@@ -25,11 +25,14 @@ function generateWithThemeRenderer(
jsonFile: string,
renderConfig: ReactRenderConfig = {},
options?: ReactThemeStudioTemplateRendererOptions,
-): string {
+) {
const rendererFactory = new StudioTemplateRendererFactory(
(theme: StudioTheme) => new ReactThemeStudioTemplateRenderer(theme, renderConfig, options),
);
- return rendererFactory.buildRenderer(loadSchemaFromJSONFile(jsonFile)).renderComponent().componentText;
+ const { componentText, declaration } = rendererFactory
+ .buildRenderer(loadSchemaFromJSONFile(jsonFile))
+ .renderComponent();
+ return { componentText, declaration };
}
function generateThemeObject(jsonFile: string): any {
@@ -46,19 +49,28 @@ function generateThemeObject(jsonFile: string): any {
describe('react theme renderer tests', () => {
describe('theme', () => {
it('should render the theme', () => {
- expect(generateWithThemeRenderer('theme')).toMatchSnapshot();
+ expect(generateWithThemeRenderer('theme').componentText).toMatchSnapshot();
});
it('should render the theme with TSX', () => {
- expect(generateWithThemeRenderer('theme', { script: ScriptKind.TSX })).toMatchSnapshot();
+ const { componentText, declaration } = generateWithThemeRenderer('theme', { script: ScriptKind.TSX });
+ expect(componentText).toMatchSnapshot();
+ expect(declaration).toBeUndefined();
});
it('should render the theme with ES5', () => {
- expect(generateWithThemeRenderer('theme', { target: ScriptTarget.ES5, script: ScriptKind.JS })).toMatchSnapshot();
+ const { componentText, declaration } = generateWithThemeRenderer('theme', {
+ target: ScriptTarget.ES5,
+ script: ScriptKind.JS,
+ renderTypeDeclarations: true,
+ });
+ expect(componentText).toMatchSnapshot();
+ expect(declaration).toBeDefined();
+ expect(declaration).toMatchSnapshot();
});
it('should render the default theme', () => {
- expect(generateWithThemeRenderer('theme', {}, { renderDefaultTheme: true })).toMatchSnapshot();
+ expect(generateWithThemeRenderer('theme', {}, { renderDefaultTheme: true }).componentText).toMatchSnapshot();
});
});
diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
index 8f03494a..9023a1a3 100644
--- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts
@@ -240,6 +240,35 @@ describe('amplify form renderer tests', () => {
expect(declaration).toMatchSnapshot();
});
+ it('should generate a update form with hasMany relationship with model name collision', () => {
+ const { componentText, declaration } = generateWithAmplifyFormRenderer(
+ 'forms/school-datastore-update',
+ 'datastore/school-student-collision',
+ undefined,
+ { isNonModelSupported: true, isRelationshipSupported: true },
+ );
+ // check nested model is imported
+ expect(componentText).toContain('import { School, Student as Student0 } from "../models";');
+
+ // check binding call is generated
+ expect(componentText).toContain('const studentRecords = useDataStoreBinding({');
+
+ // check lazy load linked data
+ expect(componentText).toContain('const linkedStudent = record ? await record.Student.toArray() : [];');
+
+ // check custom display value is set
+ expect(componentText).toContain('Student: (r) => `${r?.name ? r?.name + " - " : ""}${r?.id}`,');
+
+ // check linked data useState is generate
+ expect(componentText).toContain('const [linkedStudent, setLinkedStudent] = React.useState([]);');
+
+ // check resetStateValues has correct dependencies
+ expect(componentText).toContain('React.useEffect(resetStateValues, [schoolRecord, linkedStudent]);');
+
+ expect(componentText).toMatchSnapshot();
+ expect(declaration).toMatchSnapshot();
+ });
+
it('should render form with a two inputs in row', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/post-datastore-create-row',
@@ -668,12 +697,13 @@ describe('amplify form renderer tests', () => {
});
it('should render a update form with StorageField', () => {
- const { componentText } = generateWithAmplifyFormRenderer(
+ const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/product-datastore-update',
'datastore/product',
undefined,
);
expect(componentText).toMatchSnapshot();
+ expect(declaration).toMatchSnapshot();
});
});
diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
index 691e9530..399514a2 100644
--- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
+++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts
@@ -19,6 +19,7 @@ import {
compositePersonSchema,
generateWithAmplifyRenderer,
rendererConfigWithGraphQL,
+ userSchema,
} from './__utils__';
describe('amplify render tests', () => {
@@ -131,7 +132,12 @@ describe('amplify render tests', () => {
});
it('should render collection with data binding if binding name is items', () => {
- const generatedCode = generateWithAmplifyRenderer('collectionWithBindingItemsName');
+ const generatedCode = generateWithAmplifyRenderer(
+ 'collectionWithBindingItemsName',
+ undefined,
+ undefined,
+ userSchema,
+ );
expect(generatedCode.componentText).toMatchSnapshot();
});
diff --git a/packages/codegen-ui-react/lib/forms/form-renderer-helper/relationship.ts b/packages/codegen-ui-react/lib/forms/form-renderer-helper/relationship.ts
index 889f5b66..07b42342 100644
--- a/packages/codegen-ui-react/lib/forms/form-renderer-helper/relationship.ts
+++ b/packages/codegen-ui-react/lib/forms/form-renderer-helper/relationship.ts
@@ -23,7 +23,7 @@ import {
} from '@aws-amplify/codegen-ui';
import { getRecordsName, getLinkedDataName, buildAccessChain, getCanUnlinkModelName } from './form-state';
import { buildBaseCollectionVariableStatement } from '../../react-studio-template-renderer-helper';
-import { ImportCollection } from '../../imports';
+import { ImportCollection, ImportSource } from '../../imports';
import { lowerCaseFirst, getSetNameIdentifier, capitalizeFirstLetter } from '../../helpers';
import { isManyToManyRelationship } from './map-from-fieldConfigs';
import { extractModelAndKeys, getIDValueCallChain, getMatchEveryModelFieldCallExpression } from './model-values';
@@ -1291,6 +1291,7 @@ export const buildHasManyRelationshipStatements = (
fieldName = fieldConfigMetaData.sanitizedFieldName || fieldName;
const { relatedModelName, relatedModelFields, belongsToFieldOnRelatedModel } =
fieldConfigMetaData.relationship as HasManyRelationshipType;
+ const relatedModelVariableName = importCollection.getMappedAlias(ImportSource.LOCAL_MODELS, relatedModelName);
const linkedDataName = getLinkedDataName(fieldName);
const dataToLink = `${lowerCaseFirst(fieldName)}ToLink`;
const dataToUnLink = `${lowerCaseFirst(fieldName)}ToUnLink`;
@@ -1629,7 +1630,7 @@ export const buildHasManyRelationshipStatements = (
[
factory.createCallExpression(
factory.createPropertyAccessExpression(
- factory.createIdentifier(relatedModelName),
+ factory.createIdentifier(relatedModelVariableName),
factory.createIdentifier('copyOf'),
),
undefined,
@@ -1716,7 +1717,7 @@ export const buildHasManyRelationshipStatements = (
[
factory.createCallExpression(
factory.createPropertyAccessExpression(
- factory.createIdentifier(relatedModelName),
+ factory.createIdentifier(relatedModelVariableName),
factory.createIdentifier('copyOf'),
),
undefined,
diff --git a/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts b/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
index 6ebe10af..70d41002 100644
--- a/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
+++ b/packages/codegen-ui-react/lib/forms/form-renderer-helper/type-helper.ts
@@ -493,7 +493,13 @@ export const buildOverrideTypesBindings = (
if (field.split('.').length > 1 || !isValidVariableName(field)) {
propKey = factory.createStringLiteral(field);
}
- const componentTypePropName = `${formDefinition.elements[field].componentType}Props`;
+ let componentTypePropName = `${formDefinition.elements[field].componentType}Props`;
+ if (formDefinition.elements[field].componentType === 'StorageField') {
+ componentTypePropName = 'StorageManagerProps';
+ importCollection.addImport(ImportSource.REACT_STORAGE, componentTypePropName);
+ } else {
+ importCollection.addImport(ImportSource.UI_REACT, componentTypePropName);
+ }
typeNodes.push(
factory.createPropertySignature(
undefined,
@@ -504,7 +510,6 @@ export const buildOverrideTypesBindings = (
]),
),
);
- importCollection.addImport(ImportSource.UI_REACT, componentTypePropName);
});
});
diff --git a/packages/codegen-ui-react/lib/react-component-render-helper.ts b/packages/codegen-ui-react/lib/react-component-render-helper.ts
index b32553d8..630456c8 100644
--- a/packages/codegen-ui-react/lib/react-component-render-helper.ts
+++ b/packages/codegen-ui-react/lib/react-component-render-helper.ts
@@ -52,7 +52,13 @@ import {
ArrayLiteralExpression,
} from 'typescript';
-import { FormMetadata, FormStyleConfig, StudioFormInputFieldProperty } from '@aws-amplify/codegen-ui/lib/types';
+import {
+ DataFieldDataType,
+ FormMetadata,
+ FormStyleConfig,
+ GenericDataField,
+ StudioFormInputFieldProperty,
+} from '@aws-amplify/codegen-ui/lib/types';
import { ImportCollection } from './imports';
import { json, jsonToLiteral } from './react-studio-template-renderer-helper';
import { getChildPropMappingForComponentName } from './workflow/utils';
@@ -458,6 +464,19 @@ export function getSyntaxKindToken(operator: RelationalOperator): BinaryOperator
}
}
+export function parseNumberOperand(operand: string | number | boolean, dataField: GenericDataField | undefined) {
+ if (dataField) {
+ const numberOperandType: DataFieldDataType[] = ['Int', 'Float'];
+ if (numberOperandType.includes(dataField.dataType)) {
+ const parsedOperand = parseFloat(`${operand}`);
+ if (!Number.isNaN(parsedOperand) && Number.isFinite(parsedOperand)) {
+ return parsedOperand;
+ }
+ }
+ }
+ return operand;
+}
+
export function getConditionalOperandExpression(
operand: string | number | boolean,
operandType: string | undefined,
diff --git a/packages/codegen-ui-react/lib/react-component-renderer.ts b/packages/codegen-ui-react/lib/react-component-renderer.ts
index 530fc0a5..12c4999f 100644
--- a/packages/codegen-ui-react/lib/react-component-renderer.ts
+++ b/packages/codegen-ui-react/lib/react-component-renderer.ts
@@ -89,8 +89,8 @@ export class ReactComponentRenderer extends ComponentRendererBase<
if (this.component.componentType === 'StorageField') {
this.importCollection.addImport(ImportSource.REACT_STORAGE, 'StorageManager');
this.importCollection.addImport(ImportSource.UI_REACT_INTERNAL, 'Field');
+ this.importCollection.addImport(ImportSource.UI_REACT_INTERNAL, ImportValue.GET_OVERRIDE_PROPS);
this.importCollection.addImport(ImportSource.UTILS, 'processFile');
-
return renderStorageFieldComponent(
this.component,
this.componentMetadata,
diff --git a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts
index 66207431..3d3d86ee 100644
--- a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts
+++ b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts
@@ -72,6 +72,7 @@ import {
addBindingPropertiesImports,
getComponentPropName,
getConditionalOperandExpression,
+ parseNumberOperand,
} from './react-component-render-helper';
import {
transpile,
@@ -936,7 +937,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
const modelName = this.importCollection.addModelImport(model);
if (predicate) {
- statements.push(this.buildPredicateDeclaration(propName, predicate));
+ statements.push(this.buildPredicateDeclaration(propName, predicate, model));
statements.push(this.buildCreateDataStorePredicateCall(modelName, propName));
}
if (sort) {
@@ -1257,7 +1258,9 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
* operator: "eq",
* }
*/
- statements.push(this.buildPredicateDeclaration(propName, bindingProperties.predicate));
+ statements.push(
+ this.buildPredicateDeclaration(propName, bindingProperties.predicate, bindingProperties.model),
+ );
statements.push(this.buildCreateDataStorePredicateCall(modelName, propName));
/**
* const buttonColorDataStore = useDataStoreBinding({
@@ -1438,11 +1441,14 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
]);
}
- private predicateToObjectLiteralExpression(predicate: StudioComponentPredicate): ObjectLiteralExpression {
+ private predicateToObjectLiteralExpression(
+ predicate: StudioComponentPredicate,
+ model: string,
+ ): ObjectLiteralExpression {
const { operandType, ...filteredPredicate } = predicate;
if (filteredPredicate.operator === 'between') {
- return this.predicateToObjectLiteralExpression(resolveBetweenPredicateToMultiplePredicates(predicate));
+ return this.predicateToObjectLiteralExpression(resolveBetweenPredicateToMultiplePredicates(predicate), model);
}
const objectAssignments = Object.entries(filteredPredicate).map(([key, value]) => {
@@ -1451,7 +1457,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
factory.createIdentifier(key),
factory.createArrayLiteralExpression(
(predicate[key] as StudioComponentPredicate[]).map(
- (pred: StudioComponentPredicate) => this.predicateToObjectLiteralExpression(pred),
+ (pred: StudioComponentPredicate) => this.predicateToObjectLiteralExpression(pred, model),
false,
),
),
@@ -1460,7 +1466,13 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
if (key === 'operand' && typeof value === 'string') {
return factory.createPropertyAssignment(
factory.createIdentifier(key),
- getConditionalOperandExpression(value, operandType),
+ getConditionalOperandExpression(
+ parseNumberOperand(
+ value,
+ this.componentMetadata.dataSchemaMetadata?.models[model]?.fields[predicate.field || ''],
+ ),
+ operandType,
+ ),
);
}
return factory.createPropertyAssignment(
@@ -1488,7 +1500,11 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
return [];
}
- private buildPredicateDeclaration(name: string, predicate: StudioComponentPredicate): VariableStatement {
+ private buildPredicateDeclaration(
+ name: string,
+ predicate: StudioComponentPredicate,
+ model: string,
+ ): VariableStatement {
return factory.createVariableStatement(
undefined,
factory.createVariableDeclarationList(
@@ -1497,7 +1513,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer
factory.createIdentifier(this.getFilterObjName(name)),
undefined,
undefined,
- this.predicateToObjectLiteralExpression(predicate),
+ this.predicateToObjectLiteralExpression(predicate, model),
),
],
ts.NodeFlags.Const,
diff --git a/packages/codegen-ui-react/lib/react-theme-studio-template-renderer.ts b/packages/codegen-ui-react/lib/react-theme-studio-template-renderer.ts
index 0f5f96ad..6f6d4adc 100644
--- a/packages/codegen-ui-react/lib/react-theme-studio-template-renderer.ts
+++ b/packages/codegen-ui-react/lib/react-theme-studio-template-renderer.ts
@@ -53,6 +53,7 @@ export class ReactThemeStudioTemplateRenderer extends StudioTemplateRenderer<
ReactOutputManager,
{
componentText: string;
+ declaration: string | undefined;
renderComponentToFilesystem: (outputPath: string) => Promise;
}
> {
@@ -86,6 +87,7 @@ export class ReactThemeStudioTemplateRenderer extends StudioTemplateRenderer<
return {
componentText: transpiledComponentText,
+ declaration,
renderComponentToFilesystem: async (outputPath: string) => {
await this.renderComponentToFilesystem(transpiledComponentText)(this.fileName)(outputPath);
if (declaration) {
diff --git a/packages/codegen-ui-react/lib/utils/forms/storage-field-component.ts b/packages/codegen-ui-react/lib/utils/forms/storage-field-component.ts
index ff3ef314..c1a479ad 100644
--- a/packages/codegen-ui-react/lib/utils/forms/storage-field-component.ts
+++ b/packages/codegen-ui-react/lib/utils/forms/storage-field-component.ts
@@ -22,16 +22,7 @@ import {
ComponentMetadata,
isValidVariableName,
} from '@aws-amplify/codegen-ui';
-import {
- factory,
- JsxAttribute,
- JsxAttributeLike,
- JsxChild,
- JsxElement,
- JsxExpression,
- NodeFlags,
- SyntaxKind,
-} from 'typescript';
+import { factory, JsxAttributeLike, JsxChild, JsxElement, JsxExpression, NodeFlags, SyntaxKind } from 'typescript';
import { getDecoratedLabel } from '../../forms/form-renderer-helper';
import { buildStorageManagerOnChangeStatement } from '../../forms/form-renderer-helper/event-handler-props';
import { propertyToExpression } from '../../react-component-render-helper';
@@ -339,8 +330,8 @@ export const renderStorageFieldComponent = (
const lowerCaseDataTypeName = lowerCaseFirst(dataTypeName);
const lowerCaseDataTypeNameRecord = `${lowerCaseDataTypeName}Record`;
const storageManagerComponentName = factory.createIdentifier('StorageManager');
- const storageManagerAttributes: JsxAttribute[] = [];
- const fieldAttributes: JsxAttribute[] = [];
+ const storageManagerAttributes: JsxAttributeLike[] = [];
+ const fieldAttributes: JsxAttributeLike[] = [];
if (componentMetadata.formMetadata) {
const errorKey =
@@ -494,6 +485,15 @@ export const renderStorageFieldComponent = (
}
});
+ storageManagerAttributes.push(
+ factory.createJsxSpreadAttribute(
+ factory.createCallExpression(factory.createIdentifier('getOverrideProps'), undefined, [
+ factory.createIdentifier('overrides'),
+ factory.createStringLiteral(componentName),
+ ]),
+ ),
+ );
+
const storageManager = factory.createJsxElement(
factory.createJsxOpeningElement(
storageManagerComponentName,
diff --git a/packages/codegen-ui-react/package-lock.json b/packages/codegen-ui-react/package-lock.json
index 7fdf9783..da02a68e 100644
--- a/packages/codegen-ui-react/package-lock.json
+++ b/packages/codegen-ui-react/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@aws-amplify/codegen-ui-react",
- "version": "2.13.1",
+ "version": "2.14.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@aws-amplify/codegen-ui-react",
- "version": "2.13.1",
+ "version": "2.14.2",
"license": "Apache-2.0",
"dependencies": {
"@aws-amplify/codegen-ui": "2.13.1",
diff --git a/packages/codegen-ui-react/package.json b/packages/codegen-ui-react/package.json
index 30e3c593..f0a90cb2 100644
--- a/packages/codegen-ui-react/package.json
+++ b/packages/codegen-ui-react/package.json
@@ -1,6 +1,6 @@
{
"name": "@aws-amplify/codegen-ui-react",
- "version": "2.13.1",
+ "version": "2.14.2",
"description": "Amplify UI React code generation implementation",
"author": "Amazon Web Services",
"repository": "https://github.com/aws-amplify/amplify-codegen-ui.git",
@@ -32,7 +32,7 @@
"semver": "^7.3.5"
},
"dependencies": {
- "@aws-amplify/codegen-ui": "2.13.1",
+ "@aws-amplify/codegen-ui": "2.14.2",
"@typescript/vfs": "~1.3.5",
"pluralize": "^8.0.0",
"typescript": "<=4.5.0"
diff --git a/packages/codegen-ui/CHANGELOG.md b/packages/codegen-ui/CHANGELOG.md
index 0fd8e2e6..9c412b5a 100644
--- a/packages/codegen-ui/CHANGELOG.md
+++ b/packages/codegen-ui/CHANGELOG.md
@@ -3,6 +3,21 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.14.2](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.1...v2.14.2) (2023-06-06)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui
+
+## [2.14.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.0...v2.14.1) (2023-05-23)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui
+
+# [2.14.0](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.14.0) (2023-05-22)
+
+### Bug Fixes
+
+- **codegen-ui:** fix multiple has one relationships ([#1005](https://github.com/aws-amplify/amplify-codegen-ui/issues/1005)) ([96b7b9d](https://github.com/aws-amplify/amplify-codegen-ui/commit/96b7b9dc3e9e70e1d8527d9abb59334b0bb56ca7))
+- parse operand value when field is number type ([#1013](https://github.com/aws-amplify/amplify-codegen-ui/issues/1013)) ([ad9ba60](https://github.com/aws-amplify/amplify-codegen-ui/commit/ad9ba606ab381b2b4759f19f9310a0901dd10fa8))
+
## [2.13.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.13.1) (2023-05-02)
**Note:** Version bump only for package @aws-amplify/codegen-ui
diff --git a/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json b/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json
index 9e792eac..3a4a365d 100644
--- a/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json
+++ b/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json
@@ -45,7 +45,7 @@
{
"field": "age",
"operand": "10",
- "operator": "gt"
+ "operator": "eq"
},
{
"field": "lastName",
diff --git a/packages/codegen-ui/example-schemas/datastore/school-student-collision.json b/packages/codegen-ui/example-schemas/datastore/school-student-collision.json
new file mode 100644
index 00000000..d5c4c40e
--- /dev/null
+++ b/packages/codegen-ui/example-schemas/datastore/school-student-collision.json
@@ -0,0 +1,155 @@
+{
+ "models": {
+ "School": {
+ "name": "School",
+ "fields": {
+ "id": {
+ "name": "id",
+ "isArray": false,
+ "type": "ID",
+ "isRequired": true,
+ "attributes": []
+ },
+ "name": {
+ "name": "name",
+ "isArray": false,
+ "type": "String",
+ "isRequired": false,
+ "attributes": []
+ },
+ "Student": {
+ "name": "Student",
+ "isArray": true,
+ "type": {
+ "model": "Student"
+ },
+ "isRequired": false,
+ "attributes": [],
+ "isArrayNullable": true,
+ "association": {
+ "connectionType": "HAS_MANY",
+ "associatedWith": "schoolID"
+ }
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "isArray": false,
+ "type": "AWSDateTime",
+ "isRequired": false,
+ "attributes": [],
+ "isReadOnly": true
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "isArray": false,
+ "type": "AWSDateTime",
+ "isRequired": false,
+ "attributes": [],
+ "isReadOnly": true
+ }
+ },
+ "syncable": true,
+ "pluralName": "Schools",
+ "attributes": [
+ {
+ "type": "model",
+ "properties": {}
+ },
+ {
+ "type": "auth",
+ "properties": {
+ "rules": [
+ {
+ "allow": "public",
+ "operations": [
+ "create",
+ "update",
+ "delete",
+ "read"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ },
+ "Student": {
+ "name": "Student",
+ "fields": {
+ "id": {
+ "name": "id",
+ "isArray": false,
+ "type": "ID",
+ "isRequired": true,
+ "attributes": []
+ },
+ "name": {
+ "name": "name",
+ "isArray": false,
+ "type": "String",
+ "isRequired": false,
+ "attributes": []
+ },
+ "schoolID": {
+ "name": "schoolID",
+ "isArray": false,
+ "type": "ID",
+ "isRequired": true,
+ "attributes": []
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "isArray": false,
+ "type": "AWSDateTime",
+ "isRequired": false,
+ "attributes": [],
+ "isReadOnly": true
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "isArray": false,
+ "type": "AWSDateTime",
+ "isRequired": false,
+ "attributes": [],
+ "isReadOnly": true
+ }
+ },
+ "syncable": true,
+ "pluralName": "Students",
+ "attributes": [
+ {
+ "type": "model",
+ "properties": {}
+ },
+ {
+ "type": "key",
+ "properties": {
+ "name": "bySchool",
+ "fields": [
+ "schoolID"
+ ]
+ }
+ },
+ {
+ "type": "auth",
+ "properties": {
+ "rules": [
+ {
+ "allow": "public",
+ "operations": [
+ "create",
+ "update",
+ "delete",
+ "read"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ "enums": {},
+ "nonModels": {},
+ "version": "5e020d89e4dbb0a2e3b90b771dbcff66"
+}
\ No newline at end of file
diff --git a/packages/codegen-ui/package-lock.json b/packages/codegen-ui/package-lock.json
index 75f1d546..55aac98f 100644
--- a/packages/codegen-ui/package-lock.json
+++ b/packages/codegen-ui/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@aws-amplify/codegen-ui",
- "version": "2.13.1",
+ "version": "2.14.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@aws-amplify/codegen-ui",
- "version": "2.13.1",
+ "version": "2.14.2",
"license": "Apache-2.0",
"dependencies": {
"change-case": "^4.1.2",
diff --git a/packages/codegen-ui/package.json b/packages/codegen-ui/package.json
index 4d58b075..658af593 100644
--- a/packages/codegen-ui/package.json
+++ b/packages/codegen-ui/package.json
@@ -1,6 +1,6 @@
{
"name": "@aws-amplify/codegen-ui",
- "version": "2.13.1",
+ "version": "2.14.2",
"description": "generic component code generation interface definitions",
"author": "Amazon Web Services",
"homepage": "https://docs.amplify.aws/",
diff --git a/packages/test-generator/CHANGELOG.md b/packages/test-generator/CHANGELOG.md
index b1e5719e..8c12fce3 100644
--- a/packages/test-generator/CHANGELOG.md
+++ b/packages/test-generator/CHANGELOG.md
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [2.14.2](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.1...v2.14.2) (2023-06-06)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-test-generator
+
+## [2.14.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.14.0...v2.14.1) (2023-05-23)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-test-generator
+
+# [2.14.0](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.14.0) (2023-05-22)
+
+**Note:** Version bump only for package @aws-amplify/codegen-ui-test-generator
+
## [2.13.1](https://github.com/aws-amplify/amplify-codegen-ui/compare/v2.13.0...v2.13.1) (2023-05-02)
**Note:** Version bump only for package @aws-amplify/codegen-ui-test-generator
diff --git a/packages/test-generator/package-lock.json b/packages/test-generator/package-lock.json
index b70cf80d..c300aabd 100644
--- a/packages/test-generator/package-lock.json
+++ b/packages/test-generator/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@aws-amplify/codegen-ui-test-generator",
- "version": "2.13.1",
+ "version": "2.14.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@aws-amplify/codegen-ui-test-generator",
- "version": "2.13.1",
+ "version": "2.14.2",
"license": "Apache-2.0",
"dependencies": {
"@aws-amplify/codegen-ui": "2.12.2",
diff --git a/packages/test-generator/package.json b/packages/test-generator/package.json
index 8ad8b7b1..b512d8a4 100644
--- a/packages/test-generator/package.json
+++ b/packages/test-generator/package.json
@@ -1,6 +1,6 @@
{
"name": "@aws-amplify/codegen-ui-test-generator",
- "version": "2.13.1",
+ "version": "2.14.2",
"description": "Test generator with sample JSON files",
"author": "Amazon Web Services",
"repository": "https://github.com/aws-amplify/amplify-codegen-ui.git",
@@ -19,8 +19,8 @@
"dist/**"
],
"dependencies": {
- "@aws-amplify/codegen-ui": "2.13.1",
- "@aws-amplify/codegen-ui-react": "2.13.1",
+ "@aws-amplify/codegen-ui": "2.14.2",
+ "@aws-amplify/codegen-ui-react": "2.14.2",
"@types/node": "^15.12.1",
"loglevel": "^1.7.1",
"typescript": "^4.2.4"