mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-27 18:36:08 +00:00
Display inspection query (#16766)
* Display inspection query * added reset for global state * fixed test failure
This commit is contained in:
parent
b55890f1f9
commit
04d3720df9
@ -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,
|
||||||
|
@ -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 }) => (
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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');
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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>
|
||||||
|
@ -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 };
|
@ -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 });
|
||||||
|
},
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user