GEN-1296: sort test cases by latest run (#18097)

* GEN-1296: sort test cases by latest run

* minor fix

* added sort support for name field

* fixed unit test

* fixed failing playwright test

* fixed failing playwright test
This commit is contained in:
Shailesh Parmar 2024-10-07 12:34:09 +05:30 committed by GitHub
parent 49fceb4674
commit a74811481f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 209 additions and 39 deletions

View File

@ -79,4 +79,7 @@ Thumbs.db
src/generated src/generated
# Snapshots # Snapshots
*.snap *.snap
# env
".env"

View File

@ -231,7 +231,7 @@ test.describe('Incident Manager', PLAYWRIGHT_INGESTION_TAG_OBJ, () => {
await test.step('Resolve task from incident list page', async () => { await test.step('Resolve task from incident list page', async () => {
await visitProfilerTab(page, table1); await visitProfilerTab(page, table1);
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page await page
.getByTestId('profiler-tab-left-panel') .getByTestId('profiler-tab-left-panel')
@ -277,7 +277,7 @@ test.describe('Incident Manager', PLAYWRIGHT_INGESTION_TAG_OBJ, () => {
await test.step('Task should be closed', async () => { await test.step('Task should be closed', async () => {
await visitProfilerTab(page, table1); await visitProfilerTab(page, table1);
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page await page
.getByTestId('profiler-tab-left-panel') .getByTestId('profiler-tab-left-panel')
@ -373,7 +373,7 @@ test.describe('Incident Manager', PLAYWRIGHT_INGESTION_TAG_OBJ, () => {
await test.step("Verify incident's status on DQ page", async () => { await test.step("Verify incident's status on DQ page", async () => {
await visitProfilerTab(page, table1); await visitProfilerTab(page, table1);
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page await page
.getByTestId('profiler-tab-left-panel') .getByTestId('profiler-tab-left-panel')

View File

@ -130,7 +130,7 @@ test('Table test case', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => {
).toBeVisible(); ).toBeVisible();
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page.click(`[data-testid="view-service-button"]`); await page.click(`[data-testid="view-service-button"]`);
await testCaseResponse; await testCaseResponse;
@ -210,7 +210,7 @@ test('Column test case', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => {
await page.waitForSelector('[data-testid="view-service-button"]'); await page.waitForSelector('[data-testid="view-service-button"]');
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page.click(`[data-testid="view-service-button"]`); await page.click(`[data-testid="view-service-button"]`);
await testCaseResponse; await testCaseResponse;

View File

@ -99,7 +99,7 @@ test('Table difference test case', async ({ page }) => {
await page.getByTestId('submit-test').click(); await page.getByTestId('submit-test').click();
await createTestCaseResponse; await createTestCaseResponse;
const tableTestResponse = page.waitForResponse( const tableTestResponse = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?fields=*` `/api/v1/dataQuality/testCases/search/list?*fields=*`
); );
await page.getByTestId('view-service-button').click(); await page.getByTestId('view-service-button').click();
await tableTestResponse; await tableTestResponse;
@ -196,7 +196,7 @@ test('Custom SQL Query', async ({ page }) => {
await page.getByTestId('submit-test').click(); await page.getByTestId('submit-test').click();
await createTestCaseResponse; await createTestCaseResponse;
const tableTestResponse = page.waitForResponse( const tableTestResponse = page.waitForResponse(
`/api/v1/dataQuality/testCases/search/list?fields=*` `/api/v1/dataQuality/testCases/search/list?*fields=*`
); );
await page.getByTestId('view-service-button').click(); await page.getByTestId('view-service-button').click();
await tableTestResponse; await tableTestResponse;
@ -300,7 +300,7 @@ test('Column Values To Be Not Null', async ({ page }) => {
await page.waitForSelector('[data-testid="success-line"]'); await page.waitForSelector('[data-testid="success-line"]');
await page.waitForSelector('[data-testid="view-service-button"]'); await page.waitForSelector('[data-testid="view-service-button"]');
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page.click(`[data-testid="view-service-button"]`); await page.click(`[data-testid="view-service-button"]`);
await testCaseResponse; await testCaseResponse;

View File

@ -32,7 +32,7 @@ export const visitDataQualityTab = async (page: Page, table: TableClass) => {
await table.visitEntityPage(page); await table.visitEntityPage(page);
await page.getByTestId('profiler').click(); await page.getByTestId('profiler').click();
const testCaseResponse = page.waitForResponse( const testCaseResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?fields=*' '/api/v1/dataQuality/testCases/search/list?*fields=*'
); );
await page await page
.getByTestId('profiler-tab-left-panel') .getByTestId('profiler-tab-left-panel')

View File

@ -53,13 +53,14 @@ import {
TIER_CATEGORY, TIER_CATEGORY,
} from '../../../constants/constants'; } from '../../../constants/constants';
import { import {
DEFAULT_SORT_ORDER,
TEST_CASE_FILTERS, TEST_CASE_FILTERS,
TEST_CASE_PLATFORM_OPTION, TEST_CASE_PLATFORM_OPTION,
TEST_CASE_STATUS_OPTION, TEST_CASE_STATUS_OPTION,
TEST_CASE_TYPE_OPTION, TEST_CASE_TYPE_OPTION,
} from '../../../constants/profiler.constant'; } from '../../../constants/profiler.constant';
import { usePermissionProvider } from '../../../context/PermissionProvider/PermissionProvider'; import { usePermissionProvider } from '../../../context/PermissionProvider/PermissionProvider';
import { ERROR_PLACEHOLDER_TYPE, SORT_ORDER } from '../../../enums/common.enum'; import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
import { TabSpecificField } from '../../../enums/entity.enum'; import { TabSpecificField } from '../../../enums/entity.enum';
import { SearchIndex } from '../../../enums/search.enum'; import { SearchIndex } from '../../../enums/search.enum';
import { TestCase } from '../../../generated/tests/testCase'; import { TestCase } from '../../../generated/tests/testCase';
@ -68,7 +69,10 @@ import useCustomLocation from '../../../hooks/useCustomLocation/useCustomLocatio
import { DataQualityPageTabs } from '../../../pages/DataQuality/DataQualityPage.interface'; import { DataQualityPageTabs } from '../../../pages/DataQuality/DataQualityPage.interface';
import { searchQuery } from '../../../rest/searchAPI'; import { searchQuery } from '../../../rest/searchAPI';
import { getTags } from '../../../rest/tagAPI'; import { getTags } from '../../../rest/tagAPI';
import { getListTestCaseBySearch } from '../../../rest/testAPI'; import {
getListTestCaseBySearch,
ListTestCaseParamsBySearch,
} from '../../../rest/testAPI';
import { getTestCaseFiltersValue } from '../../../utils/DataQuality/DataQualityUtils'; import { getTestCaseFiltersValue } from '../../../utils/DataQuality/DataQualityUtils';
import { getEntityName } from '../../../utils/EntityUtils'; import { getEntityName } from '../../../utils/EntityUtils';
import { getDataQualityPagePath } from '../../../utils/RouterUtils'; import { getDataQualityPagePath } from '../../../utils/RouterUtils';
@ -94,6 +98,8 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
const [tagOptions, setTagOptions] = useState<DefaultOptionType[]>([]); const [tagOptions, setTagOptions] = useState<DefaultOptionType[]>([]);
const [tierOptions, setTierOptions] = useState<DefaultOptionType[]>([]); const [tierOptions, setTierOptions] = useState<DefaultOptionType[]>([]);
const [serviceOptions, setServiceOptions] = useState<DefaultOptionType[]>([]); const [serviceOptions, setServiceOptions] = useState<DefaultOptionType[]>([]);
const [sortOptions, setSortOptions] =
useState<ListTestCaseParamsBySearch>(DEFAULT_SORT_ORDER);
const params = useMemo(() => { const params = useMemo(() => {
const search = location.search; const search = location.search;
@ -146,7 +152,8 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
const fetchTestCases = async ( const fetchTestCases = async (
currentPage = INITIAL_PAGING_VALUE, currentPage = INITIAL_PAGING_VALUE,
filters?: string[] filters?: string[],
apiParams?: ListTestCaseParamsBySearch
) => { ) => {
const updatedParams = getTestCaseFiltersValue( const updatedParams = getTestCaseFiltersValue(
params, params,
@ -157,6 +164,8 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
try { try {
const { data, paging } = await getListTestCaseBySearch({ const { data, paging } = await getListTestCaseBySearch({
...updatedParams, ...updatedParams,
...sortOptions,
...apiParams,
testCaseStatus: isEmpty(params?.testCaseStatus) testCaseStatus: isEmpty(params?.testCaseStatus)
? undefined ? undefined
: params?.testCaseStatus, : params?.testCaseStatus,
@ -169,8 +178,6 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
], ],
q: searchValue ? `*${searchValue}*` : undefined, q: searchValue ? `*${searchValue}*` : undefined,
offset: (currentPage - 1) * pageSize, offset: (currentPage - 1) * pageSize,
sortType: SORT_ORDER.DESC,
sortField: 'testCaseResult.timestamp',
}); });
setTestCase(data); setTestCase(data);
handlePagingChange(paging); handlePagingChange(paging);
@ -182,6 +189,16 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
} }
}; };
const sortTestCase = async (apiParams?: TestCaseSearchParams) => {
const updatedValue = uniq([...selectedFilter, ...Object.keys(params)]);
await fetchTestCases(
INITIAL_PAGING_VALUE,
updatedValue,
apiParams ?? DEFAULT_SORT_ORDER
);
setSortOptions(apiParams ?? DEFAULT_SORT_ORDER);
};
const handleStatusSubmit = (testCase: TestCase) => { const handleStatusSubmit = (testCase: TestCase) => {
setTestCase((prev) => { setTestCase((prev) => {
const data = prev.map((test) => { const data = prev.map((test) => {
@ -620,6 +637,7 @@ export const TestCases = ({ summaryPanel }: { summaryPanel: ReactNode }) => {
url: getDataQualityPagePath(DataQualityPageTabs.TEST_CASES), url: getDataQualityPagePath(DataQualityPageTabs.TEST_CASES),
}, },
]} ]}
fetchTestCases={sortTestCase}
isLoading={isLoading} isLoading={isLoading}
pagingData={pagingData} pagingData={pagingData}
showPagination={showPagination} showPagination={showPagination}

View File

@ -27,6 +27,7 @@ import DataQualityTab from './DataQualityTab';
const mockProps: DataQualityTabProps = { const mockProps: DataQualityTabProps = {
testCases: MOCK_TEST_CASE, testCases: MOCK_TEST_CASE,
onTestUpdate: jest.fn(), onTestUpdate: jest.fn(),
fetchTestCases: jest.fn(),
}; };
const mockPermissionsData = { const mockPermissionsData = {
permissions: { permissions: {
@ -114,6 +115,76 @@ describe('DataQualityTab test', () => {
expect(await findByText(header, 'label.action-plural')).toBeInTheDocument(); expect(await findByText(header, 'label.action-plural')).toBeInTheDocument();
}); });
it('Should send API request with sort params on click of last-run', async () => {
await act(async () => {
render(<DataQualityTab {...mockProps} />);
});
const tableRows = await screen.findAllByRole('row');
const header = tableRows[0];
const lastRunHeader = await findByText(header, 'label.last-run');
expect(lastRunHeader).toBeInTheDocument();
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith({
sortField: 'testCaseResult.timestamp',
sortType: 'asc',
});
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith({
sortField: 'testCaseResult.timestamp',
sortType: 'desc',
});
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith(undefined);
});
it('Should send API request with sort params on click of name', async () => {
await act(async () => {
render(<DataQualityTab {...mockProps} />);
});
const tableRows = await screen.findAllByRole('row');
const header = tableRows[0];
const lastRunHeader = await findByText(header, 'label.name');
expect(lastRunHeader).toBeInTheDocument();
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith({
sortField: 'name.keyword',
sortType: 'asc',
});
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith({
sortField: 'name.keyword',
sortType: 'desc',
});
await act(async () => {
fireEvent.click(lastRunHeader);
});
expect(mockProps.fetchTestCases).toHaveBeenCalledWith(undefined);
});
it('Table data should be render as per data props', async () => { it('Table data should be render as per data props', async () => {
const firstRowData = MOCK_TEST_CASE[0]; const firstRowData = MOCK_TEST_CASE[0];
await act(async () => { await act(async () => {

View File

@ -12,13 +12,14 @@
*/ */
import { Button, Col, Row, Skeleton, Space, Tooltip, Typography } from 'antd'; import { Button, Col, Row, Skeleton, Space, Tooltip, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table'; import { ColumnsType, TablePaginationConfig } from 'antd/lib/table';
import { FilterValue, SorterResult } from 'antd/lib/table/interface';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import classNames from 'classnames'; import classNames from 'classnames';
import { isUndefined, sortBy } from 'lodash'; import { isArray, isUndefined, sortBy } from 'lodash';
import { PagingResponse } from 'Models'; import { PagingResponse } from 'Models';
import QueryString from 'qs'; import QueryString from 'qs';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { ReactComponent as IconEdit } from '../../../../assets/svg/edit-new.svg'; import { ReactComponent as IconEdit } from '../../../../assets/svg/edit-new.svg';
@ -28,10 +29,14 @@ import { DATA_QUALITY_PROFILER_DOCS } from '../../../../constants/docs.constants
import { NO_PERMISSION_FOR_ACTION } from '../../../../constants/HelperTextUtil'; import { NO_PERMISSION_FOR_ACTION } from '../../../../constants/HelperTextUtil';
import { usePermissionProvider } from '../../../../context/PermissionProvider/PermissionProvider'; import { usePermissionProvider } from '../../../../context/PermissionProvider/PermissionProvider';
import { ResourceEntity } from '../../../../context/PermissionProvider/PermissionProvider.interface'; import { ResourceEntity } from '../../../../context/PermissionProvider/PermissionProvider.interface';
import { SORT_ORDER } from '../../../../enums/common.enum';
import { EntityTabs, EntityType } from '../../../../enums/entity.enum'; import { EntityTabs, EntityType } from '../../../../enums/entity.enum';
import { TestCaseStatus } from '../../../../generated/configuration/testResultNotificationConfiguration';
import { Operation } from '../../../../generated/entity/policies/policy'; import { Operation } from '../../../../generated/entity/policies/policy';
import { TestCase, TestCaseResult } from '../../../../generated/tests/testCase'; import {
TestCase,
TestCaseResult,
TestCaseStatus,
} from '../../../../generated/tests/testCase';
import { TestCaseResolutionStatus } from '../../../../generated/tests/testCaseResolutionStatus'; import { TestCaseResolutionStatus } from '../../../../generated/tests/testCaseResolutionStatus';
import { getListTestCaseIncidentByStateId } from '../../../../rest/incidentManagerAPI'; import { getListTestCaseIncidentByStateId } from '../../../../rest/incidentManagerAPI';
import { removeTestCaseFromTestSuite } from '../../../../rest/testAPI'; import { removeTestCaseFromTestSuite } from '../../../../rest/testAPI';
@ -74,6 +79,7 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
afterDeleteAction, afterDeleteAction,
showPagination, showPagination,
breadcrumbData, breadcrumbData,
fetchTestCases,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { permissions } = usePermissionProvider(); const { permissions } = usePermissionProvider();
@ -82,6 +88,7 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
const [testCaseStatus, setTestCaseStatus] = useState< const [testCaseStatus, setTestCaseStatus] = useState<
TestCaseResolutionStatus[] TestCaseResolutionStatus[]
>([]); >([]);
const isApiSortingEnabled = useRef(false);
const testCaseEditPermission = useMemo(() => { const testCaseEditPermission = useMemo(() => {
return checkPermission( return checkPermission(
@ -101,19 +108,21 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
const sortedData = useMemo( const sortedData = useMemo(
() => () =>
sortBy(testCases, (test) => { isApiSortingEnabled.current
switch (test.testCaseResult?.testCaseStatus) { ? testCases
case TestCaseStatus.Failed: : sortBy(testCases, (test) => {
return 0; switch (test.testCaseResult?.testCaseStatus) {
case TestCaseStatus.Aborted: case TestCaseStatus.Failed:
return 1; return 0;
case TestCaseStatus.Success: case TestCaseStatus.Aborted:
return 2; return 1;
case TestCaseStatus.Success:
return 2;
default: default:
return 3; return 3;
} }
}), }),
[testCases] [testCases]
); );
@ -144,7 +153,7 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
width: 300, width: 300,
sorter: (a, b) => a.name.localeCompare(b.name), sorter: true,
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
render: (name: string, record) => { render: (name: string, record) => {
const status = record.testCaseResult?.testCaseStatus; const status = record.testCaseResult?.testCaseStatus;
@ -247,6 +256,7 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
dataIndex: 'testCaseResult', dataIndex: 'testCaseResult',
key: 'lastRun', key: 'lastRun',
width: 150, width: 150,
sorter: true,
render: (result: TestCaseResult) => render: (result: TestCaseResult) =>
result?.timestamp ? formatDateTime(result.timestamp) : '--', result?.timestamp ? formatDateTime(result.timestamp) : '--',
}, },
@ -411,6 +421,29 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
} }
}; };
const handleTableChange = (
_pagination: TablePaginationConfig,
_filters: Record<string, FilterValue | null>,
sorter: SorterResult<TestCase> | SorterResult<TestCase>[]
) => {
if (!isArray(sorter) && fetchTestCases) {
if (sorter?.columnKey === 'lastRun' || sorter?.columnKey === 'name') {
const sortData = isUndefined(sorter.order)
? undefined
: {
sortField:
sorter?.columnKey === 'lastRun'
? 'testCaseResult.timestamp'
: 'name.keyword',
sortType:
sorter?.order === 'ascend' ? SORT_ORDER.ASC : SORT_ORDER.DESC,
};
isApiSortingEnabled.current = !isUndefined(sorter.order);
fetchTestCases(sortData);
}
}
};
useEffect(() => { useEffect(() => {
if (testCases.length) { if (testCases.length) {
fetchTestCaseStatus(); fetchTestCaseStatus();
@ -454,6 +487,7 @@ const DataQualityTab: React.FC<DataQualityTabProps> = ({
pagination={false} pagination={false}
rowKey="id" rowKey="id"
size="small" size="small"
onChange={handleTableChange}
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>

View File

@ -21,7 +21,10 @@ import {
import { Thread } from '../../../../generated/entity/feed/thread'; import { Thread } from '../../../../generated/entity/feed/thread';
import { TestCase } from '../../../../generated/tests/testCase'; import { TestCase } from '../../../../generated/tests/testCase';
import { TestSuite } from '../../../../generated/tests/testSuite'; import { TestSuite } from '../../../../generated/tests/testSuite';
import { ListTestCaseParams } from '../../../../rest/testAPI'; import {
ListTestCaseParams,
ListTestCaseParamsBySearch,
} from '../../../../rest/testAPI';
import { NextPreviousProps } from '../../../common/NextPrevious/NextPrevious.interface'; import { NextPreviousProps } from '../../../common/NextPrevious/NextPrevious.interface';
import { TitleBreadcrumbProps } from '../../../common/TitleBreadcrumb/TitleBreadcrumb.interface'; import { TitleBreadcrumbProps } from '../../../common/TitleBreadcrumb/TitleBreadcrumb.interface';
@ -115,6 +118,7 @@ export interface DataQualityTabProps {
}; };
showPagination?: boolean; showPagination?: boolean;
breadcrumbData?: TitleBreadcrumbProps['titleLinks']; breadcrumbData?: TitleBreadcrumbProps['titleLinks'];
fetchTestCases?: (params?: ListTestCaseParamsBySearch) => Promise<void>;
} }
export interface TestSummaryProps { export interface TestSummaryProps {

View File

@ -16,9 +16,13 @@ import { isEmpty } from 'lodash';
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { getEntityDetailsPath } from '../../../../../constants/constants'; import {
getEntityDetailsPath,
INITIAL_PAGING_VALUE,
} from '../../../../../constants/constants';
import { PAGE_HEADERS } from '../../../../../constants/PageHeaders.constant'; import { PAGE_HEADERS } from '../../../../../constants/PageHeaders.constant';
import { import {
DEFAULT_SORT_ORDER,
TEST_CASE_STATUS_OPTION, TEST_CASE_STATUS_OPTION,
TEST_CASE_TYPE_OPTION, TEST_CASE_TYPE_OPTION,
} from '../../../../../constants/profiler.constant'; } from '../../../../../constants/profiler.constant';
@ -29,7 +33,10 @@ import { ProfilerDashboardType } from '../../../../../enums/table.enum';
import { TestCaseStatus } from '../../../../../generated/tests/testCase'; import { TestCaseStatus } from '../../../../../generated/tests/testCase';
import LimitWrapper from '../../../../../hoc/LimitWrapper'; import LimitWrapper from '../../../../../hoc/LimitWrapper';
import { useFqn } from '../../../../../hooks/useFqn'; import { useFqn } from '../../../../../hooks/useFqn';
import { TestCaseType } from '../../../../../rest/testAPI'; import {
ListTestCaseParamsBySearch,
TestCaseType,
} from '../../../../../rest/testAPI';
import { import {
getBreadcrumbForTable, getBreadcrumbForTable,
getEntityName, getEntityName,
@ -78,6 +85,8 @@ export const QualityTab = () => {
useState<TestCaseStatus>('' as TestCaseStatus); useState<TestCaseStatus>('' as TestCaseStatus);
const [selectedTestType, setSelectedTestType] = useState(TestCaseType.all); const [selectedTestType, setSelectedTestType] = useState(TestCaseType.all);
const [searchValue, setSearchValue] = useState<string>(); const [searchValue, setSearchValue] = useState<string>();
const [sortOptions, setSortOptions] =
useState<ListTestCaseParamsBySearch>(DEFAULT_SORT_ORDER);
const testSuite = useMemo(() => table?.testSuite, [table]); const testSuite = useMemo(() => table?.testSuite, [table]);
const handleTestCasePageChange: NextPreviousProps['pagingHandler'] = ({ const handleTestCasePageChange: NextPreviousProps['pagingHandler'] = ({
@ -85,6 +94,7 @@ export const QualityTab = () => {
}) => { }) => {
if (currentPage) { if (currentPage) {
fetchAllTests({ fetchAllTests({
...sortOptions,
testCaseType: selectedTestType, testCaseType: selectedTestType,
testCaseStatus: isEmpty(selectedTestCaseStatus) testCaseStatus: isEmpty(selectedTestCaseStatus)
? undefined ? undefined
@ -106,6 +116,12 @@ export const QualityTab = () => {
}); });
}; };
const handleSortTestCase = async (apiParams?: ListTestCaseParamsBySearch) => {
setSortOptions(apiParams ?? DEFAULT_SORT_ORDER);
await fetchAllTests({ ...(apiParams ?? DEFAULT_SORT_ORDER), offset: 0 });
handlePageChange(INITIAL_PAGING_VALUE);
};
const tableBreadcrumb = useMemo(() => { const tableBreadcrumb = useMemo(() => {
return table return table
? [ ? [
@ -147,6 +163,7 @@ export const QualityTab = () => {
(await getResourceLimit('dataQuality', true, true)); (await getResourceLimit('dataQuality', true, true));
}} }}
breadcrumbData={tableBreadcrumb} breadcrumbData={tableBreadcrumb}
fetchTestCases={handleSortTestCase}
isLoading={isTestsLoading} isLoading={isTestsLoading}
showTableColumn={false} showTableColumn={false}
testCases={allTestCases} testCases={allTestCases}

View File

@ -165,6 +165,8 @@ describe('QualityTab', () => {
offset: 10, offset: 10,
testCaseStatus: undefined, testCaseStatus: undefined,
testCaseType: 'all', testCaseType: 'all',
sortField: 'testCaseResult.timestamp',
sortType: 'desc',
}); });
}); });

View File

@ -26,7 +26,10 @@ import React, {
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PAGE_SIZE } from '../../../../constants/constants'; import { PAGE_SIZE } from '../../../../constants/constants';
import { mockDatasetData } from '../../../../constants/mockTourData.constants'; import { mockDatasetData } from '../../../../constants/mockTourData.constants';
import { DEFAULT_RANGE_DATA } from '../../../../constants/profiler.constant'; import {
DEFAULT_RANGE_DATA,
DEFAULT_SORT_ORDER,
} from '../../../../constants/profiler.constant';
import { useTourProvider } from '../../../../context/TourProvider/TourProvider'; import { useTourProvider } from '../../../../context/TourProvider/TourProvider';
import { TabSpecificField } from '../../../../enums/entity.enum'; import { TabSpecificField } from '../../../../enums/entity.enum';
import { Table } from '../../../../generated/entity/data/table'; import { Table } from '../../../../generated/entity/data/table';
@ -209,6 +212,7 @@ export const TableProfilerProvider = ({
setIsTestsLoading(true); setIsTestsLoading(true);
try { try {
const { data, paging } = await getListTestCaseBySearch({ const { data, paging } = await getListTestCaseBySearch({
...DEFAULT_SORT_ORDER,
...params, ...params,
fields: [ fields: [
TabSpecificField.TEST_CASE_RESULT, TabSpecificField.TEST_CASE_RESULT,

View File

@ -16,6 +16,7 @@ import { capitalize, map, startCase, values } from 'lodash';
import { DateFilterType, StepperStepType } from 'Models'; import { DateFilterType, StepperStepType } from 'Models';
import { TestCaseSearchParams } from '../components/DataQuality/DataQuality.interface'; import { TestCaseSearchParams } from '../components/DataQuality/DataQuality.interface';
import { CSMode } from '../enums/codemirror.enum'; import { CSMode } from '../enums/codemirror.enum';
import { SORT_ORDER } from '../enums/common.enum';
import { DMLOperationType } from '../generated/api/data/createTableProfile'; import { DMLOperationType } from '../generated/api/data/createTableProfile';
import { import {
ColumnProfilerConfig, ColumnProfilerConfig,
@ -466,3 +467,8 @@ export const DEFAULT_PROFILER_CONFIG_VALUE = {
}, },
], ],
}; };
export const DEFAULT_SORT_ORDER = {
sortType: SORT_ORDER.DESC,
sortField: 'testCaseResult.timestamp',
};

View File

@ -31,6 +31,8 @@ import { TitleBreadcrumbProps } from '../../components/common/TitleBreadcrumb/Ti
import DataQualityTab from '../../components/Database/Profiler/DataQualityTab/DataQualityTab'; import DataQualityTab from '../../components/Database/Profiler/DataQualityTab/DataQualityTab';
import { AddTestCaseList } from '../../components/DataQuality/AddTestCaseList/AddTestCaseList.component'; import { AddTestCaseList } from '../../components/DataQuality/AddTestCaseList/AddTestCaseList.component';
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1'; import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
import { INITIAL_PAGING_VALUE } from '../../constants/constants';
import { DEFAULT_SORT_ORDER } from '../../constants/profiler.constant';
import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider'; import { usePermissionProvider } from '../../context/PermissionProvider/PermissionProvider';
import { import {
OperationPermission, OperationPermission,
@ -86,10 +88,12 @@ const TestSuiteDetailsPage = () => {
showPagination, showPagination,
} = usePaging(); } = usePaging();
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const [testSuitePermissions, setTestSuitePermission] = const [testSuitePermissions, setTestSuitePermissions] =
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION); useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
const [isTestCaseModalOpen, setIsTestCaseModalOpen] = const [isTestCaseModalOpen, setIsTestCaseModalOpen] =
useState<boolean>(false); useState<boolean>(false);
const [sortOptions, setSortOptions] =
useState<ListTestCaseParamsBySearch>(DEFAULT_SORT_ORDER);
const [slashedBreadCrumb, setSlashedBreadCrumb] = useState< const [slashedBreadCrumb, setSlashedBreadCrumb] = useState<
TitleBreadcrumbProps['titleLinks'] TitleBreadcrumbProps['titleLinks']
@ -133,7 +137,7 @@ const TestSuiteDetailsPage = () => {
ResourceEntity.TEST_SUITE, ResourceEntity.TEST_SUITE,
testSuiteFQN testSuiteFQN
); );
setTestSuitePermission(response); setTestSuitePermissions(response);
} catch (error) { } catch (error) {
showErrorToast(error as AxiosError); showErrorToast(error as AxiosError);
} finally { } finally {
@ -152,6 +156,7 @@ const TestSuiteDetailsPage = () => {
TabSpecificField.INCIDENT_ID, TabSpecificField.INCIDENT_ID,
], ],
testSuiteId, testSuiteId,
...sortOptions,
...param, ...param,
limit: pageSize, limit: pageSize,
}); });
@ -169,6 +174,11 @@ const TestSuiteDetailsPage = () => {
setIsTestCaseLoading(false); setIsTestCaseLoading(false);
} }
}; };
const handleSortTestCase = async (apiParams?: ListTestCaseParamsBySearch) => {
setSortOptions(apiParams ?? DEFAULT_SORT_ORDER);
await fetchTestCases({ ...(apiParams ?? DEFAULT_SORT_ORDER), offset: 0 });
handlePageChange(INITIAL_PAGING_VALUE);
};
const handleAddTestCaseSubmit = async (testCases: TestCase[]) => { const handleAddTestCaseSubmit = async (testCases: TestCase[]) => {
const testCaseIds = testCases.reduce((ids, curr) => { const testCaseIds = testCases.reduce((ids, curr) => {
@ -391,6 +401,7 @@ const TestSuiteDetailsPage = () => {
<DataQualityTab <DataQualityTab
afterDeleteAction={fetchTestCases} afterDeleteAction={fetchTestCases}
breadcrumbData={incidentUrlState} breadcrumbData={incidentUrlState}
fetchTestCases={handleSortTestCase}
isLoading={isLoading || isTestCaseLoading} isLoading={isLoading || isTestCaseLoading}
pagingData={pagingData} pagingData={pagingData}
removeFromTestSuite={{ testSuite: testSuite as TestSuite }} removeFromTestSuite={{ testSuite: testSuite as TestSuite }}