diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.component.tsx deleted file mode 100644 index 7e75978eb16..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.component.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2023 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 { Button, Modal } from 'antd'; -import { useForm } from 'antd/lib/form/Form'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import { CreateDataProduct } from '../../../generated/api/domains/createDataProduct'; -import { CreateDomain } from '../../../generated/api/domains/createDomain'; -import AddDomainForm from '../AddDomainForm/AddDomainForm.component'; -import { DomainFormType } from '../DomainPage.interface'; -import { AddDataProductModalProps } from './AddDataProductModal.interface'; - -const AddDataProductModal = ({ - open, - onSubmit, - onCancel, -}: AddDataProductModalProps) => { - const { t } = useTranslation(); - const [form] = useForm(); - - const handleFormSubmit = async ( - formData: CreateDomain | CreateDataProduct - ) => { - onSubmit(formData); - }; - - return ( - - {t('label.cancel')} - , - , - ]} - maskClosable={false} - okText={t('label.submit')} - open={open} - title={t('label.add-entity', { entity: t('label.data-product') })} - width={750} - onCancel={onCancel}> - - - ); -}; - -export default AddDataProductModal; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.interface.ts deleted file mode 100644 index 261787ed970..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.interface.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2023 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 { CreateDataProduct } from '../../../generated/api/domains/createDataProduct'; -import { CreateDomain } from '../../../generated/api/domains/createDomain'; -import { Domain } from '../../../generated/entity/domains/domain'; - -export interface AddDataProductModalProps { - open: boolean; - data?: Domain; - onCancel: () => void; - onSubmit: (data: CreateDomain | CreateDataProduct) => Promise; -} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.test.tsx deleted file mode 100644 index 332666d087b..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDataProductModal/AddDataProductModal.test.tsx +++ /dev/null @@ -1,83 +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 { act, fireEvent, render, screen } from '@testing-library/react'; -import React from 'react'; -import AddDataProductModal from './AddDataProductModal.component'; - -const formData = { - description: 'test-description', - name: 'test-name', -}; - -const mockSubmit = jest.fn(); -const mockCancel = jest.fn(); -const mockSave = jest.fn(); - -const mockProps = { - open: true, - onSubmit: mockSubmit, - onCancel: mockCancel, -}; - -jest.mock('../AddDomainForm/AddDomainForm.component', () => { - return jest.fn().mockImplementation(({ onSubmit }) => ( -
- AddDomainForm - -
- )); -}); - -jest.mock('antd/lib/form/Form', () => ({ - useForm: () => [ - { - submit: mockSave, - }, - ], -})); - -describe('Test AddDataProductModal Component', () => { - it('Should Render Add Data Product Modal Component', async () => { - render(); - - expect(await screen.findByText('label.add-entity')).toBeInTheDocument(); - expect(await screen.findByText('AddDomainForm')).toBeInTheDocument(); - expect(await screen.findByText('label.cancel')).toBeInTheDocument(); - expect(await screen.findByText('label.save')).toBeInTheDocument(); - }); - - it('Should call onSubmit function', async () => { - render(); - - const submitButton = await screen.findByTestId('submit-button'); - await act(async () => { - fireEvent.click(submitButton); - }); - - expect(mockSubmit).toHaveBeenCalledWith(formData); - }); - - it('should call form.submit when save button is clicked', async () => { - await act(async () => { - render(); - }); - const button = await screen.findByTestId('save-data-product'); - await act(async () => { - fireEvent.click(button); - }); - - expect(mockSave).toHaveBeenCalled(); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomain/AddDomain.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomain/AddDomain.component.tsx index 6b1e970c958..49f1be43859 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomain/AddDomain.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomain/AddDomain.component.tsx @@ -11,7 +11,6 @@ * limitations under the License. */ import { Typography } from 'antd'; -import { useForm } from 'antd/lib/form/Form'; import { AxiosError } from 'axios'; import React, { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -33,7 +32,6 @@ import './add-domain.less'; const AddDomain = () => { const { t } = useTranslation(); const history = useHistory(); - const [form] = useForm(); const [isLoading, setIsLoading] = useState(false); const { refreshDomains } = useDomainProvider(); @@ -114,7 +112,6 @@ const AddDomain = () => { })} { const { t } = useTranslation(); + const [form] = Form.useForm(formRef); const { permissions } = usePermissionProvider(); const domainTypeArray = Object.keys(DomainType).map((key) => ({ @@ -235,67 +236,64 @@ const AddDomainForm = ({ }; return ( - <> -
-
- {generateFormFields(formFields)} -
- {getField(ownerField)} - {selectedOwner && ( -
- -
- )} + + {generateFormFields(formFields)} +
+ {getField(ownerField)} + {selectedOwner && ( +
+
-
- {getField(expertsField)} - {Boolean(expertsList.length) && ( - - {expertsList.map((d) => ( - - ))} - - )} -
- - {!isFormInDialog && ( - - - - - )} - + )}
- +
+ {getField(expertsField)} + {Boolean(expertsList.length) && ( + + {expertsList.map((d) => ( + + ))} + + )} +
+ + {!isFormInDialog && ( + + + + + )} + ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.interface.ts index eda54bf0481..eefdc1c3b8c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.interface.ts @@ -19,7 +19,7 @@ export interface AddDomainFormProps { isFormInDialog: boolean; onCancel: () => void; onSubmit: (data: CreateDomain | CreateDataProduct) => Promise; - formRef: FormInstance; + formRef?: FormInstance; loading: boolean; type: DomainFormType; } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.test.tsx new file mode 100644 index 00000000000..65eed4b8435 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Domain/AddDomainForm/AddDomainForm.test.tsx @@ -0,0 +1,122 @@ +/* + * 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 { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import { DomainFormType } from '../DomainPage.interface'; +import AddDomainForm from './AddDomainForm.component'; + +jest.mock('antd', () => ({ + ...jest.requireActual('antd'), + Button: jest + .fn() + .mockImplementation(({ loading, children, ...rest }) => ( + + )), +})); + +jest.mock('../../../components/common/UserTag/UserTag.component', () => ({ + UserTag: jest.fn().mockImplementation(() =>

UserTag

), +})); + +jest.mock('../../../context/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockReturnValue({ + permissions: { + glossary: { + Create: true, + }, + }, + }), +})); + +jest.mock('../../../utils/EntityUtils', () => ({ + getEntityName: jest.fn().mockReturnValue('getEntityName'), +})); + +jest.mock('../../../utils/DomainUtils', () => ({ + domainTypeTooltipDataRender: jest + .fn() + .mockReturnValue(

domainTypeTooltipDataRender

), +})); + +jest.mock('../../../utils/PermissionsUtils', () => ({ + checkPermission: jest.fn().mockReturnValue(true), +})); + +const mockOnCancel = jest.fn(); +const mockOnSubmit = jest.fn(); + +const mockProps = { + loading: false, + isFormInDialog: false, + onCancel: mockOnCancel, + onSubmit: mockOnSubmit, + type: DomainFormType.DOMAIN, +}; + +describe('Test Add Domain component', () => { + it('Should render content of form', async () => { + render(); + + expect(screen.getByText('label.name')).toBeInTheDocument(); + expect(screen.getByTestId('name')).toBeInTheDocument(); + expect(screen.getByText('label.display-name')).toBeInTheDocument(); + expect(screen.getByTestId('display-name')).toBeInTheDocument(); + expect(screen.getByText('label.description')).toBeInTheDocument(); + expect(screen.getByTestId('editor')).toBeInTheDocument(); + expect(screen.getByText('label.icon-url')).toBeInTheDocument(); + expect(screen.getByTestId('icon-url')).toBeInTheDocument(); + expect(screen.getByText('label.color')).toBeInTheDocument(); + expect(screen.getByTestId('color-picker')).toBeInTheDocument(); + expect(screen.getByTestId('color-input')).toBeInTheDocument(); + expect(screen.getByText('label.domain-type')).toBeInTheDocument(); + expect(screen.getAllByTestId('helper-icon')).toHaveLength(2); + expect(screen.getByText('label.owner')).toBeInTheDocument(); + expect(screen.getByTestId('add-owner')).toBeInTheDocument(); + expect(screen.getByText('label.expert-plural')).toBeInTheDocument(); + expect(screen.getByTestId('add-experts')).toBeInTheDocument(); + expect(screen.getByTestId('cancel-domain')).toBeInTheDocument(); + expect(screen.getByTestId('save-domain')).toBeInTheDocument(); + }); + + it('Should show loading button', async () => { + render(); + + expect(screen.getByText('Loader.Button')).toBeInTheDocument(); + }); + + it('Should trigger onCancel', async () => { + render(); + fireEvent.click(screen.getByText('label.cancel')); + + expect(mockOnCancel).toHaveBeenCalled(); + }); + + it('Should not show footer button if form is in dialog box', async () => { + render(); + + expect(screen.queryByTestId('cta-buttons')).not.toBeInTheDocument(); + }); + + it('Should not trigger onSubmit if required element are not filled', async () => { + render(); + fireEvent.click(screen.getByTestId('save-domain')); + + expect(mockOnSubmit).not.toHaveBeenCalled(); + }); + + it('Should not show domain type if type is not DOMAIN', async () => { + render(); + + expect(screen.queryByText('label.domain-type')).not.toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Domain/DomainDetailsPage/DomainDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Domain/DomainDetailsPage/DomainDetailsPage.component.tsx index 767b1b4aee3..83846e9a700 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Domain/DomainDetailsPage/DomainDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Domain/DomainDetailsPage/DomainDetailsPage.component.tsx @@ -15,6 +15,7 @@ import { Button, Col, Dropdown, + Modal, Row, Space, Tabs, @@ -22,6 +23,7 @@ import { Typography, } from 'antd'; import ButtonGroup from 'antd/lib/button/button-group'; +import { useForm } from 'antd/lib/form/Form'; import { ItemType } from 'antd/lib/menu/hooks/useItems'; import { AxiosError } from 'axios'; import classNames from 'classnames'; @@ -65,7 +67,6 @@ import { import { EntityType } from '../../../enums/entity.enum'; import { SearchIndex } from '../../../enums/search.enum'; import { CreateDataProduct } from '../../../generated/api/domains/createDataProduct'; -import { CreateDomain } from '../../../generated/api/domains/createDomain'; import { DataProduct } from '../../../generated/entity/domains/dataProduct'; import { Domain } from '../../../generated/entity/domains/domain'; import { ChangeDescription } from '../../../generated/entity/type'; @@ -94,9 +95,9 @@ import TabsLabel from '../../common/TabsLabel/TabsLabel.component'; import { AssetSelectionModal } from '../../DataAssets/AssetsSelectionModal/AssetSelectionModal'; import { EntityDetailsObjectInterface } from '../../Explore/ExplorePage.interface'; import StyleModal from '../../Modals/StyleModal/StyleModal.component'; -import AddDataProductModal from '../AddDataProductModal/AddDataProductModal.component'; +import AddDomainForm from '../AddDomainForm/AddDomainForm.component'; import '../domain.less'; -import { DomainTabs } from '../DomainPage.interface'; +import { DomainFormType, DomainTabs } from '../DomainPage.interface'; import DataProductsTab from '../DomainTabs/DataProductsTab/DataProductsTab.component'; import { DataProductsTabRef } from '../DomainTabs/DataProductsTab/DataProductsTab.interface'; import DocumentationTab from '../DomainTabs/DocumentationTab/DocumentationTab.component'; @@ -109,6 +110,7 @@ const DomainDetailsPage = ({ isVersionsView = false, }: DomainDetailsPageProps) => { const { t } = useTranslation(); + const [form] = useForm(); const { getEntityPermission } = usePermissionProvider(); const history = useHistory(); const { tab: activeTab, version } = @@ -345,6 +347,11 @@ const DomainDetailsPage = ({ setPreviewAsset(asset); }, []); + const handleCloseDataProductModal = useCallback( + () => setShowAddDataProductModal(false), + [] + ); + const manageButtonContent: ItemType[] = [ ...(editDisplayNamePermission ? ([ @@ -639,13 +646,41 @@ const DomainDetailsPage = ({ {showAddDataProductModal && ( - + {t('label.cancel')} + , + , + ]} + maskClosable={false} + okText={t('label.submit')} open={showAddDataProductModal} - onCancel={() => setShowAddDataProductModal(false)} - onSubmit={(data: CreateDomain | CreateDataProduct) => - addDataProduct(data as CreateDataProduct) - } - /> + title={t('label.add-entity', { entity: t('label.data-product') })} + width={750} + onCancel={handleCloseDataProductModal}> + + )} {assetModalVisible && (