Display inspection query (#16766)

* Display inspection query

* added reset for global state

* fixed test failure
This commit is contained in:
Shailesh Parmar 2024-06-25 11:09:53 +05:30 committed by GitHub
parent b55890f1f9
commit 04d3720df9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 257 additions and 151 deletions

View File

@ -30,9 +30,9 @@ import {
Thread, Thread,
ThreadTaskStatus, ThreadTaskStatus,
} from '../../../../generated/entity/feed/thread'; } from '../../../../generated/entity/feed/thread';
import { EntityReference } from '../../../../generated/entity/type';
import { useElementInView } from '../../../../hooks/useElementInView'; import { useElementInView } from '../../../../hooks/useElementInView';
import { useFqn } from '../../../../hooks/useFqn'; import { useFqn } from '../../../../hooks/useFqn';
import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store';
import ActivityFeedListV1 from '../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1.component'; import ActivityFeedListV1 from '../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1.component';
import { useActivityFeedProvider } from '../../../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; import { useActivityFeedProvider } from '../../../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
import { TaskFilter } from '../../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface'; 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 { TaskTab } from '../../../Entity/Task/TaskTab/TaskTab.component';
import './test-case-incident-tab.style.less'; import './test-case-incident-tab.style.less';
const TestCaseIncidentTab = ({ owner }: { owner?: EntityReference }) => { const TestCaseIncidentTab = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { fqn: decodedFqn } = useFqn(); const { fqn: decodedFqn } = useFqn();
const { testCase } = useTestCaseStore();
const owner = useMemo(() => testCase?.owner, [testCase]);
const { const {
selectedThread, selectedThread,

View File

@ -25,6 +25,22 @@ const mockUseActivityFeedProviderValue = {
setActiveThread: jest.fn(), 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', () => { jest.mock('../../../Entity/Task/TaskTab/TaskTab.component', () => {
return { return {
TaskTab: jest.fn().mockImplementation(({ onAfterClose }) => ( TaskTab: jest.fn().mockImplementation(({ onAfterClose }) => (

View File

@ -30,6 +30,7 @@ import { EntityType } from '../../../../enums/entity.enum';
import { Operation } from '../../../../generated/entity/policies/policy'; import { Operation } from '../../../../generated/entity/policies/policy';
import { TestCaseParameterValue } from '../../../../generated/tests/testCase'; import { TestCaseParameterValue } from '../../../../generated/tests/testCase';
import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store';
import { updateTestCaseById } from '../../../../rest/testAPI'; import { updateTestCaseById } from '../../../../rest/testAPI';
import { checkPermission } from '../../../../utils/PermissionsUtils'; import { checkPermission } from '../../../../utils/PermissionsUtils';
import { showErrorToast, showSuccessToast } from '../../../../utils/ToastUtils'; import { showErrorToast, showSuccessToast } from '../../../../utils/ToastUtils';
@ -39,14 +40,11 @@ import SchemaEditor from '../../../Database/SchemaEditor/SchemaEditor';
import EditTestCaseModal from '../../AddDataQualityTest/EditTestCaseModal'; import EditTestCaseModal from '../../AddDataQualityTest/EditTestCaseModal';
import '../incident-manager.style.less'; import '../incident-manager.style.less';
import './test-case-result-tab.style.less'; import './test-case-result-tab.style.less';
import { TestCaseResultTabProps } from './TestCaseResultTab.interface';
import testCaseResultTabClassBase from './TestCaseResultTabClassBase'; import testCaseResultTabClassBase from './TestCaseResultTabClassBase';
const TestCaseResultTab = ({ const TestCaseResultTab = () => {
testCaseData,
onTestCaseUpdate,
}: TestCaseResultTabProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { testCase: testCaseData, setTestCase } = useTestCaseStore();
const additionalComponent = const additionalComponent =
testCaseResultTabClassBase.getAdditionalComponents(); testCaseResultTabClassBase.getAdditionalComponents();
const [isDescriptionEdit, setIsDescriptionEdit] = useState<boolean>(false); const [isDescriptionEdit, setIsDescriptionEdit] = useState<boolean>(false);
@ -95,7 +93,7 @@ const TestCaseResultTab = ({
testCaseData.id ?? '', testCaseData.id ?? '',
jsonPatch jsonPatch
); );
onTestCaseUpdate(res); setTestCase(res);
showSuccessToast( showSuccessToast(
t('server.update-entity-success', { t('server.update-entity-success', {
entity: t('label.test-case'), entity: t('label.test-case'),
@ -109,7 +107,7 @@ const TestCaseResultTab = ({
} }
} }
}, },
[testCaseData, updateTestCaseById, onTestCaseUpdate] [testCaseData, updateTestCaseById, setTestCase]
); );
const handleCancelParameter = useCallback( const handleCancelParameter = useCallback(
@ -225,7 +223,7 @@ const TestCaseResultTab = ({
testCase={testCaseData} testCase={testCaseData}
visible={isParameterEdit} visible={isParameterEdit}
onCancel={handleCancelParameter} onCancel={handleCancelParameter}
onUpdate={onTestCaseUpdate} onUpdate={setTestCase}
/> />
)} )}
</Row> </Row>

View File

@ -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;
}

View File

@ -21,54 +21,61 @@ import React from 'react';
import { TestCase } from '../../../../generated/tests/testCase'; import { TestCase } from '../../../../generated/tests/testCase';
import { checkPermission } from '../../../../utils/PermissionsUtils'; import { checkPermission } from '../../../../utils/PermissionsUtils';
import TestCaseResultTab from './TestCaseResultTab.component'; import TestCaseResultTab from './TestCaseResultTab.component';
import { TestCaseResultTabProps } from './TestCaseResultTab.interface';
const mockProps: TestCaseResultTabProps = { const mockTestCaseData = {
testCaseData: { id: '1b748634-d24b-4879-9791-289f2f90fc3c',
id: '1b748634-d24b-4879-9791-289f2f90fc3c', name: 'table_column_count_equals',
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: fullyQualifiedName:
'sample_data.ecommerce_db.shopify.dim_address.table_column_count_equals', 'sample_data.ecommerce_db.shopify.dim_address.testSuite',
testDefinition: { },
id: '48063740-ac35-4854-9ab3-b1b542c820fe', parameterValues: [
type: 'testDefinition', {
name: 'tableColumnCountToEqual', name: 'columnCount',
fullyQualifiedName: 'tableColumnCountToEqual', value: '10',
displayName: 'Table Column Count To Equal',
}, },
entityLink: '<#E::table::sample_data.ecommerce_db.shopify.dim_address>', { name: 'sqlExpression', value: 'select * from dim_address' },
entityFQN: 'sample_data.ecommerce_db.shopify.dim_address', ],
testSuite: { testCaseResult: {
id: 'fe44ef1a-1b83-4872-bef6-fbd1885986b8', timestamp: 1703570591595,
type: 'testSuite', testCaseStatus: 'Success',
name: 'sample_data.ecommerce_db.shopify.dim_address.testSuite', result: 'Found 10 columns vs. the expected 10',
fullyQualifiedName: testResultValue: [
'sample_data.ecommerce_db.shopify.dim_address.testSuite',
},
parameterValues: [
{ {
name: 'columnCount', name: 'columnCount',
value: '10', value: '10',
}, },
{ name: 'sqlExpression', value: 'select * from dim_address' },
], ],
testCaseResult: { },
timestamp: 1703570591595, updatedAt: 1703570589915,
testCaseStatus: 'Success', updatedBy: 'admin',
result: 'Found 10 columns vs. the expected 10', } as TestCase;
testResultValue: [
{
name: 'columnCount',
value: '10',
},
],
},
updatedAt: 1703570589915,
updatedBy: 'admin',
} as TestCase,
onTestCaseUpdate: jest.fn(),
};
const mockFunc = jest.fn();
jest.mock(
'../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store',
() => ({
useTestCaseStore: jest.fn().mockImplementation(() => ({
testCase: mockTestCaseData,
setTestCase: mockFunc,
})),
})
);
jest.mock('../../../common/EntityDescription/DescriptionV1', () => { jest.mock('../../../common/EntityDescription/DescriptionV1', () => {
return jest.fn().mockImplementation(() => <div>DescriptionV1</div>); return jest.fn().mockImplementation(() => <div>DescriptionV1</div>);
}); });
@ -97,7 +104,7 @@ jest.mock('../../../../utils/PermissionsUtils', () => ({
describe('TestCaseResultTab', () => { describe('TestCaseResultTab', () => {
it('Should render component', async () => { it('Should render component', async () => {
render(<TestCaseResultTab {...mockProps} />); render(<TestCaseResultTab />);
expect( expect(
await screen.findByTestId('test-case-result-tab-container') 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 () => { it("EditTestCaseModal should be rendered when 'Edit' button is clicked", async () => {
render(<TestCaseResultTab {...mockProps} />); render(<TestCaseResultTab />);
const editButton = await screen.findByTestId('edit-parameter-icon'); const editButton = await screen.findByTestId('edit-parameter-icon');
fireEvent.click(editButton); fireEvent.click(editButton);
@ -122,7 +129,7 @@ describe('TestCaseResultTab', () => {
}); });
it('EditTestCaseModal should be removed on cancel click', async () => { it('EditTestCaseModal should be removed on cancel click', async () => {
const { container } = render(<TestCaseResultTab {...mockProps} />); const { container } = render(<TestCaseResultTab />);
const editButton = await screen.findByTestId('edit-parameter-icon'); const editButton = await screen.findByTestId('edit-parameter-icon');
fireEvent.click(editButton); fireEvent.click(editButton);
@ -136,7 +143,7 @@ describe('TestCaseResultTab', () => {
}); });
it('onTestCaseUpdate should be called while updating params', async () => { it('onTestCaseUpdate should be called while updating params', async () => {
render(<TestCaseResultTab {...mockProps} />); render(<TestCaseResultTab />);
const editButton = await screen.findByTestId('edit-parameter-icon'); const editButton = await screen.findByTestId('edit-parameter-icon');
fireEvent.click(editButton); fireEvent.click(editButton);
@ -146,14 +153,12 @@ describe('TestCaseResultTab', () => {
const updateButton = await screen.findByTestId('update-test'); const updateButton = await screen.findByTestId('update-test');
fireEvent.click(updateButton); fireEvent.click(updateButton);
expect(mockProps.onTestCaseUpdate).toHaveBeenCalledWith( expect(mockFunc).toHaveBeenCalledWith(mockTestCaseData);
mockProps.testCaseData
);
}); });
it("Should not show edit icon if user doesn't have edit permission", () => { it("Should not show edit icon if user doesn't have edit permission", () => {
(checkPermission as jest.Mock).mockReturnValueOnce(false); (checkPermission as jest.Mock).mockReturnValueOnce(false);
const { container } = render(<TestCaseResultTab {...mockProps} />); const { container } = render(<TestCaseResultTab />);
const editButton = queryByTestId(container, 'edit-parameter-icon'); const editButton = queryByTestId(container, 'edit-parameter-icon');

View File

@ -15,6 +15,7 @@ import { TestCaseResolutionStatus } from '../../generated/tests/testCaseResoluti
export enum IncidentManagerTabs { export enum IncidentManagerTabs {
TEST_CASE_RESULTS = 'test-case-results', TEST_CASE_RESULTS = 'test-case-results',
SQL_QUERY = 'sql-query',
ISSUES = 'issues', ISSUES = 'issues',
} }
export interface TestCaseIncidentStatusData { export interface TestCaseIncidentStatusData {

View File

@ -13,10 +13,12 @@
import { act, fireEvent, render, screen } from '@testing-library/react'; import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { TestCase } from '../../../generated/tests/testCase';
import { getTestCaseByFqn } from '../../../rest/testAPI'; import { getTestCaseByFqn } from '../../../rest/testAPI';
import { checkPermission } from '../../../utils/PermissionsUtils'; import { checkPermission } from '../../../utils/PermissionsUtils';
import { IncidentManagerTabs } from '../IncidentManager.interface'; import { IncidentManagerTabs } from '../IncidentManager.interface';
import IncidentManagerDetailPage from './IncidentManagerDetailPage'; import IncidentManagerDetailPage from './IncidentManagerDetailPage';
import { UseTestCaseStoreInterface } from './useTestCase.store';
const mockTestCaseData = { const mockTestCaseData = {
id: '1b748634-d24b-4879-9791-289f2f90fc3c', id: '1b748634-d24b-4879-9791-289f2f90fc3c',
@ -67,7 +69,17 @@ const mockTestCaseData = {
version: 0.1, version: 0.1,
updatedAt: 1703570589915, updatedAt: 1703570589915,
updatedBy: 'admin', 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', () => ({ jest.mock('../../../rest/testAPI', () => ({
getTestCaseByFqn: jest getTestCaseByFqn: jest
@ -179,13 +191,17 @@ describe('IncidentManagerDetailPage', () => {
}); });
it('should render no data placeholder message if there is no data', async () => { it('should render no data placeholder message if there is no data', async () => {
mockUseTestCase.testCase = undefined;
(getTestCaseByFqn as jest.Mock).mockImplementationOnce(() => (getTestCaseByFqn as jest.Mock).mockImplementationOnce(() =>
Promise.reject() Promise.reject()
); );
await act(async () => { await act(async () => {
render(<IncidentManagerDetailPage />, { wrapper: MemoryRouter }); render(<IncidentManagerDetailPage />, { wrapper: MemoryRouter });
}); });
expect(await screen.findByText('ErrorPlaceHolder')).toBeInTheDocument(); expect(await screen.findByText('ErrorPlaceHolder')).toBeInTheDocument();
mockUseTestCase.testCase = mockTestCaseData;
}); });
}); });

View File

@ -22,12 +22,9 @@ import ActivityFeedProvider from '../../../components/ActivityFeed/ActivityFeedP
import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton'; import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton';
import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder'; import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
import Loader from '../../../components/common/Loader/Loader'; import Loader from '../../../components/common/Loader/Loader';
import TabsLabel from '../../../components/common/TabsLabel/TabsLabel.component';
import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component'; import TitleBreadcrumb from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component';
import { TitleBreadcrumbProps } from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.interface'; import { TitleBreadcrumbProps } from '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.interface';
import IncidentManagerPageHeader from '../../../components/DataQuality/IncidentManager/IncidentManagerPageHeader/IncidentManagerPageHeader.component'; 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 EntityHeaderTitle from '../../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component';
import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface'; import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface';
import PageLayoutV1 from '../../../components/PageLayoutV1/PageLayoutV1'; 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 { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
import { EntityTabs, EntityType } from '../../../enums/entity.enum'; import { EntityTabs, EntityType } from '../../../enums/entity.enum';
import { Operation } from '../../../generated/entity/policies/policy'; 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 { useFqn } from '../../../hooks/useFqn';
import { FeedCounts } from '../../../interface/feed.interface'; import { FeedCounts } from '../../../interface/feed.interface';
import { getTestCaseByFqn, updateTestCaseById } from '../../../rest/testAPI'; import { getTestCaseByFqn, updateTestCaseById } from '../../../rest/testAPI';
@ -47,7 +44,8 @@ import { checkPermission } from '../../../utils/PermissionsUtils';
import { getIncidentManagerDetailPagePath } from '../../../utils/RouterUtils'; import { getIncidentManagerDetailPagePath } from '../../../utils/RouterUtils';
import { showErrorToast } from '../../../utils/ToastUtils'; import { showErrorToast } from '../../../utils/ToastUtils';
import { IncidentManagerTabs } from '../IncidentManager.interface'; import { IncidentManagerTabs } from '../IncidentManager.interface';
import { TestCaseData } from './IncidentManagerDetailPage.interface'; import testCaseClassBase from './TestCaseClassBase';
import { useTestCaseStore } from './useTestCase.store';
const IncidentManagerDetailPage = () => { const IncidentManagerDetailPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -60,10 +58,8 @@ const IncidentManagerDetailPage = () => {
const { fqn: testCaseFQN } = useFqn(); const { fqn: testCaseFQN } = useFqn();
const [testCaseData, setTestCaseData] = useState<TestCaseData>({ const { isLoading, setIsLoading, setTestCase, testCase, reset } =
data: undefined, useTestCaseStore();
isLoading: true,
});
const [feedCount, setFeedCount] = useState<FeedCounts>( const [feedCount, setFeedCount] = useState<FeedCounts>(
FEED_COUNT_INITIAL_DATA FEED_COUNT_INITIAL_DATA
); );
@ -90,59 +86,33 @@ const IncidentManagerDetailPage = () => {
}; };
}, [permissions]); }, [permissions]);
const onTestCaseUpdate = (data: TestCase) => { const tabDetails: TabsProps['items'] = useMemo(() => {
setTestCaseData((prev) => ({ ...prev, data })); const tabs = testCaseClassBase.getTab(feedCount.openTaskCount);
};
const tabDetails: TabsProps['items'] = useMemo( return tabs.map(({ LabelComponent, labelProps, key, Tab }) => ({
() => [ key,
{ label: <LabelComponent {...labelProps} />,
label: ( children: <Tab />,
<TabsLabel id="test-case-result" name={t('label.test-case-result')} /> }));
), }, [feedCount.openTaskCount, testCaseClassBase.showSqlQueryTab]);
children: (
<TestCaseResultTab
testCaseData={testCaseData.data}
onTestCaseUpdate={onTestCaseUpdate}
/>
),
key: IncidentManagerTabs.TEST_CASE_RESULTS,
},
{
label: (
<TabsLabel
count={feedCount.openTaskCount}
id="incident"
name={t('label.incident')}
/>
),
key: IncidentManagerTabs.ISSUES,
children: <TestCaseIncidentTab owner={testCaseData.data?.owner} />,
},
],
[testCaseData, feedCount.openTaskCount]
);
const fetchTestCaseData = async () => { const fetchTestCaseData = async () => {
setTestCaseData((prev) => ({ ...prev, isLoading: true })); setIsLoading(true);
try { try {
const response = await getTestCaseByFqn(testCaseFQN, { const response = await getTestCaseByFqn(testCaseFQN, {
fields: [ fields: testCaseClassBase.getFields(),
'testSuite',
'testCaseResult',
'testDefinition',
'owner',
'incidentId',
],
}); });
setTestCaseData((prev) => ({ ...prev, data: response })); testCaseClassBase.setShowSqlQueryTab(
!isUndefined(response.inspectionQuery)
);
setTestCase(response);
} catch (error) { } catch (error) {
showErrorToast( showErrorToast(
error as AxiosError, error as AxiosError,
t('server.entity-fetch-error', { entity: t('label.test-case') }) t('server.entity-fetch-error', { entity: t('label.test-case') })
); );
} finally { } finally {
setTestCaseData((prev) => ({ ...prev, isLoading: false })); setIsLoading(false);
} }
}; };
@ -160,12 +130,12 @@ const IncidentManagerDetailPage = () => {
return [ return [
...data, ...data,
{ {
name: testCaseData?.data?.name ?? '', name: testCase?.name ?? '',
url: '', url: '',
activeTitle: true, activeTitle: true,
}, },
]; ];
}, [testCaseData]); }, [testCase]);
const handleTabChange = (activeKey: string) => { const handleTabChange = (activeKey: string) => {
if (activeKey !== activeTab) { if (activeKey !== activeTab) {
@ -180,38 +150,36 @@ const IncidentManagerDetailPage = () => {
const updateTestCase = async (id: string, patch: PatchOperation[]) => { const updateTestCase = async (id: string, patch: PatchOperation[]) => {
try { try {
const res = await updateTestCaseById(id, patch); const res = await updateTestCaseById(id, patch);
onTestCaseUpdate(res); setTestCase(res);
} catch (error) { } catch (error) {
showErrorToast(error as AxiosError); showErrorToast(error as AxiosError);
} }
}; };
const handleOwnerChange = async (owner?: EntityReference) => { const handleOwnerChange = async (owner?: EntityReference) => {
const data = testCaseData.data; if (testCase) {
if (data) {
const updatedTestCase = { const updatedTestCase = {
...data, ...testCase,
owner, owner,
}; };
const jsonPatch = compare(data, updatedTestCase); const jsonPatch = compare(testCase, updatedTestCase);
if (jsonPatch.length && data.id) { if (jsonPatch.length && testCase.id) {
await updateTestCase(data.id, jsonPatch); await updateTestCase(testCase.id, jsonPatch);
} }
} }
}; };
const handleDisplayNameChange = async (entityName?: EntityName) => { const handleDisplayNameChange = async (entityName?: EntityName) => {
try { try {
const data = testCaseData.data; if (testCase) {
if (data) {
const updatedTestCase = { const updatedTestCase = {
...data, ...testCase,
...entityName, ...entityName,
}; };
const jsonPatch = compare(data, updatedTestCase); const jsonPatch = compare(testCase, updatedTestCase);
if (jsonPatch.length && data.id) { if (jsonPatch.length && testCase.id) {
await updateTestCase(data.id, jsonPatch); await updateTestCase(testCase.id, jsonPatch);
} }
} }
} catch (error) { } catch (error) {
@ -232,11 +200,17 @@ const IncidentManagerDetailPage = () => {
fetchTestCaseData(); fetchTestCaseData();
getEntityFeedCount(); getEntityFeedCount();
} else { } else {
setTestCaseData((prev) => ({ ...prev, isLoading: false })); setIsLoading(false);
} }
// Cleanup function for unmount
return () => {
reset();
testCaseClassBase.setShowSqlQueryTab(false);
};
}, [testCaseFQN, hasViewPermission]); }, [testCaseFQN, hasViewPermission]);
if (testCaseData.isLoading) { if (isLoading) {
return <Loader />; return <Loader />;
} }
@ -244,7 +218,7 @@ const IncidentManagerDetailPage = () => {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />; return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
} }
if (isUndefined(testCaseData.data)) { if (isUndefined(testCase)) {
return <ErrorPlaceHolder />; return <ErrorPlaceHolder />;
} }
@ -262,9 +236,9 @@ const IncidentManagerDetailPage = () => {
<Col span={23}> <Col span={23}>
<EntityHeaderTitle <EntityHeaderTitle
className="w-max-full-45" className="w-max-full-45"
displayName={testCaseData.data?.displayName} displayName={testCase?.displayName}
icon={<TestCaseIcon className="h-9" />} icon={<TestCaseIcon className="h-9" />}
name={testCaseData.data?.name ?? ''} name={testCase?.name ?? ''}
serviceName="testCase" serviceName="testCase"
/> />
</Col> </Col>
@ -276,11 +250,11 @@ const IncidentManagerDetailPage = () => {
} }
allowSoftDelete={false} allowSoftDelete={false}
canDelete={hasDeletePermission} canDelete={hasDeletePermission}
displayName={testCaseData.data.displayName} displayName={testCase.displayName}
editDisplayNamePermission={editDisplayNamePermission} editDisplayNamePermission={editDisplayNamePermission}
entityFQN={testCaseData.data.fullyQualifiedName} entityFQN={testCase.fullyQualifiedName}
entityId={testCaseData.data.id} entityId={testCase.id}
entityName={testCaseData.data.name} entityName={testCase.name}
entityType={EntityType.TEST_CASE} entityType={EntityType.TEST_CASE}
onEditDisplayName={handleDisplayNameChange} onEditDisplayName={handleDisplayNameChange}
/> />
@ -290,7 +264,7 @@ const IncidentManagerDetailPage = () => {
<Col className="p-x-lg"> <Col className="p-x-lg">
<IncidentManagerPageHeader <IncidentManagerPageHeader
fetchTaskCount={getEntityFeedCount} fetchTaskCount={getEntityFeedCount}
testCaseData={testCaseData.data} testCaseData={testCase}
onOwnerUpdate={handleOwnerChange} onOwnerUpdate={handleOwnerChange}
/> />
</Col> </Col>

View File

@ -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 };

View File

@ -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<UseTestCaseStoreInterface>()((set) => ({
testCase: undefined,
isLoading: true,
setTestCase: (testCase: TestCase) => {
set({ testCase });
},
setIsLoading: (isLoading: boolean) => {
set({ isLoading });
},
reset: () => {
set({ testCase: undefined, isLoading: true });
},
}));