Skip to content

Commit

Permalink
feat: add graphql support for create form (#1008)
Browse files Browse the repository at this point in the history
  • Loading branch information
rtpascual authored May 12, 2023
1 parent 1990db6 commit 03fde39
Show file tree
Hide file tree
Showing 8 changed files with 742 additions and 13 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
*/
/* eslint-disable no-template-curly-in-string */
import { ImportSource } from '../imports';
import { generateComponentOnlyWithAmplifyFormRenderer, generateWithAmplifyFormRenderer } from './__utils__';
import {
generateComponentOnlyWithAmplifyFormRenderer,
generateWithAmplifyFormRenderer,
rendererConfigWithGraphQL,
} from './__utils__';

describe('amplify form renderer tests', () => {
describe('datastore form tests', () => {
Expand Down Expand Up @@ -672,6 +676,19 @@ describe('amplify form renderer tests', () => {
});
});

describe('GraphQL form tests', () => {
it('should generate a create form', () => {
const { componentText } = generateWithAmplifyFormRenderer(
'forms/post-datastore-create',
'datastore/post',
rendererConfigWithGraphQL,
{ isNonModelSupported: true, isRelationshipSupported: true },
);

expect(componentText).toMatchSnapshot();
});
});

it('should render form for child of bidirectional 1:m when field defined on parent', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/car-datastore-update',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export class AmplifyFormRenderer extends ReactFormTemplateRenderer {
this.component,
this.componentMetadata,
this.importCollection,
this.renderConfig,
parent,
).renderElement(renderChildren);

Expand Down Expand Up @@ -189,6 +190,7 @@ export class AmplifyFormRenderer extends ReactFormTemplateRenderer {
this.component,
this.componentMetadata,
this.importCollection,
this.renderConfig,
parent,
).renderElement(renderChildren);
}
Expand Down
17 changes: 13 additions & 4 deletions packages/codegen-ui-react/lib/amplify-ui-renderers/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ import {
import { factory, JsxAttribute, JsxChild, JsxElement, JsxOpeningElement, Statement, SyntaxKind } from 'typescript';
import { ReactComponentRenderer } from '../react-component-renderer';
import { buildFormLayoutProperties, buildOpeningElementProperties } from '../react-component-render-helper';
import { ImportCollection, ImportSource } from '../imports';
import { buildDataStoreExpression } from '../forms';
import { ImportCollection, ImportSource, ImportValue } from '../imports';
import { buildExpression } from '../forms';
import { onSubmitValidationRun, buildModelFieldObject } from '../forms/form-renderer-helper';
import { hasTokenReference } from '../utils/forms/layout-helpers';
import { resetFunctionCheck } from '../forms/form-renderer-helper/value-props';
import { isModelDataType } from '../forms/form-renderer-helper/render-checkers';
import { replaceEmptyStringStatement } from '../forms/form-renderer-helper/cta-props';
import { ReactRenderConfig } from '../react-render-config';
import { defaultRenderConfig } from '../react-studio-template-renderer-helper';

export default class FormRenderer extends ReactComponentRenderer<BaseComponentProps> {
constructor(
component: StudioComponent | StudioComponentChild,
protected form: StudioForm, // we are passing in form here as it's the top level component
protected componentMetadata: ComponentMetadata,
protected importCollection: ImportCollection,
protected renderConfig: ReactRenderConfig & typeof defaultRenderConfig,
protected parent?: StudioNode,
) {
super(component, componentMetadata, importCollection, parent);
Expand All @@ -54,7 +57,12 @@ export default class FormRenderer extends ReactComponentRenderer<BaseComponentPr
);

this.importCollection.addImport('@aws-amplify/ui-react', this.component.componentType);
if (this.form.dataType.dataSourceType === 'DataStore') {
if (
this.form.dataType.dataSourceType === 'DataStore' &&
this.renderConfig.apiConfiguration?.dataApi === 'GraphQL'
) {
this.importCollection.addMappedImport(ImportValue.API);
} else if (this.form.dataType.dataSourceType === 'DataStore') {
this.importCollection.addImport('aws-amplify', 'DataStore');
}

Expand Down Expand Up @@ -140,13 +148,14 @@ export default class FormRenderer extends ReactComponentRenderer<BaseComponentPr
factory.createBlock(
[
replaceEmptyStringStatement,
...buildDataStoreExpression(
...buildExpression(
formActionType,
dataTypeName,
importedModelName,
formMetadata.fieldConfigs,
dataSchemaMetadata,
this.importCollection,
'apiConfiguration' in this.renderConfig ? this.renderConfig.apiConfiguration?.dataApi : undefined,
),
// call onSuccess hook if it exists
factory.createIfStatement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,51 @@ import { isManyToManyRelationship } from './map-from-fieldConfigs';
import { ImportCollection } from '../../imports';
import { getBiDirectionalRelationshipStatements } from './bidirectional-relationship';
import { generateModelObjectToSave } from './parse-fields';
import { DataApiKind } from '../../react-render-config';

const getRecordCreateDataStoreCallExpression = ({
const getRecordCreateCallExpression = ({
savedObjectName,
importedModelName,
importCollection,
dataApi,
}: {
savedObjectName: string;
importedModelName: string;
importCollection: ImportCollection;
dataApi: DataApiKind;
}) => {
if (dataApi === 'GraphQL') {
const createMutation = `create${importedModelName}`;

return factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createIdentifier('API'), factory.createIdentifier('graphql')),
undefined,
[
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier('query'),
factory.createIdentifier(importCollection.addGraphqlMutationImport(createMutation)),
),
factory.createPropertyAssignment(
factory.createIdentifier('variables'),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier('input'),
factory.createIdentifier(savedObjectName),
),
],
false,
),
),
],
true,
),
],
);
}

return factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createIdentifier('DataStore'), factory.createIdentifier('save')),
undefined,
Expand Down Expand Up @@ -211,13 +248,14 @@ export const replaceEmptyStringStatement = factory.createExpressionStatement(
),
);

export const buildDataStoreExpression = (
export const buildExpression = (
dataStoreActionType: 'update' | 'create',
modelName: string,
importedModelName: string,
fieldConfigs: Record<string, FieldConfigMetadata>,
dataSchema: GenericDataSchema,
importCollection: ImportCollection,
dataApi: DataApiKind = 'DataStore',
): Statement[] => {
const modelFieldsObjectName = 'modelFields';
const modelFieldsObjectToSaveName = 'modelFieldsToSave';
Expand Down Expand Up @@ -314,9 +352,11 @@ export const buildDataStoreExpression = (
);
}

const recordCreateDataStoreCallExpression = getRecordCreateDataStoreCallExpression({
const recordCreateCallExpression = getRecordCreateCallExpression({
savedObjectName,
importedModelName,
importCollection,
dataApi,
});
const genericCreateStatement = relationshipsPromisesAccessStatements.length
? [
Expand All @@ -328,14 +368,14 @@ export const buildDataStoreExpression = (
factory.createIdentifier(savedRecordName),
undefined,
undefined,
factory.createAwaitExpression(recordCreateDataStoreCallExpression),
factory.createAwaitExpression(recordCreateCallExpression),
),
],
NodeFlags.Const,
),
),
]
: [factory.createExpressionStatement(factory.createAwaitExpression(recordCreateDataStoreCallExpression))];
: [factory.createExpressionStatement(factory.createAwaitExpression(recordCreateCallExpression))];

const resolvePromisesStatement = factory.createExpressionStatement(
factory.createAwaitExpression(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
export { onSubmitValidationRun, buildUpdateDatastoreQuery, buildDataStoreExpression } from './cta-props';
export { onSubmitValidationRun, buildUpdateDatastoreQuery, buildExpression } from './cta-props';

export { buildModelFieldObject } from './model-fields';

Expand Down
2 changes: 1 addition & 1 deletion packages/codegen-ui-react/lib/forms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
export { buildDataStoreExpression, addFormAttributes } from './form-renderer-helper';
export { buildExpression, addFormAttributes } from './form-renderer-helper';
export * from './react-form-renderer';
export * from './form-renderer-helper/type-helper';
2 changes: 1 addition & 1 deletion packages/codegen-ui-react/lib/forms/react-form-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ export abstract class ReactFormTemplateRenderer extends StudioTemplateRenderer<
),
];

// add binding elments to statements
// add binding elements to statements
statements.push(
factory.createVariableStatement(
undefined,
Expand Down

0 comments on commit 03fde39

Please sign in to comment.