diff --git a/packages/form-code-generator-patternfly-theme/src/api/types.ts b/packages/form-code-generator-patternfly-theme/src/api/types.ts index 468283af5a6..a8a859e3401 100644 --- a/packages/form-code-generator-patternfly-theme/src/api/types.ts +++ b/packages/form-code-generator-patternfly-theme/src/api/types.ts @@ -20,11 +20,9 @@ export interface FormElement { reactImports: string[]; pfImports: string[]; - + pfIconImports?: string[]; requiredCode?: string[]; - ref: InputReference; - stateCode: string; jsxCode: string; isReadonly: boolean; @@ -33,6 +31,7 @@ export interface FormElement { abstract class AbstractFormElement implements FormElement { jsxCode: string; pfImports: string[]; + pfIconImports?: string[]; reactImports: string[]; requiredCode?: string[]; ref: InputReference; diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/AutoForm.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/AutoForm.tsx index ffb59cc8fec..756eb65890a 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/AutoForm.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/AutoForm.tsx @@ -45,11 +45,13 @@ const AutoForm: React.FC = (props) => { const inputs: FormElement[] = renderFormInputs(props.schema); let pfImports: string[] = []; + let pfIconImports: string[] = []; let reactImports: string[] = ["useCallback", "useEffect"]; let staticCodeArray: string[] = []; inputs.forEach((input) => { pfImports = union(pfImports, input.pfImports); + pfIconImports = union(pfIconImports, input.pfIconImports); reactImports = union(reactImports, input.reactImports); staticCodeArray = union(staticCodeArray, input.requiredCode); }); @@ -62,7 +64,8 @@ const AutoForm: React.FC = (props) => { const formTemplate = ` import React, { ${reactImports.join(", ")} } from "react"; - import { ${pfImports.join(", ")} } from "@patternfly/react-core"; +import { ${pfImports.join(", ")} } from "@patternfly/react-core"; +${pfIconImports.length > 0 ? `import { ${pfIconImports.join(", ")} } from "@patternfly/react-icons";` : ""} const ${formName}: React.FC = ( props:any ) => { const [formApi, setFormApi] = useState(); diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/CheckBoxGroupField.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/CheckBoxGroupField.tsx index 330dc771efa..8bc9347a97c 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/CheckBoxGroupField.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/CheckBoxGroupField.tsx @@ -51,10 +51,9 @@ const CheckBoxGroup: React.FC = (props: CheckBoxGroupProps) aria-label={'${props.name}'} label={'${props.transform ? props.transform(value) : value}'} isDisabled={${props.disabled || false}} - isChecked={${ref.stateName}.indexOf('${value}') != -1} - onChange={() => handleCheckboxGroupChange('${value}', ${ref.stateName}, ${ref.stateSetter})} + isChecked={${ref.stateName}.indexOf('${value}') !== -1} + onChange={${props.itemProps?.isListItem ? getListItemOnChange({ itemProps: props.itemProps, name: props.name, callback: (internalValue: string) => `handleCheckboxGroupChange(${internalValue}, ${ref.stateName}, ${ref.stateSetter})`, overrideNewValue: `'${value}'` }) : `() => handleCheckboxGroupChange('${value}', ${ref.stateName}, ${ref.stateSetter})`}} value={${props.itemProps?.isListItem ? getListItemValue({ itemProps: props.itemProps, name: props.name }) : `'${value}'`}} - onChange={${props.itemProps?.isListItem ? getListItemOnChange({ itemProps: props.itemProps, name: props.name, callback: (internalValue: string) => `handleCheckboxGroupChange('${internalValue}', ${ref.stateName}, ${ref.stateSetter})`, overrideNewValue: `'${value}'` }) : `handleCheckboxGroupChange('${value}', ${ref.stateName}, ${ref.stateSetter})`}} />`; }) .join("\n"); diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/DateField.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/DateField.tsx index 98cc654f2a5..e84502c8db3 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/DateField.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/DateField.tsx @@ -25,6 +25,7 @@ import { buildDefaultInputElement, getInputReference, renderField } from "./util import { useAddFormElementToContext } from "./CodeGenContext"; import { DATE_FUNCTIONS, TIME_FUNCTIONS } from "./staticCode/staticCodeBlocks"; import { DATE } from "./utils/dataTypes"; +import { getListItemName, getListItemOnChange, getListItemValue, ListItemProps } from "./rendering/ListItemField"; export type DateFieldProps = HTMLFieldProps< Date, @@ -35,6 +36,7 @@ export type DateFieldProps = HTMLFieldProps< required: boolean; max?: Date; min?: Date; + itemProps: ListItemProps; } >; @@ -52,19 +54,34 @@ const Date: React.FC = (props: DateFieldProps) => { onDateChange(newDate, ${ref.stateSetter}, ${ref.stateName})} - value={parseDate(${ref.stateName})} + name={${props.itemProps?.isListItem ? getListItemName({ itemProps: props.itemProps, name: props.name }) : `'${props.name}'`}} + onChange={${ + props.itemProps?.isListItem + ? getListItemOnChange({ + itemProps: props.itemProps, + name: props.name, + callback: (value) => `onDateChange(${value}, ${ref.stateSetter}, ${ref.stateName})`, + }) + : `newDate => onDateChange(newDate, ${ref.stateSetter}, ${ref.stateName})` + }} + value={${props.itemProps?.isListItem ? getListItemValue({ itemProps: props.itemProps, name: props.name, callback: (value: string) => `parseDate(${value})` }) : `parseDate(${ref.stateName})`}} /> onTimeChange(time, ${ref.stateSetter}, ${ - ref.stateName - }, hours, minutes)} + name={${props.itemProps?.isListItem ? getListItemName({ itemProps: props.itemProps, name: props.name }) : `'${props.name}'`}} + onChange={${ + props.itemProps?.isListItem + ? getListItemOnChange({ + itemProps: props.itemProps, + name: props.name, + callback: (_) => `onTimeChange(time, ${ref.stateSetter}, ${ref.stateName}, hours, minutes)`, + overrideParam: "(time, hours?, minutes?)", + }) + : `(time, hours?, minutes?) => onTimeChange(time, ${ref.stateSetter}, ${ref.stateName}, hours, minutes)` + }} style={{ width: '120px' }} - time={parseTime(${ref.stateName})} + time={${props.itemProps?.isListItem ? getListItemValue({ itemProps: props.itemProps, name: props.name, callback: (value: string) => `parseTime(${value})` }) : `parseTime(${ref.stateName})`}} /> diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/ListField.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/ListField.tsx index 66527f630c5..108827240a2 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/ListField.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/ListField.tsx @@ -109,13 +109,11 @@ const List: React.FC = (props: ListFieldProps) => { `; - // TODO ADD PLUS AND MINUS ICONS const element: FormInput = { ref, pfImports: [...new Set(["Split", "SplitItem", "Button", ...(listItem?.pfImports ?? [])])], + pfIconImports: [...new Set(["PlusCircleIcon", "MinusCircleIcon", ...(listItem?.pfIconImports ?? [])])], reactImports: [...new Set([...(listItem?.reactImports ?? [])])], - requiredCode: [...new Set([...(listItem?.requiredCode ?? [])])], - // requiredIcons: ["PlusCircleIcon", "MinusCircleIcon"], jsxCode, stateCode: getStateCode(ref.stateName, ref.stateSetter, "any[]", "[]"), isReadonly: props.disabled, diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/SelectField.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/SelectField.tsx index 7dcc01c535a..212b91466ad 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/SelectField.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/SelectField.tsx @@ -24,6 +24,7 @@ import { FormInput, InputReference } from "../api"; import { getInputReference, getStateCode, getStateCodeFromRef, NS_SEPARATOR, renderField } from "./utils/Utils"; import { MULTIPLE_SELECT_FUNCTIONS, SELECT_FUNCTIONS } from "./staticCode/staticCodeBlocks"; import { ARRAY, STRING } from "./utils/dataTypes"; +import { getListItemName, getListItemOnChange, getListItemValue, ListItemProps } from "./rendering/ListItemField"; export type SelectInputProps = HTMLFieldProps< string | string[], @@ -31,6 +32,7 @@ export type SelectInputProps = HTMLFieldProps< { allowedValues?: string[]; transform?(value: string): string; + itemProps?: ListItemProps; } >; @@ -75,17 +77,15 @@ const Select: React.FC = (props: SelectInputProps) => { isRequired={${props.required}} >`; diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/rendering/ListItemField.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/rendering/ListItemField.tsx index 8cb8fd0af6f..ba170e07acf 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/rendering/ListItemField.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/rendering/ListItemField.tsx @@ -55,9 +55,18 @@ export const getListItemName = ({ itemProps, name }: { itemProps: ListItemProps; * `listStateName[index]` * `listStateName[index].itemName.` */ -export const getListItemValue = ({ itemProps, name }: { itemProps: ListItemProps; name: string }) => { +export const getListItemValue = ({ + itemProps, + name, + callback, +}: { + itemProps: ListItemProps; + name: string; + callback?: (value: string) => string; +}) => { const { itemName, isNested } = getItemNameAndWithIsNested(name); - return `${itemProps?.listStateName}[${itemProps?.indexVariableName}]${isNested ? `.${itemName}` : ""}`; + const property = `${itemProps?.listStateName}[${itemProps?.indexVariableName}]${isNested ? `.${itemName}` : ""}`; + return `${callback ? callback(property) : property}`; }; /** @@ -78,17 +87,23 @@ export const getListItemOnChange = ({ name, callback, overrideNewValue, + overrideParam, }: { itemProps: ListItemProps; name: string; callback?: (value: string) => string; + overrideParam?: string; overrideNewValue?: string; }) => { const { itemName, isNested } = getItemNameAndWithIsNested(name); return ` - newValue => ${itemProps?.listStateSetter}(s => { const newState = [...s]; - newState[${itemProps?.indexVariableName}]${isNested ? `.${itemName}` : ""} = ${callback ? callback(overrideNewValue ? overrideNewValue : "newValue") : overrideNewValue ? overrideNewValue : "newValue"}; - return newState; })`; + ${overrideParam ? overrideParam : "newValue"} => { + ${itemProps?.listStateSetter}(s => { + const newState = [...s]; + newState[${itemProps?.indexVariableName}]${isNested ? `.${itemName}` : ""} = ${callback ? callback(overrideNewValue ? overrideNewValue : "newValue") : overrideNewValue ? overrideNewValue : "newValue"}; + return newState; + }) + }`; }; export interface Props { diff --git a/packages/form-code-generator-patternfly-theme/src/uniforms/utils/Utils.tsx b/packages/form-code-generator-patternfly-theme/src/uniforms/utils/Utils.tsx index 70f765ea518..fde13d3620e 100644 --- a/packages/form-code-generator-patternfly-theme/src/uniforms/utils/Utils.tsx +++ b/packages/form-code-generator-patternfly-theme/src/uniforms/utils/Utils.tsx @@ -50,6 +50,7 @@ export const getStateCode = ( type DefaultInputProps = { pfImports: string[]; + pfIconImports?: string[]; inputJsxCode: string; ref: InputReference; requiredCode?: string[]; @@ -65,6 +66,7 @@ type WrapperProps = { export const buildDefaultInputElement = ({ pfImports, + pfIconImports, inputJsxCode, ref, wrapper, @@ -86,6 +88,7 @@ export const buildDefaultInputElement = ({ return { ref, pfImports, + pfIconImports, reactImports: ["useState"], requiredCode: requiredCode, jsxCode, diff --git a/packages/form-code-generator-patternfly-theme/tests/CheckBoxGroupField.test.tsx b/packages/form-code-generator-patternfly-theme/tests/CheckBoxGroupField.test.tsx index 57825df0f97..a4376b771a5 100644 --- a/packages/form-code-generator-patternfly-theme/tests/CheckBoxGroupField.test.tsx +++ b/packages/form-code-generator-patternfly-theme/tests/CheckBoxGroupField.test.tsx @@ -73,7 +73,7 @@ describe(" tests", () => { aria-label={'${props.name}'}`; expect(formElement.jsxCode).toContain(checkbox); expect(formElement.jsxCode).toContain(`label={'${value}'}`); - expect(formElement.jsxCode).toContain(`isChecked={${formElement.ref.stateName}.indexOf('${value}') != -1}`); + expect(formElement.jsxCode).toContain(`isChecked={${formElement.ref.stateName}.indexOf('${value}') !== -1}`); expect(formElement.jsxCode).toContain( `onChange={() => handleCheckboxGroupChange('${value}', ${formElement.ref.stateName}, ${formElement.ref.stateSetter})}` ); diff --git a/packages/form-code-generator-patternfly-theme/tests/ListField.test.tsx b/packages/form-code-generator-patternfly-theme/tests/ListField.test.tsx index 6d8a17a3448..5ad537dd495 100644 --- a/packages/form-code-generator-patternfly-theme/tests/ListField.test.tsx +++ b/packages/form-code-generator-patternfly-theme/tests/ListField.test.tsx @@ -33,6 +33,22 @@ describe(" tests", () => { friends: { type: Array }, "friends.$": Object, "friends.$.name": { type: String }, + "friends.$.age": { type: Number }, + "friends.$.country": { type: String, allowedValues: ["US", "Brazil"] }, + "friends.$.married": { type: Boolean }, + "friends.$.know": { + type: Array, + allowedValues: ["Java", "Node", "Docker"], + uniforms: { + checkboxes: true, + }, + }, + "friends.$.know.$": String, + "friends.$.areas": { + type: String, + allowedValues: ["Developer", "HR", "UX"], + }, + "friends.$.birthday": { type: Date }, }; const props: AutoFormProps = { @@ -42,37 +58,8 @@ describe(" tests", () => { placeholder: true, }; - // const props = { - // id: "id", - // label: "friends", - // name: "friends", - // disabled: false, - // onChange: jest.fn(), - // maxCount: 10, - // }; - const { container } = render(); - // const { container, formElement } = renderField(ListField, props, schema); - expect(container).toMatchSnapshot(); - - // expect(formElement.reactImports).toContain("useState"); - // expect(formElement.pfImports).toContain("FormGroup"); - // expect(formElement.pfImports).toContain("TextInput"); - - // expect(formElement.ref.binding).toBe(props.name); - // expect(formElement.ref.stateName).toBe(props.name); - // expect(formElement.ref.stateSetter).toBe(`set__${props.name}`); - - // expect(formElement.jsxCode).not.toBeNull(); - // expect(formElement.jsxCode).toContain("label={'age'}"); - // expect(formElement.jsxCode).toContain("name={'age'}"); - // expect(formElement.jsxCode).toContain("isDisabled={false}"); - - // expect(formElement.jsxCode).toContain(`step={1}`); - // expect(formElement.jsxCode).toContain(`min={${props.min}}`); - // expect(formElement.jsxCode).toContain(`max={${props.max}}`); - // expect(formElement.stateCode).not.toBeNull(); }); }); diff --git a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/AutoForm.test.tsx.snap b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/AutoForm.test.tsx.snap index 96df0733236..bada6af3381 100644 --- a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/AutoForm.test.tsx.snap +++ b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/AutoForm.test.tsx.snap @@ -19,8 +19,11 @@ import { FlexItem, InputGroup, TimePicker, - Alert, + Split, + SplitItem, + Button, } from '@patternfly/react-core'; +import { PlusCircleIcon, MinusCircleIcon } from '@patternfly/react-icons'; const Form__HRInterview: React.FC<any> = (props: any) => { const [formApi, setFormApi] = useState<any>(); const [personalData__name, set__personalData__name] = useState<string>(''); @@ -48,7 +51,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { const [interview__hire, set__interview__hire] = useState<boolean>(false); const [interview__hiringDate, set__interview__hiringDate] = useState<string>(); - const [friends, set__friends] = useState<any[]>(); + const [friends, set__friends] = useState<any[]>([]); /* Utility function that fills the form with the data received from the kogito runtime */ const setFormData = (data) => { if (!data) { @@ -69,7 +72,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { set__interview__rating(data?.interview?.rating ?? ''); set__interview__hire(data?.interview?.hire ?? false); set__interview__hiringDate(data?.interview?.hiringDate); - set__friends(data?.friends); + set__friends(data?.friends ?? []); }; /* Utility function to generate the expected form output as a json object */ const getFormData = useCallback(() => { @@ -300,15 +303,15 @@ const Form__HRInterview: React.FC<any> = (props: any) => { isOpen={interview__position__expanded} selections={interview__position} onToggle={(isOpen) => set__interview__position__expanded(isOpen)} - onSelect={(event, value, isPlaceHolder) => { + onSelect={(event, value, isPlaceHolder) => handleSelect( value, isPlaceHolder, interview__position, set__interview__position, set__interview__position__expanded - ); - }} + ) + } value={interview__position}> <SelectOption key={'Developer'} value={'Developer'}> Developer @@ -336,14 +339,14 @@ const Form__HRInterview: React.FC<any> = (props: any) => { onToggle={(isOpen) => set__interview__otherPositions__expanded(isOpen) } - onSelect={(event, value, isPlaceHolder) => { + onSelect={(event, value, isPlaceHolder) => handleMultipleSelect( value, isPlaceHolder, interview__otherPositions, set__interview__otherPositions - ); - }} + ) + } value={interview__otherPositions}> <SelectOption key={'Developer'} value={'Developer'}> Developer @@ -367,7 +370,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { aria-label={'interview.skills'} label={'Java'} isDisabled={false} - isChecked={interview__skills.indexOf('Java') != -1} + isChecked={interview__skills.indexOf('Java') !== -1} onChange={() => handleCheckboxGroupChange( 'Java', @@ -384,7 +387,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { aria-label={'interview.skills'} label={'React'} isDisabled={false} - isChecked={interview__skills.indexOf('React') != -1} + isChecked={interview__skills.indexOf('React') !== -1} onChange={() => handleCheckboxGroupChange( 'React', @@ -401,7 +404,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { aria-label={'interview.skills'} label={'TypeScript'} isDisabled={false} - isChecked={interview__skills.indexOf('TypeScript') != -1} + isChecked={interview__skills.indexOf('TypeScript') !== -1} onChange={() => handleCheckboxGroupChange( 'TypeScript', @@ -418,7 +421,7 @@ const Form__HRInterview: React.FC<any> = (props: any) => { aria-label={'interview.skills'} label={'Quarkus'} isDisabled={false} - isChecked={interview__skills.indexOf('Quarkus') != -1} + isChecked={interview__skills.indexOf('Quarkus') !== -1} onChange={() => handleCheckboxGroupChange( 'Quarkus', @@ -571,21 +574,96 @@ const Form__HRInterview: React.FC<any> = (props: any) => { </FormGroup> </CardBody> </Card> - <FormGroup - fieldId={'uniforms-0000-000x'} - label={'Friends'} - isRequired={true}> - <Alert variant='warning' title='Unsupported field type: Array'> - Cannot find form control for property <code>friends</code> with type{' '} - <code>Array</code>:<br /> - Some complex property types, such as <code> - Array&lt;object&gt; - </code>{' '} - aren't yet supported, however, you can still write your own component - into the form and use the already existing states{' '} - <code>const [ friends, set__friends ]</code>. - </Alert> - </FormGroup> + <div fieldId={'uniforms-0000-000x'}> + <Split hasGutter> + <SplitItem>{'Friends' && <label>'Friends'</label>}</SplitItem> + <SplitItem isFilled /> + <SplitItem> + <Button + name='$' + variant='plain' + style={{ paddingLeft: '0', paddingRight: '0' }} + disabled={false} + onClick={() => { + !false && set__friends((friends ?? []).concat([])); + }}> + +{/* <PlusCircleIcon color='#0088ce' /> */} + </Button> + </SplitItem> + </Split> + <div> + {friends?.map((_, itemIndex) => ( + <div + key={itemIndex} + style={{ + marginBottom: '1rem', + display: 'flex', + justifyContent: 'space-between', + }}> + <div style={{ width: '100%', marginRight: '10px' }}> + <Card> + <CardBody className='pf-c-form'> + <FormGroup + fieldId={'uniforms-0000-0010'} + label={'Name'} + isRequired={true}> + <TextInput + name={\`friends.\${itemIndex}.name\`} + id={'uniforms-0000-0010'} + isDisabled={false} + placeholder={''} + type={'text'} + value={friends[itemIndex].name} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].name = newValue; + return newState; + }); + }} + /> + </FormGroup> + <FormGroup + fieldId={'uniforms-0000-0012'} + label={'Age'} + isRequired={true}> + <TextInput + type={'number'} + name={\`friends.\${itemIndex}.age\`} + isDisabled={false} + id={'uniforms-0000-0012'} + placeholder={''} + step={0.01} + value={friends[itemIndex].age} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].age = Number(newValue); + return newState; + }); + }} + /> + </FormGroup> + </CardBody> + </Card> + </div> + <div> + <Button + disabled={false} + variant='plain' + style={{ paddingLeft: '0', paddingRight: '0' }} + onClick={() => { + const value = friends!.slice(); + value.splice(NaN, 1); + !false && set__friends(value); + }}> + - {/* <MinusCircleIcon color='#cc0000' /> */} + </Button> + </div> + </div> + ))} + </div> + </div> </div> ); }; diff --git a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/CheckBoxGroupField.test.tsx.snap b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/CheckBoxGroupField.test.tsx.snap index 0977df1232c..dad60b85dff 100644 --- a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/CheckBoxGroupField.test.tsx.snap +++ b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/CheckBoxGroupField.test.tsx.snap @@ -2,6 +2,6 @@ exports[` tests - rendering 1`] = `
- {"ref":{"binding":"roles","stateName":"roles","stateSetter":"set__roles","dataType":{"name":"string[]","defaultValue":"[]"}},"pfImports":["Checkbox","FormGroup"],"reactImports":["useState"],"requiredCode":["checkbox_group_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'Roles'}\\n isRequired={true}\\n >\\n <Checkbox\\n key={'id-Developer'}\\n id={'id-Developer'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'Developer'} \\n isDisabled={false} \\n isChecked={roles.indexOf('Developer') != -1}\\n onChange={() => handleCheckboxGroupChange('Developer', roles, set__roles)}\\n value={'Developer'}\\n onChange={handleCheckboxGroupChange('Developer', roles, set__roles)}\\n/>\\n<Checkbox\\n key={'id-HR'}\\n id={'id-HR'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'HR'} \\n isDisabled={false} \\n isChecked={roles.indexOf('HR') != -1}\\n onChange={() => handleCheckboxGroupChange('HR', roles, set__roles)}\\n value={'HR'}\\n onChange={handleCheckboxGroupChange('HR', roles, set__roles)}\\n/>\\n<Checkbox\\n key={'id-UX'}\\n id={'id-UX'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'UX'} \\n isDisabled={false} \\n isChecked={roles.indexOf('UX') != -1}\\n onChange={() => handleCheckboxGroupChange('UX', roles, set__roles)}\\n value={'UX'}\\n onChange={handleCheckboxGroupChange('UX', roles, set__roles)}\\n/>\\n </FormGroup>","stateCode":"const [ roles, set__roles ] = useState<string[]>([]);","isReadonly":false} + {"ref":{"binding":"roles","stateName":"roles","stateSetter":"set__roles","dataType":{"name":"string[]","defaultValue":"[]"}},"pfImports":["Checkbox","FormGroup"],"reactImports":["useState"],"requiredCode":["checkbox_group_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'Roles'}\\n isRequired={true}\\n >\\n <Checkbox\\n key={'id-Developer'}\\n id={'id-Developer'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'Developer'} \\n isDisabled={false} \\n isChecked={roles.indexOf('Developer') !== -1}\\n onChange={() => handleCheckboxGroupChange('Developer', roles, set__roles)}\\n value={'Developer'}\\n/>\\n<Checkbox\\n key={'id-HR'}\\n id={'id-HR'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'HR'} \\n isDisabled={false} \\n isChecked={roles.indexOf('HR') !== -1}\\n onChange={() => handleCheckboxGroupChange('HR', roles, set__roles)}\\n value={'HR'}\\n/>\\n<Checkbox\\n key={'id-UX'}\\n id={'id-UX'}\\n name={'roles'}\\n aria-label={'roles'}\\n label={'UX'} \\n isDisabled={false} \\n isChecked={roles.indexOf('UX') !== -1}\\n onChange={() => handleCheckboxGroupChange('UX', roles, set__roles)}\\n value={'UX'}\\n/>\\n </FormGroup>","stateCode":"const [ roles, set__roles ] = useState<string[]>([]);","isReadonly":false}
`; diff --git a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/ListField.test.tsx.snap b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/ListField.test.tsx.snap index a6286dde416..45b3fae6e27 100644 --- a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/ListField.test.tsx.snap +++ b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/ListField.test.tsx.snap @@ -11,7 +11,18 @@ import { CardBody, TextInput, FormGroup, + SelectOption, + SelectOptionObject, + Select, + SelectVariant, + Checkbox, + DatePicker, + Flex, + FlexItem, + InputGroup, + TimePicker, } from '@patternfly/react-core'; +import { PlusCircleIcon, MinusCircleIcon } from '@patternfly/react-icons'; const Form__id: React.FC<any> = (props: any) => { const [formApi, setFormApi] = useState<any>(); const [friends, set__friends] = useState<any[]>([]); @@ -107,15 +118,250 @@ const Form__id: React.FC<any> = (props: any) => { placeholder={''} type={'text'} value={friends[itemIndex].name} - onChange={(newValue) => + onChange={(newValue) => { set__friends((s) => { const newState = [...s]; newState[itemIndex].name = newValue; return newState; - }) + }); + }} + /> + </FormGroup> + <FormGroup + fieldId={'uniforms-0000-0006'} + label={'Age'} + isRequired={true}> + <TextInput + type={'number'} + name={\`friends.\${itemIndex}.age\`} + isDisabled={false} + id={'uniforms-0000-0006'} + placeholder={''} + step={0.01} + value={friends[itemIndex].age} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].age = Number(newValue); + return newState; + }); + }} + /> + </FormGroup> + <FormGroup + fieldId={'uniforms-0000-0008'} + label={'Country'} + isRequired={true}> + <Select + id={'uniforms-0000-0008'} + name={\`friends.\${itemIndex}.country\`} + variant={SelectVariant.single} + isDisabled={false} + placeholderText={''} + isOpen={friends__$__country__expanded} + selections={friends__$__country} + onToggle={(isOpen) => + set__friends__$__country__expanded(isOpen) } + onSelect={(event, value, isPlaceHolder) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].country = handleSelect( + value, + isPlaceHolder, + friends__$__country, + set__friends__$__country, + set__friends__$__country__expanded + ); + return newState; + }); + }} + value={friends[itemIndex].country}> + <SelectOption key={'US'} value={'US'}> + US + </SelectOption> + <SelectOption key={'Brazil'} value={'Brazil'}> + Brazil + </SelectOption> + </Select> + </FormGroup> + <FormGroup fieldId='uniforms-0000-000a'> + <Checkbox + isChecked={friends[itemIndex].married} + isDisabled={false} + id={'uniforms-0000-000a'} + name={\`friends.\${itemIndex}.married\`} + label={'Married'} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].married = newValue; + return newState; + }); + }} + /> + </FormGroup> + <FormGroup + fieldId={'uniforms-0000-000c'} + label={'Know'} + isRequired={true}> + <Checkbox + key={'uniforms-0000-000c-Java'} + id={'uniforms-0000-000c-Java'} + name={\`friends.\${itemIndex}.know\`} + aria-label={'friends.$.know'} + label={'Java'} + isDisabled={false} + isChecked={friends__$__know.indexOf('Java') !== -1} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].know = + handleCheckboxGroupChange( + 'Java', + friends__$__know, + set__friends__$__know + ); + return newState; + }); + }} + value={friends[itemIndex].know} + /> + <Checkbox + key={'uniforms-0000-000c-Node'} + id={'uniforms-0000-000c-Node'} + name={\`friends.\${itemIndex}.know\`} + aria-label={'friends.$.know'} + label={'Node'} + isDisabled={false} + isChecked={friends__$__know.indexOf('Node') !== -1} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].know = + handleCheckboxGroupChange( + 'Node', + friends__$__know, + set__friends__$__know + ); + return newState; + }); + }} + value={friends[itemIndex].know} + /> + <Checkbox + key={'uniforms-0000-000c-Docker'} + id={'uniforms-0000-000c-Docker'} + name={\`friends.\${itemIndex}.know\`} + aria-label={'friends.$.know'} + label={'Docker'} + isDisabled={false} + isChecked={friends__$__know.indexOf('Docker') !== -1} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].know = + handleCheckboxGroupChange( + 'Docker', + friends__$__know, + set__friends__$__know + ); + return newState; + }); + }} + value={friends[itemIndex].know} /> </FormGroup> + <FormGroup + fieldId={'uniforms-0000-000e'} + label={'Areas'} + isRequired={true}> + <Select + id={'uniforms-0000-000e'} + name={\`friends.\${itemIndex}.areas\`} + variant={SelectVariant.single} + isDisabled={false} + placeholderText={''} + isOpen={friends__$__areas__expanded} + selections={friends__$__areas} + onToggle={(isOpen) => + set__friends__$__areas__expanded(isOpen) + } + onSelect={(event, value, isPlaceHolder) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].areas = handleSelect( + value, + isPlaceHolder, + friends__$__areas, + set__friends__$__areas, + set__friends__$__areas__expanded + ); + return newState; + }); + }} + value={friends[itemIndex].areas}> + <SelectOption key={'Developer'} value={'Developer'}> + Developer + </SelectOption> + <SelectOption key={'HR'} value={'HR'}> + HR + </SelectOption> + <SelectOption key={'UX'} value={'UX'}> + UX + </SelectOption> + </Select> + </FormGroup> + <FormGroup + fieldId={'uniforms-0000-000g'} + label={'Birthday'} + isRequired={true}> + <Flex + direction={{ default: 'column' }} + id={'uniforms-0000-000g'}> + <FlexItem> + <InputGroup style={{ background: 'transparent' }}> + <DatePicker + id={'date-picker-uniforms-0000-000g'} + isDisabled={false} + name={\`friends.\${itemIndex}.birthday\`} + onChange={(newValue) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].birthday = onDateChange( + newValue, + set__friends__$__birthday, + friends__$__birthday + ); + return newState; + }); + }} + value={parseDate(friends[itemIndex].birthday)} + /> + <TimePicker + id={'time-picker-uniforms-0000-000g'} + isDisabled={false} + name={\`friends.\${itemIndex}.birthday\`} + onChange={(time, hours?, minutes?) => { + set__friends((s) => { + const newState = [...s]; + newState[itemIndex].birthday = onTimeChange( + time, + set__friends__$__birthday, + friends__$__birthday, + hours, + minutes + ); + return newState; + }); + }} + style={{ width: '120px' }} + time={parseTime(friends[itemIndex].birthday)} + /> + </InputGroup> + </FlexItem> + </Flex> + </FormGroup> </CardBody> </Card> </div> diff --git a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/NestField.test.tsx.snap b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/NestField.test.tsx.snap index ee9d764a0d4..c7f684512ea 100644 --- a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/NestField.test.tsx.snap +++ b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/NestField.test.tsx.snap @@ -2,6 +2,6 @@ exports[` tests - rendering 1`] = `
- {"pfImports":["Card","CardBody","TextInput","FormGroup","SelectOption","SelectOptionObject","Select","SelectVariant"],"reactImports":["useState"],"requiredCode":["select_functions"],"stateCode":"const [ candidate__name, set__candidate__name ] = useState<string>(\\"\\");\\nconst [ candidate__age, set__candidate__age ] = useState<number>();\\nconst [ candidate__role, set__candidate__role ] = useState<string>(\\"\\");\\nconst [ candidate__role__expanded, set__candidate__role__expanded ] = useState<boolean>(false);","jsxCode":"<Card>\\n <CardBody className=\\"pf-c-form\\">\\n <label><b>Candidate</b></label>\\n <FormGroup\\n fieldId={'uniforms-0000-0001'}\\n label={'Name'}\\n isRequired={true}\\n >\\n <TextInput\\n name={'candidate.name'}\\n id={'uniforms-0000-0001'}\\n isDisabled={false}\\n placeholder={''}\\n type={'text'}\\n value={candidate__name}\\n onChange={set__candidate__name}\\n />\\n </FormGroup>\\n<FormGroup\\n fieldId={'uniforms-0000-0003'}\\n label={'Age'}\\n isRequired={true}\\n >\\n <TextInput\\n type={'number'}\\n name={'candidate.age'}\\n isDisabled={false}\\n id={'uniforms-0000-0003'}\\n placeholder={''}\\n step={1} \\n value={candidate__age}\\n onChange={(newValue) => set__candidate__age(Number(newValue))}\\n />\\n </FormGroup>\\n<FormGroup\\n fieldId={'uniforms-0000-0005'}\\n label={'Role'}\\n isRequired={true}\\n ><Select\\n id={'uniforms-0000-0005'}\\n name={'candidate.role'}\\n variant={SelectVariant.single}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={candidate__role__expanded}\\n selections={candidate__role}\\n onToggle={(isOpen) => set__candidate__role__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => {\\n handleSelect(value, isPlaceHolder, candidate__role, set__candidate__role, set__candidate__role__expanded)\\n }}\\n value={candidate__role}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>\\n </CardBody></Card>","ref":{"binding":"candidate","stateName":"candidate","stateSetter":"set__candidate","dataType":{"name":"any"}},"childRefs":[{"binding":"candidate.name","stateName":"candidate__name","stateSetter":"set__candidate__name","dataType":{"name":"string","defaultValue":"\\"\\""}},{"binding":"candidate.age","stateName":"candidate__age","stateSetter":"set__candidate__age","dataType":{"name":"number"}},{"binding":"candidate.role","stateName":"candidate__role","stateSetter":"set__candidate__role","dataType":{"name":"string","defaultValue":"\\"\\""}}],"isReadonly":false} + {"pfImports":["Card","CardBody","TextInput","FormGroup","SelectOption","SelectOptionObject","Select","SelectVariant"],"reactImports":["useState"],"requiredCode":["select_functions"],"stateCode":"const [ candidate__name, set__candidate__name ] = useState<string>(\\"\\");\\nconst [ candidate__age, set__candidate__age ] = useState<number>();\\nconst [ candidate__role, set__candidate__role ] = useState<string>(\\"\\");\\nconst [ candidate__role__expanded, set__candidate__role__expanded ] = useState<boolean>(false);","jsxCode":"<Card>\\n <CardBody className=\\"pf-c-form\\">\\n <label><b>Candidate</b></label>\\n <FormGroup\\n fieldId={'uniforms-0000-0001'}\\n label={'Name'}\\n isRequired={true}\\n >\\n <TextInput\\n name={'candidate.name'}\\n id={'uniforms-0000-0001'}\\n isDisabled={false}\\n placeholder={''}\\n type={'text'}\\n value={candidate__name}\\n onChange={set__candidate__name}\\n />\\n </FormGroup>\\n<FormGroup\\n fieldId={'uniforms-0000-0003'}\\n label={'Age'}\\n isRequired={true}\\n >\\n <TextInput\\n type={'number'}\\n name={'candidate.age'}\\n isDisabled={false}\\n id={'uniforms-0000-0003'}\\n placeholder={''}\\n step={1} \\n value={candidate__age}\\n onChange={(newValue) => set__candidate__age(Number(newValue))}\\n />\\n </FormGroup>\\n<FormGroup\\n fieldId={'uniforms-0000-0005'}\\n label={'Role'}\\n isRequired={true}\\n ><Select\\n id={'uniforms-0000-0005'}\\n name={'candidate.role'}\\n variant={SelectVariant.single}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={candidate__role__expanded}\\n selections={candidate__role}\\n onToggle={(isOpen) => set__candidate__role__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => handleSelect(value, isPlaceHolder, candidate__role, set__candidate__role, set__candidate__role__expanded)}\\n value={candidate__role}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>\\n </CardBody></Card>","ref":{"binding":"candidate","stateName":"candidate","stateSetter":"set__candidate","dataType":{"name":"any"}},"childRefs":[{"binding":"candidate.name","stateName":"candidate__name","stateSetter":"set__candidate__name","dataType":{"name":"string","defaultValue":"\\"\\""}},{"binding":"candidate.age","stateName":"candidate__age","stateSetter":"set__candidate__age","dataType":{"name":"number"}},{"binding":"candidate.role","stateName":"candidate__role","stateSetter":"set__candidate__role","dataType":{"name":"string","defaultValue":"\\"\\""}}],"isReadonly":false}
`; diff --git a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/SelectField.test.tsx.snap b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/SelectField.test.tsx.snap index 506093d2ca8..24b0b19b086 100644 --- a/packages/form-code-generator-patternfly-theme/tests/__snapshots__/SelectField.test.tsx.snap +++ b/packages/form-code-generator-patternfly-theme/tests/__snapshots__/SelectField.test.tsx.snap @@ -2,12 +2,12 @@ exports[` tests - multiple value rendering 1`] = `
- {"ref":{"binding":"otherPositions","stateName":"otherPositions","stateSetter":"set__otherPositions","dataType":{"name":"string[]","defaultValue":"[]"}},"pfImports":["SelectOption","SelectOptionObject","Select","SelectVariant","FormGroup"],"reactImports":["useState"],"requiredCode":["multiple_select_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'OtherPositions'}\\n isRequired={true}\\n ><Select\\n id={'id'}\\n name={'otherPositions'}\\n variant={SelectVariant.typeaheadMulti}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={otherPositions__expanded}\\n selections={otherPositions}\\n onToggle={(isOpen) => set__otherPositions__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => {\\n handleMultipleSelect(value, isPlaceHolder, otherPositions, set__otherPositions)\\n }}\\n value={otherPositions}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>","stateCode":"const [ otherPositions, set__otherPositions ] = useState<string[]>([]);\\nconst [ otherPositions__expanded, set__otherPositions__expanded ] = useState<boolean>(false);","isReadonly":false} + {"ref":{"binding":"otherPositions","stateName":"otherPositions","stateSetter":"set__otherPositions","dataType":{"name":"string[]","defaultValue":"[]"}},"pfImports":["SelectOption","SelectOptionObject","Select","SelectVariant","FormGroup"],"reactImports":["useState"],"requiredCode":["multiple_select_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'OtherPositions'}\\n isRequired={true}\\n ><Select\\n id={'id'}\\n name={'otherPositions'}\\n variant={SelectVariant.typeaheadMulti}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={otherPositions__expanded}\\n selections={otherPositions}\\n onToggle={(isOpen) => set__otherPositions__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => handleMultipleSelect(value, isPlaceHolder, otherPositions, set__otherPositions)}\\n value={otherPositions}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>","stateCode":"const [ otherPositions, set__otherPositions ] = useState<string[]>([]);\\nconst [ otherPositions__expanded, set__otherPositions__expanded ] = useState<boolean>(false);","isReadonly":false}
`; exports[` tests - single value rendering 1`] = `
- {"ref":{"binding":"role","stateName":"role","stateSetter":"set__role","dataType":{"name":"string","defaultValue":"\\"\\""}},"pfImports":["SelectOption","SelectOptionObject","Select","SelectVariant","FormGroup"],"reactImports":["useState"],"requiredCode":["select_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'Role'}\\n isRequired={true}\\n ><Select\\n id={'id'}\\n name={'role'}\\n variant={SelectVariant.single}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={role__expanded}\\n selections={role}\\n onToggle={(isOpen) => set__role__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => {\\n handleSelect(value, isPlaceHolder, role, set__role, set__role__expanded)\\n }}\\n value={role}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>","stateCode":"const [ role, set__role ] = useState<string>(\\"\\");\\nconst [ role__expanded, set__role__expanded ] = useState<boolean>(false);","isReadonly":false} + {"ref":{"binding":"role","stateName":"role","stateSetter":"set__role","dataType":{"name":"string","defaultValue":"\\"\\""}},"pfImports":["SelectOption","SelectOptionObject","Select","SelectVariant","FormGroup"],"reactImports":["useState"],"requiredCode":["select_functions"],"jsxCode":"<FormGroup\\n fieldId={'id'}\\n label={'Role'}\\n isRequired={true}\\n ><Select\\n id={'id'}\\n name={'role'}\\n variant={SelectVariant.single}\\n isDisabled={false}\\n placeholderText={''}\\n isOpen={role__expanded}\\n selections={role}\\n onToggle={(isOpen) => set__role__expanded(isOpen)}\\n onSelect={(event, value, isPlaceHolder) => handleSelect(value, isPlaceHolder, role, set__role, set__role__expanded)}\\n value={role}\\n >\\n <SelectOption key={'Developer'} value={'Developer'}>Developer</SelectOption>\\n<SelectOption key={'HR'} value={'HR'}>HR</SelectOption>\\n<SelectOption key={'UX'} value={'UX'}>UX</SelectOption>\\n </Select></FormGroup>","stateCode":"const [ role, set__role ] = useState<string>(\\"\\");\\nconst [ role__expanded, set__role__expanded ] = useState<boolean>(false);","isReadonly":false}
`;