Skip to content

Commit

Permalink
fix(557) - Enforce required name and type in beans forms
Browse files Browse the repository at this point in the history
  • Loading branch information
tplevko committed Feb 16, 2024
1 parent a6f2464 commit e40aeb1
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 9 deletions.
4 changes: 3 additions & 1 deletion packages/ui/src/components/Form/CustomAutoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ interface CustomAutoFormProps extends IDataTestID {
omitFields?: string[];
onChangeModel?: (model: unknown) => void;
onChange?: (path: string, value: unknown) => void;
handleConfirm?: () => void;
submitRef?: React.RefObject<HTMLButtonElement>;
}

export type CustomAutoFormRef = { fields: HTMLElement[]; form: typeof AutoForm };
Expand Down Expand Up @@ -45,7 +47,6 @@ export const CustomAutoForm = forwardRef<CustomAutoFormRef, CustomAutoFormProps>
fields: fieldsRefs.current,
form: formRef.current,
}));

return (
<AutoField.componentDetectorContext.Provider value={CustomAutoFieldDetector}>
<AutoForm
Expand All @@ -56,6 +57,7 @@ export const CustomAutoForm = forwardRef<CustomAutoFormRef, CustomAutoFormProps>
onChange={props.onChange}
data-testid={props['data-testid']}
disabled={props.disabled}
onSubmit={props.handleConfirm}
>
{props.sortFields ? (
// For some forms, sorting its fields might be beneficial
Expand Down
7 changes: 5 additions & 2 deletions packages/ui/src/components/Form/bean/NewBeanModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NewBeanModal } from './NewBeanModal';
import { fireEvent, render } from '@testing-library/react';
import { screen } from '@testing-library/dom';
import * as catalogIndex from '@kaoto-next/camel-catalog/index.json';
import { act } from 'react-dom/test-utils';

describe('NewBeanModal', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -11,7 +12,7 @@ describe('NewBeanModal', () => {
beanSchema = entitiesCatalog.bean.propertiesSchema;
});

it('should render', () => {
it('should render', async () => {
const mockOnCreate = jest.fn();
const mockOnCancel = jest.fn();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -26,12 +27,14 @@ describe('NewBeanModal', () => {
);
const nameTeextbox = screen.getAllByRole('textbox').filter((textbox) => textbox.getAttribute('label') === 'Name');
fireEvent.input(nameTeextbox[0], { target: { value: 'foo' } });
const labelTeextbox = screen.getAllByRole('textbox').filter((textbox) => textbox.getAttribute('label') === 'Type');
fireEvent.input(labelTeextbox[0], { target: { value: 'bar' } });
const createButton = screen
.getAllByRole('button')
.filter((button) => button.textContent && button.textContent === 'Create');
expect(createButton).toHaveLength(1);
expect(mockOnCreate.mock.calls).toHaveLength(0);
fireEvent.click(createButton[0]);
await act(async () => fireEvent.click(createButton[0]));
expect(mockOnCreate.mock.calls).toHaveLength(1);
expect(mockOnCreate.mock.calls[0][0].name).toEqual('foo');

Expand Down
15 changes: 12 additions & 3 deletions packages/ui/src/components/Form/bean/NewBeanModal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { RegistryBeanDefinition } from '@kaoto-next/camel-catalog/types';
import { Button, Modal } from '@patternfly/react-core';
import { FunctionComponent, useCallback, useEffect, useState } from 'react';
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react';
import { KaotoSchemaDefinition } from '../../../models';
import { MetadataEditor } from '../../MetadataEditor';
import { CustomAutoFormRef } from '../CustomAutoForm';

export type NewBeanModalProps = {
beanSchema: KaotoSchemaDefinition['schema'];
Expand All @@ -17,13 +18,19 @@ export type NewBeanModalProps = {
export const NewBeanModal: FunctionComponent<NewBeanModalProps> = (props: NewBeanModalProps) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [beanModel, setBeanModel] = useState<any>();
const submitRef = useRef<CustomAutoFormRef>(null);

useEffect(() => {
setBeanModel(props.beanName ? { name: props.beanName } : {});
}, [props.beanName]);

const handleConfirm = useCallback(() => {
props.onCreateBean(beanModel as RegistryBeanDefinition);
const handleConfirm = useCallback(async () => {
// validation updates the bean model, so we need to clone it to avoid creating the bean with default values
const beanModelTmp = { ...beanModel };
const valid = await submitRef.current?.form.validate();
if (valid === undefined || valid === null) {
props.onCreateBean(beanModelTmp as RegistryBeanDefinition);
}
}, [beanModel, props]);

const handleCancel = useCallback(() => {
Expand Down Expand Up @@ -53,6 +60,8 @@ export const NewBeanModal: FunctionComponent<NewBeanModalProps> = (props: NewBea
schema={props.beanSchema}
metadata={beanModel}
onChangeModel={setBeanModel}
handleConfirm={handleConfirm}
ref={submitRef}
/>
</Modal>
)
Expand Down
17 changes: 14 additions & 3 deletions packages/ui/src/components/MetadataEditor/MetadataEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Split, SplitItem, Stack, StackItem, Title } from '@patternfly/react-core';
import cloneDeep from 'lodash/cloneDeep';
import { FunctionComponent, PropsWithChildren, useEffect, useRef, useState } from 'react';
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { JSONSchemaBridge } from 'uniforms-bridge-json-schema';
import { SchemaService } from '../Form';
import { CustomAutoForm, CustomAutoFormRef } from '../Form/CustomAutoForm';
Expand All @@ -15,9 +15,11 @@ interface MetadataEditorProps {
metadata: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onChangeModel: (model: any) => void;
handleConfirm?: () => void;
submitRef?: React.RefObject<HTMLButtonElement>;
}

export const MetadataEditor: FunctionComponent<PropsWithChildren<MetadataEditorProps>> = (props) => {
export const MetadataEditor = forwardRef<CustomAutoFormRef, MetadataEditorProps>((props, forwardedRef) => {
const schemaServiceRef = useRef(new SchemaService());
const [schemaBridge, setSchemaBridge] = useState<JSONSchemaBridge | undefined>(
schemaServiceRef.current.getSchemaBridge(getFormSchema()),
Expand All @@ -27,6 +29,11 @@ export const MetadataEditor: FunctionComponent<PropsWithChildren<MetadataEditorP
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [preparedModel, setPreparedModel] = useState<any>(null);

useImperativeHandle(forwardedRef, () => ({
fields: fieldsRefs.current?.fields ?? [],
form: fieldsRefs.current?.form,
}));

useEffect(() => {
setSchemaBridge(schemaServiceRef.current.getSchemaBridge(getFormSchema()));
}, [props.schema]);
Expand Down Expand Up @@ -121,6 +128,8 @@ export const MetadataEditor: FunctionComponent<PropsWithChildren<MetadataEditorP
disabled={isFormDisabled()}
sortFields={true}
ref={fieldsRefs}
handleConfirm={props.handleConfirm}
submitRef={props.submitRef}
/>
</StackItem>
</Stack>
Expand All @@ -135,8 +144,10 @@ export const MetadataEditor: FunctionComponent<PropsWithChildren<MetadataEditorP
disabled={isFormDisabled()}
sortFields={true}
ref={fieldsRefs}
handleConfirm={props.handleConfirm}
submitRef={props.submitRef}
/>
)}
</>
);
};
});

0 comments on commit e40aeb1

Please sign in to comment.