From d474e427a11df3c027a487e099a558fd8961710f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:40:20 +0000 Subject: [PATCH 1/6] Initial plan From b87d98bb46c4c42e6c5268bcc1ca8d3ac2d72aac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:49:34 +0000 Subject: [PATCH 2/6] Add pure MUI components to core library and update formUtils to use them Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com> --- .../ui/src/components/MUIForm/MUIForm.tsx | 47 ++++++++++++++ .../components/MUIFormItem/MUIFormItem.tsx | 54 ++++++++++++++++ .../components/MUITextField/MUITextField.tsx | 34 +++++++++++ .../main/resources/ui/src/components/index.ts | 3 + .../main/resources/ui/src/utils/formUtils.tsx | 61 +++++++++++++++---- 5 files changed, 186 insertions(+), 13 deletions(-) create mode 100644 openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx create mode 100644 openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIFormItem/MUIFormItem.tsx create mode 100644 openmetadata-ui-core-components/src/main/resources/ui/src/components/MUITextField/MUITextField.tsx diff --git a/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx new file mode 100644 index 000000000000..01f4ec3fa5ed --- /dev/null +++ b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2025 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Box, BoxProps } from '@mui/material'; +import { FC, FormEvent, ReactNode } from 'react'; + +interface MUIFormProps { + onSubmit?: (event: FormEvent) => void; + onReset?: (event: FormEvent) => void; + children: ReactNode; + className?: string; + id?: string; + sx?: BoxProps['sx']; +} + +const MUIForm: FC = ({ + onSubmit, + onReset, + children, + className, + id, + sx, +}) => { + return ( + + {children} + + ); +}; + +export default MUIForm; diff --git a/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIFormItem/MUIFormItem.tsx b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIFormItem/MUIFormItem.tsx new file mode 100644 index 000000000000..a17b6ae5b1c2 --- /dev/null +++ b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIFormItem/MUIFormItem.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2025 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { FormControl, FormHelperText } from '@mui/material'; +import { FC, ReactNode } from 'react'; + +interface MUIFormItemProps { + label?: ReactNode; + error?: boolean; + helperText?: ReactNode; + required?: boolean; + children: ReactNode; + className?: string; + id?: string; + fullWidth?: boolean; +} + +const MUIFormItem: FC = ({ + label, + error, + helperText, + required, + children, + className, + id, + fullWidth = true, +}) => { + return ( + + {label} + {children} + {helperText && ( + {helperText} + )} + + ); +}; + +export default MUIFormItem; diff --git a/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUITextField/MUITextField.tsx b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUITextField/MUITextField.tsx new file mode 100644 index 000000000000..02c46afa7d28 --- /dev/null +++ b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUITextField/MUITextField.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2025 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { TextField, TextFieldProps } from '@mui/material'; +import { FC, memo } from 'react'; + +interface MUITextFieldProps extends Omit { + variant?: 'outlined' | 'filled' | 'standard'; + size?: 'small' | 'medium'; +} + +const MUITextField: FC = ({ + size = 'small', + ...props +}) => { + return ( + + ); +}; + +export default memo(MUITextField); diff --git a/openmetadata-ui-core-components/src/main/resources/ui/src/components/index.ts b/openmetadata-ui-core-components/src/main/resources/ui/src/components/index.ts index b4541b5e90b1..53b95a421de2 100644 --- a/openmetadata-ui-core-components/src/main/resources/ui/src/components/index.ts +++ b/openmetadata-ui-core-components/src/main/resources/ui/src/components/index.ts @@ -1,3 +1,6 @@ // Component exports export * from "./checkbox-icons"; +export { default as MUITextField } from './MUITextField/MUITextField'; +export { default as MUIForm } from './MUIForm/MUIForm'; +export { default as MUIFormItem } from './MUIFormItem/MUIFormItem'; export { SnackbarContent } from "./SnackbarContent"; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx index 9099bac3cd8a..f87b52a56565 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx @@ -11,6 +11,7 @@ * limitations under the License. */ import { TooltipProps as MUITooltipProps } from '@mui/material/Tooltip'; +import { MUIFormItem, MUITextField } from '@openmetadata/ui-core-components'; import { ErrorTransformer } from '@rjsf/utils'; import { Alert, @@ -30,7 +31,7 @@ import { TooltipPlacement } from 'antd/lib/tooltip'; import { AxiosError } from 'axios'; import classNames from 'classnames'; import { compact, startCase, toString } from 'lodash'; -import { Fragment, ReactNode } from 'react'; +import { ChangeEvent, Fragment, ReactNode } from 'react'; import AsyncSelectList from '../components/common/AsyncSelectList/AsyncSelectList'; import { AsyncSelectListProps } from '../components/common/AsyncSelectList/AsyncSelectList.interface'; import TreeAsyncSelectList from '../components/common/AsyncSelectList/TreeAsyncSelectList'; @@ -50,7 +51,6 @@ import MUIFormItemLabel from '../components/common/MUIFormItemLabel'; import MUIGlossaryTagSuggestion from '../components/common/MUIGlossaryTagSuggestion/MUIGlossaryTagSuggestion'; import MUISelect from '../components/common/MUISelect/MUISelect'; import MUITagSuggestion from '../components/common/MUITagSuggestion/MUITagSuggestion'; -import MUITextField from '../components/common/MUITextField/MUITextField'; import MUIUserTeamSelect, { MUIUserTeamSelectProps, } from '../components/common/MUIUserTeamSelect/MUIUserTeamSelect'; @@ -75,6 +75,7 @@ import TagSuggestion, { TagSuggestionProps, } from '../pages/TasksPage/shared/TagSuggestion'; import { t } from './i18next/LocalUtil'; +import { getSanitizeContent } from './sanitize.utils'; import { getErrorText } from './StringsUtils'; export const getField = (field: FieldProp) => { @@ -145,48 +146,82 @@ export const getField = (field: FieldProp) => { break; case FieldTypes.TEXT_MUI: { - const { error, ...muiProps } = props; + const { error, onChange, value, ...muiProps } = props; const isRequired = fieldRules.some( (rule) => (rule as RuleObject).required ); + // Handle sanitization on change + const handleChange = (e: ChangeEvent) => { + const sanitizedValue = getSanitizeContent(e.target.value); + if (onChange) { + (onChange as (e: ChangeEvent) => void)({ + ...e, + target: { ...e.target, value: sanitizedValue }, + }); + } + }; + return ( - + > + + ); } case FieldTypes.PASSWORD_MUI: { - const { error, ...muiProps } = props; + const { error, onChange, value, ...muiProps } = props; const isRequired = fieldRules.some( (rule) => (rule as RuleObject).required ); + // Handle sanitization on change + const handleChange = (e: ChangeEvent) => { + const sanitizedValue = getSanitizeContent(e.target.value); + if (onChange) { + (onChange as (e: ChangeEvent) => void)({ + ...e, + target: { ...e.target, value: sanitizedValue }, + }); + } + }; + return ( - + > + + ); } From 65c840217a8e39274b43775d7d99a2a3dff4bdfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:53:52 +0000 Subject: [PATCH 3/6] Remove unnecessary MUIFormItem wrapper from formUtils Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com> --- .../main/resources/ui/src/utils/formUtils.tsx | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx index f87b52a56565..b64012f663aa 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.tsx @@ -11,7 +11,7 @@ * limitations under the License. */ import { TooltipProps as MUITooltipProps } from '@mui/material/Tooltip'; -import { MUIFormItem, MUITextField } from '@openmetadata/ui-core-components'; +import { MUITextField } from '@openmetadata/ui-core-components'; import { ErrorTransformer } from '@rjsf/utils'; import { Alert, @@ -164,23 +164,19 @@ export const getField = (field: FieldProp) => { return ( - - - + value={value} + onChange={handleChange} + {...muiProps} + /> ); } @@ -204,24 +200,20 @@ export const getField = (field: FieldProp) => { return ( - - - + type="password" + value={value} + onChange={handleChange} + {...muiProps} + /> ); } From 26689eb9cda87044b7c3f9799557da02a30429d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:54:55 +0000 Subject: [PATCH 4/6] Add tests for TEXT_MUI and PASSWORD_MUI field types Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com> --- .../resources/ui/src/utils/formUtils.test.tsx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.test.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.test.tsx index f72880541455..dfd2fedc305d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/formUtils.test.tsx @@ -73,6 +73,44 @@ describe('formUtils', () => { expect(JSON.stringify(result)).not.toContain('form-item-alert'); }); + + it('Should render TEXT_MUI field type with MUITextField from core components', async () => { + const result = getField({ + name: 'testField', + label: 'Test Field', + type: FieldTypes.TEXT_MUI, + required: true, + helperText: 'This is a helper text', + helperTextType: HelperTextType.ALERT, + props: { + 'data-testid': 'test-text-field', + }, + id: 'root/testField', + formItemLayout: FormItemLayout.VERTICAL, + }); + + // Verify the result contains MUITextField + const resultString = JSON.stringify(result); + expect(resultString).toContain('testField'); + }); + + it('Should render PASSWORD_MUI field type with type password', async () => { + const result = getField({ + name: 'passwordField', + label: 'Password Field', + type: FieldTypes.PASSWORD_MUI, + required: true, + props: { + 'data-testid': 'test-password-field', + }, + id: 'root/passwordField', + formItemLayout: FormItemLayout.VERTICAL, + }); + + // Verify the result contains password type + const resultString = JSON.stringify(result); + expect(resultString).toContain('password'); + }); }); describe('createScrollToErrorHandler', () => { From 1c9d07eebf28bbae7c336675ea8c85de64bcc563 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 07:55:40 +0000 Subject: [PATCH 5/6] Remove old MUITextField component from openmetadata-ui Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com> --- .../common/MUITextField/MUITextField.tsx | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/common/MUITextField/MUITextField.tsx diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/MUITextField/MUITextField.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/MUITextField/MUITextField.tsx deleted file mode 100644 index e7e4f7b23bf3..000000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/MUITextField/MUITextField.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Collate. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { TextField, TextFieldProps } from '@mui/material'; -import { ChangeEvent, FC, memo, useCallback } from 'react'; -import { getSanitizeContent } from '../../../utils/sanitize.utils'; - -interface MUITextFieldProps extends Omit { - variant?: 'outlined' | 'filled' | 'standard'; - size?: 'small' | 'medium'; -} - -const MUITextField: FC = ({ - value, - onChange, - variant, - size = 'small', - ...props -}) => { - const handleChange = useCallback( - (e: ChangeEvent) => { - const sanitizedValue = getSanitizeContent(e.target.value); - if (onChange) { - onChange({ ...e, target: { ...e.target, value: sanitizedValue } }); - } - }, - [onChange] - ); - - return ( - - ); -}; - -export default memo(MUITextField); From 6ee1e831d9ca626a2233ce218fd06a7f475a70b1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 08:05:34 +0000 Subject: [PATCH 6/6] Remove 'as any' type casts from MUIForm component Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com> --- .../resources/ui/src/components/MUIForm/MUIForm.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx index 01f4ec3fa5ed..6943200199a6 100644 --- a/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx +++ b/openmetadata-ui-core-components/src/main/resources/ui/src/components/MUIForm/MUIForm.tsx @@ -11,11 +11,11 @@ * limitations under the License. */ import { Box, BoxProps } from '@mui/material'; -import { FC, FormEvent, ReactNode } from 'react'; +import { ComponentProps, FC, ReactNode } from 'react'; interface MUIFormProps { - onSubmit?: (event: FormEvent) => void; - onReset?: (event: FormEvent) => void; + onSubmit?: ComponentProps<'form'>['onSubmit']; + onReset?: ComponentProps<'form'>['onReset']; children: ReactNode; className?: string; id?: string; @@ -33,8 +33,8 @@ const MUIForm: FC = ({ return (