Fix #5091 Make "Data Quality" column on Table schema page optional to hide (#7260)

* Fix #5091 Make "Data Quality" column on Table schema page optional to hide

* Fix unit test

* Improve checks
This commit is contained in:
Sachin Chaurasiya 2022-09-06 21:59:40 +05:30 committed by GitHub
parent 84aede2eaf
commit be553eb017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 128 additions and 59 deletions

View File

@ -176,13 +176,15 @@ const BotListV1 = ({
<ErrorPlaceHolder <ErrorPlaceHolder
buttons={ buttons={
<div className="tw-text-lg tw-text-center"> <div className="tw-text-lg tw-text-center">
<Button <Tooltip
ghost title={createPermission ? 'Add Bot' : NO_PERMISSION_FOR_ACTION}>
title="Add Team" <Button
type="primary" disabled={!createPermission}
onClick={handleAddBotClick}> type="primary"
Add Bot onClick={handleAddBotClick}>
</Button> Add Bot
</Button>
</Tooltip>
</div> </div>
} }
doc={BOTS_DOCS} doc={BOTS_DOCS}

View File

@ -48,11 +48,7 @@ import { getEntityFeedLink } from '../../utils/EntityUtils';
import { getDefaultValue } from '../../utils/FeedElementUtils'; import { getDefaultValue } from '../../utils/FeedElementUtils';
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils'; import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { import { getTagsWithoutTier, getUsagePercentile } from '../../utils/TableUtils';
getTableTestsValue,
getTagsWithoutTier,
getUsagePercentile,
} from '../../utils/TableUtils';
import { showErrorToast } from '../../utils/ToastUtils'; import { showErrorToast } from '../../utils/ToastUtils';
import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList'; import ActivityFeedList from '../ActivityFeed/ActivityFeedList/ActivityFeedList';
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel'; import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
@ -125,7 +121,6 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
postFeedHandler, postFeedHandler,
feedCount, feedCount,
entityFieldThreadCount, entityFieldThreadCount,
tableTestCase,
createThread, createThread,
qualityTestFormHandler, qualityTestFormHandler,
deletePostHandler, deletePostHandler,
@ -408,7 +403,6 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
key: 'Rows', key: 'Rows',
value: prepareTableRowInfo(), value: prepareTableRowInfo(),
}, },
{ key: 'Tests', value: getTableTestsValue(tableTestCase) },
]; ];
const onDescriptionEdit = (): void => { const onDescriptionEdit = (): void => {
@ -745,9 +739,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
)} )}
{activeTab === 5 && ( {activeTab === 5 && (
<TableProfilerV1 <TableProfilerV1
hasEditAccess={ permissions={tablePermissions}
tablePermissions.EditAll || tablePermissions.EditDataProfile
}
table={tableDetails} table={tableDetails}
onAddTestClick={qualityTestFormHandler} onAddTestClick={qualityTestFormHandler}
/> />

View File

@ -833,20 +833,6 @@ const EntityTable = ({
return renderCell(TABLE_HEADERS_V1.dataTypeDisplay, record, index); return renderCell(TABLE_HEADERS_V1.dataTypeDisplay, record, index);
}, },
}, },
{
title: 'Data Quality',
dataIndex: 'columnTests',
key: 'columnTests',
accessor: 'columnTests',
width: 200,
render: (
_: Array<unknown>,
record: ModifiedTableColumn,
index: number
) => {
return renderCell(TABLE_HEADERS_V1.columnTests, record, index);
},
},
{ {
title: 'Description', title: 'Description',
dataIndex: 'description', dataIndex: 'description',

View File

@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { Button, Col, Form, Radio, Row, Select, Space } from 'antd'; import { Button, Col, Form, Radio, Row, Select, Space, Tooltip } from 'antd';
import { RadioChangeEvent } from 'antd/lib/radio'; import { RadioChangeEvent } from 'antd/lib/radio';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { EntityTags, ExtraInfo } from 'Models'; import { EntityTags, ExtraInfo } from 'Models';
@ -25,6 +25,7 @@ import {
getTableTabPath, getTableTabPath,
getTeamAndUserDetailsPath, getTeamAndUserDetailsPath,
} from '../../constants/constants'; } from '../../constants/constants';
import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil';
import { PROFILER_FILTER_RANGE } from '../../constants/profiler.constant'; import { PROFILER_FILTER_RANGE } from '../../constants/profiler.constant';
import { EntityType, FqnPart } from '../../enums/entity.enum'; import { EntityType, FqnPart } from '../../enums/entity.enum';
import { ServiceCategory } from '../../enums/service.enum'; import { ServiceCategory } from '../../enums/service.enum';
@ -480,9 +481,19 @@ const ProfilerDashboard: React.FC<ProfilerDashboardProps> = ({
onChange={handleTimeRangeChange} onChange={handleTimeRangeChange}
/> />
)} )}
<Button type="primary" onClick={handleAddTestClick}> <Tooltip
Add Test title={
</Button> permission.EditAll || permission.EditTests
? 'Add Test'
: NO_PERMISSION_FOR_ACTION
}>
<Button
disabled={!(permission.EditAll || permission.EditTests)}
type="primary"
onClick={handleAddTestClick}>
Add Test
</Button>
</Tooltip>
</Space> </Space>
</Row> </Row>
</Col> </Col>

View File

@ -14,6 +14,7 @@
import { Column, Table } from '../../generated/entity/data/table'; import { Column, Table } from '../../generated/entity/data/table';
import { TestCase } from '../../generated/tests/testCase'; import { TestCase } from '../../generated/tests/testCase';
import { DatasetTestModeType } from '../../interface/dataQuality.interface'; import { DatasetTestModeType } from '../../interface/dataQuality.interface';
import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface';
export interface TableProfilerProps { export interface TableProfilerProps {
onAddTestClick: ( onAddTestClick: (
@ -22,7 +23,7 @@ export interface TableProfilerProps {
columnName?: string columnName?: string
) => void; ) => void;
table: Table; table: Table;
hasEditAccess: boolean; permissions: OperationPermission;
} }
export type TableTestsType = { export type TableTestsType = {

View File

@ -21,6 +21,7 @@ import {
} from '@testing-library/react'; } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { MOCK_TABLE, TEST_CASE } from '../../mocks/TableData.mock'; import { MOCK_TABLE, TEST_CASE } from '../../mocks/TableData.mock';
import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface';
import { TableProfilerProps } from './TableProfiler.interface'; import { TableProfilerProps } from './TableProfiler.interface';
// internal imports // internal imports
import TableProfilerV1 from './TableProfilerV1'; import TableProfilerV1 from './TableProfilerV1';
@ -60,7 +61,28 @@ jest.mock('../../axiosAPIs/testAPI', () => ({
const mockProps: TableProfilerProps = { const mockProps: TableProfilerProps = {
table: MOCK_TABLE, table: MOCK_TABLE,
hasEditAccess: true, permissions: {
Create: true,
Delete: true,
EditAll: true,
EditCustomFields: true,
EditDataProfile: true,
EditDescription: true,
EditDisplayName: true,
EditLineage: true,
EditOwner: true,
EditQueries: true,
EditSampleData: true,
EditTags: true,
EditTests: true,
EditTier: true,
ViewAll: true,
ViewDataProfile: true,
ViewQueries: true,
ViewSampleData: true,
ViewTests: true,
ViewUsage: true,
} as OperationPermission,
onAddTestClick: jest.fn(), onAddTestClick: jest.fn(),
}; };

View File

@ -57,9 +57,9 @@ import './tableProfiler.less';
const TableProfilerV1: FC<TableProfilerProps> = ({ const TableProfilerV1: FC<TableProfilerProps> = ({
table, table,
onAddTestClick, onAddTestClick,
hasEditAccess, permissions,
}) => { }) => {
const { profile, columns } = table; const { profile, columns = [] } = table;
const history = useHistory(); const history = useHistory();
const [settingModalVisible, setSettingModalVisible] = useState(false); const [settingModalVisible, setSettingModalVisible] = useState(false);
const [columnTests, setColumnTests] = useState<TestCase[]>([]); const [columnTests, setColumnTests] = useState<TestCase[]>([]);
@ -71,6 +71,10 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
ProfilerDashboardTab.SUMMARY ProfilerDashboardTab.SUMMARY
); );
const viewTest = permissions.ViewAll || permissions.ViewTests;
const viewProfiler = permissions.ViewAll || permissions.ViewDataProfile;
const editTest = permissions.EditAll || permissions.EditTests;
const handleSettingModal = (value: boolean) => { const handleSettingModal = (value: boolean) => {
setSettingModalVisible(value); setSettingModalVisible(value);
}; };
@ -106,11 +110,18 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
]; ];
}, [profile, tableTests]); }, [profile, tableTests]);
const tabOptions = useMemo(() => { const tabOptions = [
return Object.values(ProfilerDashboardTab).filter( {
(value) => value !== ProfilerDashboardTab.PROFILER label: ProfilerDashboardTab.SUMMARY,
); value: ProfilerDashboardTab.SUMMARY,
}, []); disabled: !viewProfiler,
},
{
label: ProfilerDashboardTab.DATA_QUALITY,
value: ProfilerDashboardTab.DATA_QUALITY,
disabled: !viewTest,
},
];
const handleTabChange = (e: RadioChangeEvent) => { const handleTabChange = (e: RadioChangeEvent) => {
const value = e.target.value as ProfilerDashboardTab; const value = e.target.value as ProfilerDashboardTab;
@ -158,8 +169,9 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
}; };
useEffect(() => { useEffect(() => {
if (isEmpty(table)) return; if (!isEmpty(table) && viewTest) {
fetchAllTests(); fetchAllTests();
}
}, [table]); }, [table]);
return ( return (
@ -177,11 +189,10 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
/> />
<Space> <Space>
<Tooltip <Tooltip title={editTest ? 'Add Test' : NO_PERMISSION_FOR_ACTION}>
title={hasEditAccess ? 'Add Test' : NO_PERMISSION_FOR_ACTION}>
<Link <Link
to={ to={
hasEditAccess editTest
? getAddDataQualityTableTestPath( ? getAddDataQualityTableTestPath(
ProfilerDashboardType.TABLE, ProfilerDashboardType.TABLE,
`${table.fullyQualifiedName}` `${table.fullyQualifiedName}`
@ -191,18 +202,17 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
<Button <Button
className="tw-rounded" className="tw-rounded"
data-testid="profiler-add-table-test-btn" data-testid="profiler-add-table-test-btn"
disabled={!hasEditAccess} disabled={!editTest}
type="primary"> type="primary">
Add Test Add Test
</Button> </Button>
</Link> </Link>
</Tooltip> </Tooltip>
<Tooltip <Tooltip title={editTest ? 'Settings' : NO_PERMISSION_FOR_ACTION}>
title={hasEditAccess ? 'Settings' : NO_PERMISSION_FOR_ACTION}>
<Button <Button
className="profiler-setting-btn tw-border tw-border-primary tw-rounded tw-text-primary" className="profiler-setting-btn tw-border tw-border-primary tw-rounded tw-text-primary"
data-testid="profiler-setting-btn" data-testid="profiler-setting-btn"
disabled={!hasEditAccess} disabled={!editTest}
icon={<SVGIcons alt="setting" icon={Icons.SETTINGS_PRIMERY} />} icon={<SVGIcons alt="setting" icon={Icons.SETTINGS_PRIMERY} />}
type="default" type="default"
onClick={() => handleSettingModal(true)}> onClick={() => handleSettingModal(true)}>
@ -258,7 +268,7 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
...col, ...col,
key: col.name, key: col.name,
}))} }))}
hasEditAccess={hasEditAccess} hasEditAccess={editTest}
onAddTestClick={onAddTestClick} onAddTestClick={onAddTestClick}
/> />

View File

@ -13,6 +13,7 @@
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch'; import { compare } from 'fast-json-patch';
import { isEmpty } from 'lodash';
import moment from 'moment'; import moment from 'moment';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
@ -25,6 +26,11 @@ import { getListTestCase } from '../../axiosAPIs/testAPI';
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder'; import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
import PageContainerV1 from '../../components/containers/PageContainerV1'; import PageContainerV1 from '../../components/containers/PageContainerV1';
import Loader from '../../components/Loader/Loader'; import Loader from '../../components/Loader/Loader';
import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider';
import {
OperationPermission,
ResourceEntity,
} from '../../components/PermissionProvider/PermissionProvider.interface';
import ProfilerDashboard from '../../components/ProfilerDashboard/ProfilerDashboard'; import ProfilerDashboard from '../../components/ProfilerDashboard/ProfilerDashboard';
import { API_RES_MAX_SIZE } from '../../constants/constants'; import { API_RES_MAX_SIZE } from '../../constants/constants';
import { ProfilerDashboardType } from '../../enums/table.enum'; import { ProfilerDashboardType } from '../../enums/table.enum';
@ -35,6 +41,7 @@ import {
getNameFromFQN, getNameFromFQN,
getTableFQNFromColumnFQN, getTableFQNFromColumnFQN,
} from '../../utils/CommonUtils'; } from '../../utils/CommonUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { generateEntityLink } from '../../utils/TableUtils'; import { generateEntityLink } from '../../utils/TableUtils';
import { showErrorToast } from '../../utils/ToastUtils'; import { showErrorToast } from '../../utils/ToastUtils';
@ -47,6 +54,27 @@ const ProfilerDashboardPage = () => {
const [error, setError] = useState(false); const [error, setError] = useState(false);
const [testCases, setTestCases] = useState<TestCase[]>([]); const [testCases, setTestCases] = useState<TestCase[]>([]);
const [tablePermissions, setTablePermissions] = useState<OperationPermission>(
DEFAULT_ENTITY_PERMISSION
);
const { getEntityPermission } = usePermissionProvider();
const fetchResourcePermission = async () => {
try {
const tablePermission = await getEntityPermission(
ResourceEntity.TABLE,
table.id
);
setTablePermissions(tablePermission);
} catch (error) {
showErrorToast(
jsonData['api-error-messages']['fetch-entity-permissions-error']
);
}
};
const fetchProfilerData = async (fqn: string, days = 3) => { const fetchProfilerData = async (fqn: string, days = 3) => {
try { try {
const startTs = moment().subtract(days, 'days').unix(); const startTs = moment().subtract(days, 'days').unix();
@ -98,11 +126,6 @@ const ProfilerDashboardPage = () => {
}`; }`;
const data = await getTableDetailsByFQN(fqn, field); const data = await getTableDetailsByFQN(fqn, field);
setTable(data ?? ({} as Table)); setTable(data ?? ({} as Table));
if (isColumnView) {
fetchProfilerData(entityTypeFQN);
} else {
fetchTestCases(generateEntityLink(entityTypeFQN));
}
} catch (error) { } catch (error) {
showErrorToast( showErrorToast(
error as AxiosError, error as AxiosError,
@ -127,6 +150,16 @@ const ProfilerDashboardPage = () => {
} }
}; };
const getProfilerDashboard = (permission: OperationPermission) => {
if (isColumnView && (permission.ViewAll || permission.ViewDataProfile)) {
fetchProfilerData(entityTypeFQN);
} else {
if (permission.ViewAll || permission.ViewTests) {
fetchTestCases(generateEntityLink(entityTypeFQN));
}
}
};
useEffect(() => { useEffect(() => {
if (entityTypeFQN) { if (entityTypeFQN) {
fetchTableEntity(); fetchTableEntity();
@ -136,6 +169,18 @@ const ProfilerDashboardPage = () => {
} }
}, [entityTypeFQN]); }, [entityTypeFQN]);
useEffect(() => {
if (!isEmpty(table)) {
fetchResourcePermission();
}
}, [table]);
useEffect(() => {
if (!isEmpty(table)) {
getProfilerDashboard(tablePermissions);
}
}, [table, tablePermissions]);
if (isLoading) { if (isLoading) {
return <Loader />; return <Loader />;
} }