Skip to content

Commit

Permalink
fix: support display value for array of enums
Browse files Browse the repository at this point in the history
  • Loading branch information
David Lopez authored and cwoolum committed Nov 23, 2022
1 parent 78341db commit 10ed135
Show file tree
Hide file tree
Showing 9 changed files with 1,511 additions and 1,331 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,7 @@ describe('amplify form renderer tests', () => {
});

it('should generate an update form with manyToMany relationship', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/tag-datastore-update',
'datastore/tag-post',
);
const { componentText } = generateWithAmplifyFormRenderer('forms/tag-datastore-update', 'datastore/tag-post');
// check nested model is imported
expect(componentText).toContain('import { Tag, Post, TagPost } from "../models";');

Expand All @@ -142,7 +139,22 @@ describe('amplify form renderer tests', () => {

// check resetStateValues has correct dependencies
expect(componentText).toContain('React.useEffect(resetStateValues, [tagRecord, linkedPosts]);');
});

it('should generate a create form with array of Enums', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/tag-datastore-create',
'datastore/tag-post',
);
// get displayValue function
expect(componentText).toContain('statuses: (record) => {');
expect(componentText).toContain('return enumDisplayValueMap[record];');
// ArrayField returns the item on a badge click
expect(componentText).toContain('setFieldValue(items[index]);');
// set the badgeText param
expect(componentText).toContain('getBadgeText={getDisplayValue.statuses}');
// ArrayField displays the getBadgeText return value
expect(componentText).toContain('{getBadgeText ? getBadgeText(value) : value.toString()}');
expect(componentText).toMatchSnapshot();
expect(declaration).toMatchSnapshot();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
StudioFormValueMappings,
} from '@aws-amplify/codegen-ui';
import { StudioFormInputFieldProperty } from '@aws-amplify/codegen-ui/lib/types/form/input-config';
import { isEnumFieldType } from '@aws-amplify/datastore';
import {
Expression,
factory,
Expand All @@ -28,12 +29,14 @@ import {
SyntaxKind,
NodeFlags,
CallExpression,
VariableStatement,
} from 'typescript';
import {
buildBindingExpression,
buildConcatExpression,
isBoundProperty,
isConcatenatedProperty,
isFixedPropertyWithValue,
} from '../../react-component-render-helper';
import { getRecordsName } from './form-state';
import { getElementAccessExpression } from './invalid-variable-helpers';
Expand Down Expand Up @@ -213,6 +216,10 @@ export function getDisplayValueObject(displayValueFunctions: PropertyAssignment[
// example - primaryAuthor: (record) => record?.name,
export function buildDisplayValueFunction(fieldName: string, fieldConfig: FieldConfigMetadata): PropertyAssignment {
const recordString = 'record';
const propertyName = isValidVariableName(fieldName)
? factory.createIdentifier(fieldName)
: factory.createStringLiteral(fieldName);
let additionalStatements: VariableStatement[] = [];
let renderedDisplayValue: Expression = factory.createPropertyAccessChain(
factory.createIdentifier(recordString),
factory.createToken(SyntaxKind.QuestionDotToken),
Expand All @@ -233,8 +240,52 @@ export function buildDisplayValueFunction(fieldName: string, fieldConfig: FieldC
}
}

if (isEnumFieldType(fieldConfig.dataType) && fieldConfig.valueMappings && fieldConfig.isArray) {
const displayValueMapName = `enumDisplayValueMap`;
additionalStatements = [
factory.createVariableStatement(
undefined,
factory.createVariableDeclarationList(
[
factory.createVariableDeclaration(
factory.createIdentifier(displayValueMapName),
undefined,
undefined,
factory.createObjectLiteralExpression(
fieldConfig.valueMappings.values.map((v) => {
let value = '';
let displayValue = '';
if (isFixedPropertyWithValue(v.value)) {
value = v.value.value.toString();
}
if (v.displayValue && isFixedPropertyWithValue(v.displayValue)) {
displayValue = v.displayValue.value.toString();
}
if (value === '') {
throw Error('Enum cannot have an empty value');
}
return factory.createPropertyAssignment(
factory.createStringLiteral(value),
factory.createStringLiteral(displayValue ?? value),
);
}),

true,
),
),
],
NodeFlags.Const,
),
),
];
renderedDisplayValue = factory.createElementAccessExpression(
factory.createIdentifier(displayValueMapName),
factory.createIdentifier(recordString),
);
}

return factory.createPropertyAssignment(
isValidVariableName(fieldName) ? factory.createIdentifier(fieldName) : factory.createStringLiteral(fieldName),
propertyName,
factory.createArrowFunction(
undefined,
undefined,
Expand All @@ -251,7 +302,9 @@ export function buildDisplayValueFunction(fieldName: string, fieldConfig: FieldC
],
undefined,
factory.createToken(SyntaxKind.EqualsGreaterThanToken),
renderedDisplayValue,
additionalStatements.length
? factory.createBlock([...additionalStatements, factory.createReturnStatement(renderedDisplayValue)], false)
: renderedDisplayValue,
),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import { FieldConfigMetadata } from '@aws-amplify/codegen-ui';
import { PropertyAssignment } from 'typescript';
import { buildDisplayValueFunction, getDisplayValueObject, getModelsToImport } from './display-value';
import { isModelDataType, shouldWrapInArrayField } from './render-checkers';
import { shouldImplementDisplayValueFunction, shouldWrapInArrayField } from './render-checkers';
import { buildValidationForField, buildValidations } from './validation';

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export function mapFromFieldConfigs(fieldConfigs: Record<string, FieldConfigMeta
}

// displayValue
if (isModelDataType(fieldConfig)) {
if (shouldImplementDisplayValueFunction(fieldConfig)) {
displayValueFunctions.push(buildDisplayValueFunction(fieldName, fieldConfig));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
setFieldState,
} from './form-state';
import { buildOverrideOnChangeStatement } from './event-handler-props';
import { isModelDataType } from './render-checkers';
import { isModelDataType, shouldImplementDisplayValueFunction } from './render-checkers';
import { getDisplayValueObjectName } from './display-value';
import { getElementAccessExpression } from './invalid-variable-helpers';

Expand Down Expand Up @@ -211,7 +211,7 @@ export const renderArrayFieldComponent = (

let setFieldValueIdentifier = setStateName;

if (isModelDataType(fieldConfig)) {
if (shouldImplementDisplayValueFunction(fieldConfig)) {
setFieldValueIdentifier = getSetNameIdentifier(getCurrentDisplayValueName(renderedFieldName));
props.push(
factory.createJsxAttribute(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@
limitations under the License.
*/
import { FieldConfigMetadata } from '@aws-amplify/codegen-ui';
import { isEnumFieldType } from '@aws-amplify/datastore';

export const shouldWrapInArrayField = (config: FieldConfigMetadata) => config.isArray || config.relationship;
export const shouldWrapInArrayField = (config: FieldConfigMetadata): boolean => config.isArray || !!config.relationship;

export const isModelDataType = (
config: FieldConfigMetadata,
): config is FieldConfigMetadata & { dataType: { model: string } } =>
!!(config.dataType && typeof config.dataType === 'object' && 'model' in config.dataType);

export const shouldImplementDisplayValueFunction = (config: FieldConfigMetadata): boolean => {
return isModelDataType(config) || (isEnumFieldType(config.dataType) && shouldWrapInArrayField(config));
};
20 changes: 19 additions & 1 deletion packages/codegen-ui/example-schemas/datastore/tag-post.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@
"associatedWith": "tag"
}
},
"statuses": {
"name": "statuses",
"isArray": true,
"type": {
"enum": "Status"
},
"isRequired": false,
"attributes": []
},
"createdAt": {
"name": "createdAt",
"isArray": false,
Expand Down Expand Up @@ -220,7 +229,16 @@
]
}
},
"enums": {},
"enums": {
"Status": {
"name": "Status",
"values": [
"PENDING",
"POSTED",
"IN_REVIEW"
]
}
},
"nonModels": {},
"codegenVersion": "3.3.1",
"version": "6661fbcb644d38cea3d27e2933e70457"
Expand Down
4 changes: 2 additions & 2 deletions packages/codegen-ui/lib/utils/form-component-metadata.ts
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.
*/

import { isEnumFieldType } from '@aws-amplify/datastore';
import { camelCase } from 'change-case';

import {
Expand Down Expand Up @@ -92,7 +92,7 @@ export const mapFormMetadata = (form: StudioForm, formDefinition: FormDefinition
});
}

if (element.relationship && 'valueMappings' in element) {
if ((element.relationship || isEnumFieldType(element.dataType)) && 'valueMappings' in element) {
metadata.valueMappings = element.valueMappings;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/codegen-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 10ed135

Please sign in to comment.