From 04d3720df9ad8edce92f8445ccdabf06c7be45b4 Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Tue, 25 Jun 2024 11:09:53 +0530 Subject: [PATCH] Display inspection query (#16766) * Display inspection query * added reset for global state * fixed test failure --- .../TestCaseIncidentTab.component.tsx | 7 +- .../TestCaseIncidentTab.test.tsx | 16 +++ .../TestCaseResultTab.component.tsx | 14 +- .../TestCaseResultTab.interface.ts | 19 --- .../TestCaseResultTab.test.tsx | 99 +++++++------- .../IncidentManager.interface.ts | 1 + .../IncidentManagerDetailPage.test.tsx | 16 +++ .../IncidentManagerDetailPage.tsx | 124 +++++++----------- .../TestCaseClassBase.ts | 77 +++++++++++ .../useTestCase.store.ts | 35 +++++ 10 files changed, 257 insertions(+), 151 deletions(-) delete mode 100644 openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.interface.ts create mode 100644 openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/TestCaseClassBase.ts create mode 100644 openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store.ts diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component.tsx index ee87fb2245a..79f220b6d87 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component.tsx @@ -30,9 +30,9 @@ import { Thread, ThreadTaskStatus, } from '../../../../generated/entity/feed/thread'; -import { EntityReference } from '../../../../generated/entity/type'; import { useElementInView } from '../../../../hooks/useElementInView'; import { useFqn } from '../../../../hooks/useFqn'; +import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store'; import ActivityFeedListV1 from '../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1.component'; import { useActivityFeedProvider } from '../../../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; import { TaskFilter } from '../../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface'; @@ -40,9 +40,12 @@ import Loader from '../../../common/Loader/Loader'; import { TaskTab } from '../../../Entity/Task/TaskTab/TaskTab.component'; import './test-case-incident-tab.style.less'; -const TestCaseIncidentTab = ({ owner }: { owner?: EntityReference }) => { +const TestCaseIncidentTab = () => { const { t } = useTranslation(); const { fqn: decodedFqn } = useFqn(); + const { testCase } = useTestCaseStore(); + + const owner = useMemo(() => testCase?.owner, [testCase]); const { selectedThread, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.test.tsx index 624160b16bf..c7c585de9c0 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.test.tsx @@ -25,6 +25,22 @@ const mockUseActivityFeedProviderValue = { setActiveThread: jest.fn(), }; +jest.mock( + '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store', + () => ({ + useTestCaseStore: jest.fn().mockImplementation(() => ({ + testCase: { + owner: { + name: 'arron_johnson', + displayName: 'Arron Johnson', + id: '1', + type: 'user', + }, + }, + })), + }) +); + jest.mock('../../../Entity/Task/TaskTab/TaskTab.component', () => { return { TaskTab: jest.fn().mockImplementation(({ onAfterClose }) => ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx index 950f72b93b4..84ca22742c9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component.tsx @@ -30,6 +30,7 @@ import { EntityType } from '../../../../enums/entity.enum'; import { Operation } from '../../../../generated/entity/policies/policy'; import { TestCaseParameterValue } from '../../../../generated/tests/testCase'; +import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store'; import { updateTestCaseById } from '../../../../rest/testAPI'; import { checkPermission } from '../../../../utils/PermissionsUtils'; import { showErrorToast, showSuccessToast } from '../../../../utils/ToastUtils'; @@ -39,14 +40,11 @@ import SchemaEditor from '../../../Database/SchemaEditor/SchemaEditor'; import EditTestCaseModal from '../../AddDataQualityTest/EditTestCaseModal'; import '../incident-manager.style.less'; import './test-case-result-tab.style.less'; -import { TestCaseResultTabProps } from './TestCaseResultTab.interface'; import testCaseResultTabClassBase from './TestCaseResultTabClassBase'; -const TestCaseResultTab = ({ - testCaseData, - onTestCaseUpdate, -}: TestCaseResultTabProps) => { +const TestCaseResultTab = () => { const { t } = useTranslation(); + const { testCase: testCaseData, setTestCase } = useTestCaseStore(); const additionalComponent = testCaseResultTabClassBase.getAdditionalComponents(); const [isDescriptionEdit, setIsDescriptionEdit] = useState(false); @@ -95,7 +93,7 @@ const TestCaseResultTab = ({ testCaseData.id ?? '', jsonPatch ); - onTestCaseUpdate(res); + setTestCase(res); showSuccessToast( t('server.update-entity-success', { entity: t('label.test-case'), @@ -109,7 +107,7 @@ const TestCaseResultTab = ({ } } }, - [testCaseData, updateTestCaseById, onTestCaseUpdate] + [testCaseData, updateTestCaseById, setTestCase] ); const handleCancelParameter = useCallback( @@ -225,7 +223,7 @@ const TestCaseResultTab = ({ testCase={testCaseData} visible={isParameterEdit} onCancel={handleCancelParameter} - onUpdate={onTestCaseUpdate} + onUpdate={setTestCase} /> )} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.interface.ts deleted file mode 100644 index c0105ad00e4..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.interface.ts +++ /dev/null @@ -1,19 +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 { TestCase } from '../../../../generated/tests/testCase'; - -export interface TestCaseResultTabProps { - testCaseData?: TestCase; - onTestCaseUpdate: (data: TestCase) => void; -} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx index 57510c5af00..619d5a6d4b4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.test.tsx @@ -21,54 +21,61 @@ import React from 'react'; import { TestCase } from '../../../../generated/tests/testCase'; import { checkPermission } from '../../../../utils/PermissionsUtils'; import TestCaseResultTab from './TestCaseResultTab.component'; -import { TestCaseResultTabProps } from './TestCaseResultTab.interface'; -const mockProps: TestCaseResultTabProps = { - testCaseData: { - id: '1b748634-d24b-4879-9791-289f2f90fc3c', - name: 'table_column_count_equals', +const mockTestCaseData = { + id: '1b748634-d24b-4879-9791-289f2f90fc3c', + name: 'table_column_count_equals', + fullyQualifiedName: + 'sample_data.ecommerce_db.shopify.dim_address.table_column_count_equals', + testDefinition: { + id: '48063740-ac35-4854-9ab3-b1b542c820fe', + type: 'testDefinition', + name: 'tableColumnCountToEqual', + fullyQualifiedName: 'tableColumnCountToEqual', + displayName: 'Table Column Count To Equal', + }, + entityLink: '<#E::table::sample_data.ecommerce_db.shopify.dim_address>', + entityFQN: 'sample_data.ecommerce_db.shopify.dim_address', + testSuite: { + id: 'fe44ef1a-1b83-4872-bef6-fbd1885986b8', + type: 'testSuite', + name: 'sample_data.ecommerce_db.shopify.dim_address.testSuite', fullyQualifiedName: - 'sample_data.ecommerce_db.shopify.dim_address.table_column_count_equals', - testDefinition: { - id: '48063740-ac35-4854-9ab3-b1b542c820fe', - type: 'testDefinition', - name: 'tableColumnCountToEqual', - fullyQualifiedName: 'tableColumnCountToEqual', - displayName: 'Table Column Count To Equal', + 'sample_data.ecommerce_db.shopify.dim_address.testSuite', + }, + parameterValues: [ + { + name: 'columnCount', + value: '10', }, - entityLink: '<#E::table::sample_data.ecommerce_db.shopify.dim_address>', - entityFQN: 'sample_data.ecommerce_db.shopify.dim_address', - testSuite: { - id: 'fe44ef1a-1b83-4872-bef6-fbd1885986b8', - type: 'testSuite', - name: 'sample_data.ecommerce_db.shopify.dim_address.testSuite', - fullyQualifiedName: - 'sample_data.ecommerce_db.shopify.dim_address.testSuite', - }, - parameterValues: [ + { name: 'sqlExpression', value: 'select * from dim_address' }, + ], + testCaseResult: { + timestamp: 1703570591595, + testCaseStatus: 'Success', + result: 'Found 10 columns vs. the expected 10', + testResultValue: [ { name: 'columnCount', value: '10', }, - { name: 'sqlExpression', value: 'select * from dim_address' }, ], - testCaseResult: { - timestamp: 1703570591595, - testCaseStatus: 'Success', - result: 'Found 10 columns vs. the expected 10', - testResultValue: [ - { - name: 'columnCount', - value: '10', - }, - ], - }, - updatedAt: 1703570589915, - updatedBy: 'admin', - } as TestCase, - onTestCaseUpdate: jest.fn(), -}; + }, + updatedAt: 1703570589915, + updatedBy: 'admin', +} as TestCase; +const mockFunc = jest.fn(); + +jest.mock( + '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store', + () => ({ + useTestCaseStore: jest.fn().mockImplementation(() => ({ + testCase: mockTestCaseData, + setTestCase: mockFunc, + })), + }) +); jest.mock('../../../common/EntityDescription/DescriptionV1', () => { return jest.fn().mockImplementation(() =>
DescriptionV1
); }); @@ -97,7 +104,7 @@ jest.mock('../../../../utils/PermissionsUtils', () => ({ describe('TestCaseResultTab', () => { it('Should render component', async () => { - render(); + render(); expect( await screen.findByTestId('test-case-result-tab-container') @@ -113,7 +120,7 @@ describe('TestCaseResultTab', () => { }); it("EditTestCaseModal should be rendered when 'Edit' button is clicked", async () => { - render(); + render(); const editButton = await screen.findByTestId('edit-parameter-icon'); fireEvent.click(editButton); @@ -122,7 +129,7 @@ describe('TestCaseResultTab', () => { }); it('EditTestCaseModal should be removed on cancel click', async () => { - const { container } = render(); + const { container } = render(); const editButton = await screen.findByTestId('edit-parameter-icon'); fireEvent.click(editButton); @@ -136,7 +143,7 @@ describe('TestCaseResultTab', () => { }); it('onTestCaseUpdate should be called while updating params', async () => { - render(); + render(); const editButton = await screen.findByTestId('edit-parameter-icon'); fireEvent.click(editButton); @@ -146,14 +153,12 @@ describe('TestCaseResultTab', () => { const updateButton = await screen.findByTestId('update-test'); fireEvent.click(updateButton); - expect(mockProps.onTestCaseUpdate).toHaveBeenCalledWith( - mockProps.testCaseData - ); + expect(mockFunc).toHaveBeenCalledWith(mockTestCaseData); }); it("Should not show edit icon if user doesn't have edit permission", () => { (checkPermission as jest.Mock).mockReturnValueOnce(false); - const { container } = render(); + const { container } = render(); const editButton = queryByTestId(container, 'edit-parameter-icon'); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManager.interface.ts b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManager.interface.ts index 6e9764b97f8..c1245eaca02 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManager.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManager.interface.ts @@ -15,6 +15,7 @@ import { TestCaseResolutionStatus } from '../../generated/tests/testCaseResoluti export enum IncidentManagerTabs { TEST_CASE_RESULTS = 'test-case-results', + SQL_QUERY = 'sql-query', ISSUES = 'issues', } export interface TestCaseIncidentStatusData { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.test.tsx index eaf9963153c..43b0075c566 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.test.tsx @@ -13,10 +13,12 @@ import { act, fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; +import { TestCase } from '../../../generated/tests/testCase'; import { getTestCaseByFqn } from '../../../rest/testAPI'; import { checkPermission } from '../../../utils/PermissionsUtils'; import { IncidentManagerTabs } from '../IncidentManager.interface'; import IncidentManagerDetailPage from './IncidentManagerDetailPage'; +import { UseTestCaseStoreInterface } from './useTestCase.store'; const mockTestCaseData = { id: '1b748634-d24b-4879-9791-289f2f90fc3c', @@ -67,7 +69,17 @@ const mockTestCaseData = { version: 0.1, updatedAt: 1703570589915, updatedBy: 'admin', +} as TestCase; +const mockUseTestCase: UseTestCaseStoreInterface = { + testCase: mockTestCaseData, + setTestCase: jest.fn(), + isLoading: false, + setIsLoading: jest.fn(), + reset: jest.fn(), }; +jest.mock('./useTestCase.store', () => ({ + useTestCaseStore: jest.fn().mockImplementation(() => mockUseTestCase), +})); jest.mock('../../../rest/testAPI', () => ({ getTestCaseByFqn: jest @@ -179,13 +191,17 @@ describe('IncidentManagerDetailPage', () => { }); it('should render no data placeholder message if there is no data', async () => { + mockUseTestCase.testCase = undefined; (getTestCaseByFqn as jest.Mock).mockImplementationOnce(() => Promise.reject() ); + await act(async () => { render(, { wrapper: MemoryRouter }); }); expect(await screen.findByText('ErrorPlaceHolder')).toBeInTheDocument(); + + mockUseTestCase.testCase = mockTestCaseData; }); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.tsx index 6c4748ac30f..8c4644c1413 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/IncidentManagerDetailPage.tsx @@ -22,12 +22,9 @@ import ActivityFeedProvider from '../../../components/ActivityFeed/ActivityFeedP import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton'; import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder'; import Loader from '../../../components/common/Loader/Loader'; -import TabsLabel from '../../../components/common/TabsLabel/TabsLabel.component'; import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component'; import { TitleBreadcrumbProps } from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.interface'; import IncidentManagerPageHeader from '../../../components/DataQuality/IncidentManager/IncidentManagerPageHeader/IncidentManagerPageHeader.component'; -import TestCaseIncidentTab from '../../../components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component'; -import TestCaseResultTab from '../../../components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component'; import EntityHeaderTitle from '../../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component'; import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface'; import PageLayoutV1 from '../../../components/PageLayoutV1/PageLayoutV1'; @@ -38,7 +35,7 @@ import { ResourceEntity } from '../../../context/PermissionProvider/PermissionPr import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum'; import { EntityTabs, EntityType } from '../../../enums/entity.enum'; import { Operation } from '../../../generated/entity/policies/policy'; -import { EntityReference, TestCase } from '../../../generated/tests/testCase'; +import { EntityReference } from '../../../generated/tests/testCase'; import { useFqn } from '../../../hooks/useFqn'; import { FeedCounts } from '../../../interface/feed.interface'; import { getTestCaseByFqn, updateTestCaseById } from '../../../rest/testAPI'; @@ -47,7 +44,8 @@ import { checkPermission } from '../../../utils/PermissionsUtils'; import { getIncidentManagerDetailPagePath } from '../../../utils/RouterUtils'; import { showErrorToast } from '../../../utils/ToastUtils'; import { IncidentManagerTabs } from '../IncidentManager.interface'; -import { TestCaseData } from './IncidentManagerDetailPage.interface'; +import testCaseClassBase from './TestCaseClassBase'; +import { useTestCaseStore } from './useTestCase.store'; const IncidentManagerDetailPage = () => { const { t } = useTranslation(); @@ -60,10 +58,8 @@ const IncidentManagerDetailPage = () => { const { fqn: testCaseFQN } = useFqn(); - const [testCaseData, setTestCaseData] = useState({ - data: undefined, - isLoading: true, - }); + const { isLoading, setIsLoading, setTestCase, testCase, reset } = + useTestCaseStore(); const [feedCount, setFeedCount] = useState( FEED_COUNT_INITIAL_DATA ); @@ -90,59 +86,33 @@ const IncidentManagerDetailPage = () => { }; }, [permissions]); - const onTestCaseUpdate = (data: TestCase) => { - setTestCaseData((prev) => ({ ...prev, data })); - }; + const tabDetails: TabsProps['items'] = useMemo(() => { + const tabs = testCaseClassBase.getTab(feedCount.openTaskCount); - const tabDetails: TabsProps['items'] = useMemo( - () => [ - { - label: ( - - ), - children: ( - - ), - key: IncidentManagerTabs.TEST_CASE_RESULTS, - }, - { - label: ( - - ), - key: IncidentManagerTabs.ISSUES, - children: , - }, - ], - [testCaseData, feedCount.openTaskCount] - ); + return tabs.map(({ LabelComponent, labelProps, key, Tab }) => ({ + key, + label: , + children: , + })); + }, [feedCount.openTaskCount, testCaseClassBase.showSqlQueryTab]); const fetchTestCaseData = async () => { - setTestCaseData((prev) => ({ ...prev, isLoading: true })); + setIsLoading(true); try { const response = await getTestCaseByFqn(testCaseFQN, { - fields: [ - 'testSuite', - 'testCaseResult', - 'testDefinition', - 'owner', - 'incidentId', - ], + fields: testCaseClassBase.getFields(), }); - setTestCaseData((prev) => ({ ...prev, data: response })); + testCaseClassBase.setShowSqlQueryTab( + !isUndefined(response.inspectionQuery) + ); + setTestCase(response); } catch (error) { showErrorToast( error as AxiosError, t('server.entity-fetch-error', { entity: t('label.test-case') }) ); } finally { - setTestCaseData((prev) => ({ ...prev, isLoading: false })); + setIsLoading(false); } }; @@ -160,12 +130,12 @@ const IncidentManagerDetailPage = () => { return [ ...data, { - name: testCaseData?.data?.name ?? '', + name: testCase?.name ?? '', url: '', activeTitle: true, }, ]; - }, [testCaseData]); + }, [testCase]); const handleTabChange = (activeKey: string) => { if (activeKey !== activeTab) { @@ -180,38 +150,36 @@ const IncidentManagerDetailPage = () => { const updateTestCase = async (id: string, patch: PatchOperation[]) => { try { const res = await updateTestCaseById(id, patch); - onTestCaseUpdate(res); + setTestCase(res); } catch (error) { showErrorToast(error as AxiosError); } }; const handleOwnerChange = async (owner?: EntityReference) => { - const data = testCaseData.data; - if (data) { + if (testCase) { const updatedTestCase = { - ...data, + ...testCase, owner, }; - const jsonPatch = compare(data, updatedTestCase); + const jsonPatch = compare(testCase, updatedTestCase); - if (jsonPatch.length && data.id) { - await updateTestCase(data.id, jsonPatch); + if (jsonPatch.length && testCase.id) { + await updateTestCase(testCase.id, jsonPatch); } } }; const handleDisplayNameChange = async (entityName?: EntityName) => { try { - const data = testCaseData.data; - if (data) { + if (testCase) { const updatedTestCase = { - ...data, + ...testCase, ...entityName, }; - const jsonPatch = compare(data, updatedTestCase); + const jsonPatch = compare(testCase, updatedTestCase); - if (jsonPatch.length && data.id) { - await updateTestCase(data.id, jsonPatch); + if (jsonPatch.length && testCase.id) { + await updateTestCase(testCase.id, jsonPatch); } } } catch (error) { @@ -232,11 +200,17 @@ const IncidentManagerDetailPage = () => { fetchTestCaseData(); getEntityFeedCount(); } else { - setTestCaseData((prev) => ({ ...prev, isLoading: false })); + setIsLoading(false); } + + // Cleanup function for unmount + return () => { + reset(); + testCaseClassBase.setShowSqlQueryTab(false); + }; }, [testCaseFQN, hasViewPermission]); - if (testCaseData.isLoading) { + if (isLoading) { return ; } @@ -244,7 +218,7 @@ const IncidentManagerDetailPage = () => { return ; } - if (isUndefined(testCaseData.data)) { + if (isUndefined(testCase)) { return ; } @@ -262,9 +236,9 @@ const IncidentManagerDetailPage = () => { } - name={testCaseData.data?.name ?? ''} + name={testCase?.name ?? ''} serviceName="testCase" /> @@ -276,11 +250,11 @@ const IncidentManagerDetailPage = () => { } allowSoftDelete={false} canDelete={hasDeletePermission} - displayName={testCaseData.data.displayName} + displayName={testCase.displayName} editDisplayNamePermission={editDisplayNamePermission} - entityFQN={testCaseData.data.fullyQualifiedName} - entityId={testCaseData.data.id} - entityName={testCaseData.data.name} + entityFQN={testCase.fullyQualifiedName} + entityId={testCase.id} + entityName={testCase.name} entityType={EntityType.TEST_CASE} onEditDisplayName={handleDisplayNameChange} /> @@ -290,7 +264,7 @@ const IncidentManagerDetailPage = () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/TestCaseClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/TestCaseClassBase.ts new file mode 100644 index 00000000000..a5bdcca1951 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/TestCaseClassBase.ts @@ -0,0 +1,77 @@ +/* + * 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 { ReactElement } from 'react'; +import TabsLabel from '../../../components/common/TabsLabel/TabsLabel.component'; +import { TabsLabelProps } from '../../../components/common/TabsLabel/TabsLabel.interface'; +import TestCaseIncidentTab from '../../../components/DataQuality/IncidentManager/TestCaseIncidentTab/TestCaseIncidentTab.component'; +import TestCaseResultTab from '../../../components/DataQuality/IncidentManager/TestCaseResultTab/TestCaseResultTab.component'; +import i18n from '../../../utils/i18next/LocalUtil'; +import { IncidentManagerTabs } from '../IncidentManager.interface'; + +export interface TestCaseTabType { + LabelComponent: typeof TabsLabel; + labelProps: TabsLabelProps; + Tab: () => ReactElement; + key: IncidentManagerTabs; +} + +class TestCaseClassBase { + showSqlQueryTab: boolean; + + constructor() { + this.showSqlQueryTab = false; + } + + public getTab(openTaskCount: number): TestCaseTabType[] { + return [ + { + LabelComponent: TabsLabel, + labelProps: { + id: 'test-case-result', + name: i18n.t('label.test-case-result'), + }, + Tab: TestCaseResultTab, + key: IncidentManagerTabs.TEST_CASE_RESULTS, + }, + { + LabelComponent: TabsLabel, + labelProps: { + id: 'incident', + name: i18n.t('label.incident'), + count: openTaskCount, + }, + Tab: TestCaseIncidentTab, + key: IncidentManagerTabs.ISSUES, + }, + ]; + } + + setShowSqlQueryTab(showSqlQueryTab: boolean) { + this.showSqlQueryTab = showSqlQueryTab; + } + + public getFields(): string[] { + return [ + 'testSuite', + 'testCaseResult', + 'testDefinition', + 'owner', + 'incidentId', + ]; + } +} + +const testCaseClassBase = new TestCaseClassBase(); + +export default testCaseClassBase; +export { TestCaseClassBase }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store.ts b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store.ts new file mode 100644 index 00000000000..bee6c127110 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store.ts @@ -0,0 +1,35 @@ +/* + * 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 { create } from 'zustand'; +import { TestCase } from '../../../generated/tests/testCase'; + +export interface UseTestCaseStoreInterface { + testCase: TestCase | undefined; + isLoading: boolean; + setTestCase: (testCase: TestCase) => void; + setIsLoading: (isLoading: boolean) => void; + reset: () => void; +} +export const useTestCaseStore = create()((set) => ({ + testCase: undefined, + isLoading: true, + setTestCase: (testCase: TestCase) => { + set({ testCase }); + }, + setIsLoading: (isLoading: boolean) => { + set({ isLoading }); + }, + reset: () => { + set({ testCase: undefined, isLoading: true }); + }, +}));