diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap index 71fb406c8..789fdb39e 100644 --- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap +++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/react-component-render-helper.test.ts.snap @@ -88,21 +88,45 @@ NodeObject { "dotDotDotToken": undefined, "end": -1, "expression": NodeObject { - "dotDotDotToken": undefined, - "end": -1, - "expression": NodeObject { - "colonToken": TokenObject { + "colonToken": TokenObject { + "end": -1, + "flags": 8, + "kind": 58, + "modifierFlagsCache": 0, + "parent": undefined, + "pos": -1, + "transformFlags": 0, + }, + "condition": NodeObject { + "end": -1, + "expression": NodeObject { "end": -1, "flags": 8, - "kind": 58, + "kind": 219, + "left": IdentifierObject { + "end": -1, + "escapedText": "prop", + "flags": 8, + "kind": 79, + "modifierFlagsCache": 0, + "originalKeywordKind": undefined, + "parent": undefined, + "pos": -1, + "transformFlags": 0, + }, "modifierFlagsCache": 0, + "operatorToken": TokenObject { + "end": -1, + "flags": 8, + "kind": 55, + "modifierFlagsCache": 0, + "parent": undefined, + "pos": -1, + "transformFlags": 0, + }, "parent": undefined, "pos": -1, - "transformFlags": 0, - }, - "condition": NodeObject { - "end": -1, - "expression": NodeObject { + "right": NodeObject { "end": -1, "flags": 8, "kind": 219, @@ -121,7 +145,7 @@ NodeObject { "operatorToken": TokenObject { "end": -1, "flags": 8, - "kind": 55, + "kind": 34, "modifierFlagsCache": 0, "parent": undefined, "pos": -1, @@ -129,102 +153,68 @@ NodeObject { }, "parent": undefined, "pos": -1, - "right": NodeObject { + "right": TokenObject { "end": -1, "flags": 8, - "kind": 219, - "left": IdentifierObject { - "end": -1, - "escapedText": "prop", - "flags": 8, - "kind": 79, - "modifierFlagsCache": 0, - "originalKeywordKind": undefined, - "parent": undefined, - "pos": -1, - "transformFlags": 0, - }, + "kind": 8, "modifierFlagsCache": 0, - "operatorToken": TokenObject { - "end": -1, - "flags": 8, - "kind": 34, - "modifierFlagsCache": 0, - "parent": undefined, - "pos": -1, - "transformFlags": 0, - }, + "numericLiteralFlags": 0, "parent": undefined, "pos": -1, - "right": TokenObject { - "end": -1, - "flags": 8, - "kind": 8, - "modifierFlagsCache": 0, - "numericLiteralFlags": 0, - "parent": undefined, - "pos": -1, - "text": "0", - "transformFlags": 0, - }, + "text": "0", "transformFlags": 0, }, "transformFlags": 0, }, - "flags": 8, - "kind": 210, - "modifierFlagsCache": 0, - "parent": undefined, - "pos": -1, "transformFlags": 0, }, - "end": -1, "flags": 8, - "kind": 220, + "kind": 210, "modifierFlagsCache": 0, "parent": undefined, "pos": -1, - "questionToken": TokenObject { - "end": -1, - "flags": 8, - "kind": 57, - "modifierFlagsCache": 0, - "parent": undefined, - "pos": -1, - "transformFlags": 0, - }, "transformFlags": 0, - "whenFalse": TokenObject { - "end": -1, - "flags": 8, - "hasExtendedUnicodeEscape": undefined, - "kind": 10, - "modifierFlagsCache": 0, - "parent": undefined, - "pos": -1, - "singleQuote": undefined, - "text": "bar", - "transformFlags": 0, - }, - "whenTrue": TokenObject { - "end": -1, - "flags": 8, - "hasExtendedUnicodeEscape": undefined, - "kind": 10, - "modifierFlagsCache": 0, - "parent": undefined, - "pos": -1, - "singleQuote": undefined, - "text": "foo", - "transformFlags": 0, - }, }, + "end": -1, "flags": 8, - "kind": 286, + "kind": 220, "modifierFlagsCache": 0, "parent": undefined, "pos": -1, - "transformFlags": 2, + "questionToken": TokenObject { + "end": -1, + "flags": 8, + "kind": 57, + "modifierFlagsCache": 0, + "parent": undefined, + "pos": -1, + "transformFlags": 0, + }, + "transformFlags": 0, + "whenFalse": TokenObject { + "end": -1, + "flags": 8, + "hasExtendedUnicodeEscape": undefined, + "kind": 10, + "modifierFlagsCache": 0, + "parent": undefined, + "pos": -1, + "singleQuote": undefined, + "text": "bar", + "transformFlags": 0, + }, + "whenTrue": TokenObject { + "end": -1, + "flags": 8, + "hasExtendedUnicodeEscape": undefined, + "kind": 10, + "modifierFlagsCache": 0, + "parent": undefined, + "pos": -1, + "singleQuote": undefined, + "text": "foo", + "transformFlags": 0, + }, }, "flags": 8, "kind": 286, @@ -260,9 +250,9 @@ NodeObject { } `; -exports[`react-component-render-helper buildContionalExpression operandType does not exist 1`] = `"{(user?.age && user?.age > \\"18\\") ? \\"Vote\\" : \\"Sorry you cannot vote\\"}"`; +exports[`react-component-render-helper buildContionalExpression operandType does not exist 1`] = `"(user?.age && user?.age > \\"18\\") ? \\"Vote\\" : \\"Sorry you cannot vote\\""`; -exports[`react-component-render-helper buildContionalExpression operandType exists 1`] = `"{(user?.age && user?.age > 18) ? \\"Vote\\" : \\"Sorry you cannot vote\\"}"`; +exports[`react-component-render-helper buildContionalExpression operandType exists 1`] = `"(user?.age && user?.age > 18) ? \\"Vote\\" : \\"Sorry you cannot vote\\""`; exports[`react-component-render-helper buildFixedJsxExpression boolean 1`] = `"{true}"`; 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 8daa8d58f..b5db7e8b2 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 @@ -335,6 +335,73 @@ export default function ReloadButton( } `; +exports[`amplify render tests actions with conditional in parameters 1`] = ` +Object { + "componentText": "/* eslint-disable */ +import React from \\"react\\"; +import { User } from \\"../models\\"; +import { + EscapeHatchProps, + createDataStorePredicate, + getOverrideProps, + useDataStoreBinding, + useStateMutationAction, +} from \\"@aws-amplify/ui-react/internal\\"; +import { Button, Flex, FlexProps, Text } from \\"@aws-amplify/ui-react\\"; + +export type ConditionalInMutationProps = React.PropsWithChildren< + Partial & { + user?: User; + } & { + overrides?: EscapeHatchProps | undefined | null; + } +>; +export default function ConditionalInMutation( + props: ConditionalInMutationProps +): React.ReactElement { + const { user: userProp, overrides, ...rest } = props; + const [mutatedValueChildren, setMutatedValueChildren] = + useStateMutationAction(\\"Default Value\\"); + const userFilterObj = { + field: \\"firstName\\", + operand: \\"Johnny\\", + operator: \\"eq\\", + }; + const userFilter = createDataStorePredicate(userFilterObj); + const userDataStore = useDataStoreBinding({ + type: \\"collection\\", + model: User, + criteria: userFilter, + }).items[0]; + const user = userProp !== undefined ? userProp : userDataStore; + const conditionalPropertyMutationClick = () => { + setMutatedValueChildren( + user?.age && user?.age == 45 ? \\"Conditional Value\\" : \\"Unconditional Value\\" + ); + }; + return ( + /* @ts-ignore: TS2322 */ + + + + + ); +} +", + "declaration": undefined, + "renderComponentToFilesystem": [Function], +} +`; + exports[`amplify render tests basic component tests should generate a simple button component 1`] = ` "/* eslint-disable */ import React from \\"react\\"; 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 81e5f9aae..0ab5dc8d6 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 @@ -323,6 +323,10 @@ describe('amplify render tests', () => { expect(generateWithAmplifyRenderer('workflow/dataStoreDeleteItem')).toMatchSnapshot(); }); }); + + it('with conditional in parameters', () => { + expect(generateWithAmplifyRenderer('workflow/conditionalInMutation')).toMatchSnapshot(); + }); }); it('should render events', () => { 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 f4e2c086f..7508396b4 100644 --- a/packages/codegen-ui-react/lib/react-component-render-helper.ts +++ b/packages/codegen-ui-react/lib/react-component-render-helper.ts @@ -460,7 +460,7 @@ function typedValueToJsxLiteral(value: any): PrimaryExpression { } } -export function buildConditionalExpression(prop: ConditionalStudioComponentProperty): JsxExpression { +export function buildConditionalExpression(prop: ConditionalStudioComponentProperty): Expression { const { property, field, operand, operandType, operator, then } = prop.condition; const elseBlock = prop.condition.else; const operatorToken = getSyntaxKindToken(operator); @@ -478,31 +478,28 @@ export function buildConditionalExpression(prop: ConditionalStudioComponentPrope ) : factory.createIdentifier(property); - return factory.createJsxExpression( - undefined, - factory.createConditionalExpression( - factory.createParenthesizedExpression( + return factory.createConditionalExpression( + factory.createParenthesizedExpression( + factory.createBinaryExpression( + propertyAccess, + factory.createToken(SyntaxKind.AmpersandAmpersandToken), factory.createBinaryExpression( propertyAccess, - factory.createToken(SyntaxKind.AmpersandAmpersandToken), - factory.createBinaryExpression( - propertyAccess, - operatorToken, - getConditionalOperandExpression(operand, operandType), - ), + operatorToken, + getConditionalOperandExpression(operand, operandType), ), ), - factory.createToken(SyntaxKind.QuestionToken), - resolvePropToExpression(then), - factory.createToken(SyntaxKind.ColonToken), - resolvePropToExpression(elseBlock), ), + factory.createToken(SyntaxKind.QuestionToken), + resolvePropToExpression(then), + factory.createToken(SyntaxKind.ColonToken), + resolvePropToExpression(elseBlock), ); } export function buildConditionalAttr(prop: ConditionalStudioComponentProperty, propName: string): JsxAttribute { const expr = buildConditionalExpression(prop); - return factory.createJsxAttribute(factory.createIdentifier(propName), expr); + return factory.createJsxAttribute(factory.createIdentifier(propName), factory.createJsxExpression(undefined, expr)); } export function buildChildElement(prop?: StudioComponentProperty): JsxChild | undefined { diff --git a/packages/codegen-ui/example-schemas/workflow/conditionalInMutation.json b/packages/codegen-ui/example-schemas/workflow/conditionalInMutation.json new file mode 100644 index 000000000..3969889a2 --- /dev/null +++ b/packages/codegen-ui/example-schemas/workflow/conditionalInMutation.json @@ -0,0 +1,64 @@ +{ + "id": "1234-5678-9010", + "componentType": "Flex", + "name": "ConditionalInMutation", + "properties": {}, + "bindingProperties": { + "user": { + "type": "Data", + "bindingProperties": { + "model": "User", + "predicate": { + "field": "firstName", + "operand": "Johnny", + "operator": "eq" + } + } + } + }, + "children": [ + { + "componentType": "Text", + "name": "MutatedValue", + "properties": { + "label": { + "value": "Default Value" + } + } + }, + { + "componentType": "Button", + "name": "ConditionalPropertyMutation", + "events": { + "click": { + "action": "Amplify.Mutation", + "parameters": { + "state": { + "componentName": "MutatedValue", + "property": "label", + "set": { + "condition": { + "property": "user", + "field": "age", + "operator": "eq", + "operand": 45, + "then": { + "value": "Conditional Value" + }, + "else": { + "value": "Unconditional Value" + } + } + } + } + } + } + }, + "properties": { + "children": { + "value": "Apply Conditional Property Mutation" + } + } + } + ] +} diff --git a/packages/test-generator/integration-test-templates/cypress/integration/generate-spec.ts b/packages/test-generator/integration-test-templates/cypress/integration/generate-spec.ts index 194dc52a2..4739794ea 100644 --- a/packages/test-generator/integration-test-templates/cypress/integration/generate-spec.ts +++ b/packages/test-generator/integration-test-templates/cypress/integration/generate-spec.ts @@ -144,6 +144,7 @@ const EXPECTED_SUCCESSFUL_CASES = new Set([ 'InternalMutation', 'TwoWayBindings', 'InputMutationOnClick', + 'ConditionalInMutation', ]); const EXPECTED_INVALID_INPUT_CASES = new Set([ 'ComponentMissingProperties', diff --git a/packages/test-generator/integration-test-templates/cypress/integration/workflow-spec.ts b/packages/test-generator/integration-test-templates/cypress/integration/workflow-spec.ts index 2946baf8e..983ab650f 100644 --- a/packages/test-generator/integration-test-templates/cypress/integration/workflow-spec.ts +++ b/packages/test-generator/integration-test-templates/cypress/integration/workflow-spec.ts @@ -235,6 +235,14 @@ describe('Workflow', () => { cy.get('input').should('have.attr', 'value', 'Razor Crest'); }); }); + + it('supports conditional in mutation', () => { + cy.get('#conditional-in-mutation').within(() => { + cy.get('.amplify-text').should('have.text', 'Default Value'); + cy.get('button').click(); + cy.get('.amplify-text').should('have.text', 'Conditional Value'); + }); + }); }); }); }); diff --git a/packages/test-generator/integration-test-templates/src/WorkflowTests.tsx b/packages/test-generator/integration-test-templates/src/WorkflowTests.tsx index 6731eb5b3..2e32d58f3 100644 --- a/packages/test-generator/integration-test-templates/src/WorkflowTests.tsx +++ b/packages/test-generator/integration-test-templates/src/WorkflowTests.tsx @@ -31,6 +31,7 @@ import { FormWithState, SimpleUserCollection, InputMutationOnClick, + ConditionalInMutation, } from './ui-components'; // eslint-disable-line import/extensions type AuthState = 'LoggedIn' | 'LoggedOutLocally' | 'LoggedOutGlobally' | 'Error'; @@ -218,6 +219,7 @@ export default function ComplexTests() { + ); diff --git a/packages/test-generator/lib/components/workflow/conditionalInMutation.json b/packages/test-generator/lib/components/workflow/conditionalInMutation.json new file mode 100644 index 000000000..93ad0b339 --- /dev/null +++ b/packages/test-generator/lib/components/workflow/conditionalInMutation.json @@ -0,0 +1,68 @@ +{ + "id": "1234-5678-9010", + "componentType": "Flex", + "name": "ConditionalInMutation", + "properties": { + "id": { + "value": "conditional-in-mutation" + } + }, + "bindingProperties": { + "user": { + "type": "Data", + "bindingProperties": { + "model": "User", + "predicate": { + "field": "firstName", + "operand": "Johnny", + "operator": "eq" + } + } + } + }, + "children": [ + { + "componentType": "Text", + "name": "MutatedValue", + "properties": { + "label": { + "value": "Default Value" + } + } + }, + { + "componentType": "Button", + "name": "ConditionalPropertyMutation", + "events": { + "click": { + "action": "Amplify.Mutation", + "parameters": { + "state": { + "componentName": "MutatedValue", + "property": "label", + "set": { + "condition": { + "property": "user", + "field": "age", + "operator": "eq", + "operand": 45, + "then": { + "value": "Conditional Value" + }, + "else": { + "value": "Unconditional Value" + } + } + } + } + } + } + }, + "properties": { + "children": { + "value": "Apply Conditional Property Mutation" + } + } + } + ] +} diff --git a/packages/test-generator/lib/components/workflow/index.ts b/packages/test-generator/lib/components/workflow/index.ts index 0c599fa26..84b0033c8 100644 --- a/packages/test-generator/lib/components/workflow/index.ts +++ b/packages/test-generator/lib/components/workflow/index.ts @@ -25,3 +25,4 @@ export { default as DataStoreActions } from './dataStoreActions.json'; export { default as FormWithState } from './formWithState.json'; export { default as TwoWayBindings } from './twoWayBindings.json'; export { default as InputMutationOnClick } from './inputMutationOnClick.json'; +export { default as ConditionalInMutation } from './conditionalInMutation.json';