mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-30 17:44:16 +00:00
refactor(ui): replace custom tabs component with ANTD component for dataset details page (#11751)
* refactor(ui): replace custom tabs component with ANTD component for dataset details page * fixed failing unit test and updated tour page * fixed failing cypress * replace custom tabs with antd tabs in all the version details page * code smell * refactor table details page * fixed failing unit test and broken tour page * fixed broken tour
This commit is contained in:
parent
f0f64a7b21
commit
bebdb98e68
@ -594,10 +594,6 @@ describe('Data Quality and Profiler should work properly', () => {
|
||||
cy.get('[data-testid="Profiler & Data Quality"]')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[data-testid="Profiler & Data Quality"]').should(
|
||||
'have.class',
|
||||
'active'
|
||||
);
|
||||
interceptURL('GET', '/api/v1/tables/*/columnProfile?*', 'getProfilerInfo');
|
||||
|
||||
cy.get('[data-testid="profiler-tab-left-panel"]')
|
||||
@ -649,10 +645,6 @@ describe('Data Quality and Profiler should work properly', () => {
|
||||
cy.get('[data-testid="Profiler & Data Quality"]')
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[data-testid="Profiler & Data Quality"]').should(
|
||||
'have.class',
|
||||
'active'
|
||||
);
|
||||
interceptURL(
|
||||
'GET',
|
||||
`api/v1/tables/name/${serviceName}.*.${term}?include=all`,
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
import { EntityUnion } from 'components/Explore/explore.interface';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { isEmpty, isNil, isUndefined } from 'lodash';
|
||||
import { action, makeAutoObservable } from 'mobx';
|
||||
import { ClientAuth, NewUser } from 'Models';
|
||||
@ -56,7 +57,7 @@ class AppState {
|
||||
|
||||
isTourOpen = false;
|
||||
currentTourPage: CurrentTourPageType = CurrentTourPageType.MY_DATA_PAGE;
|
||||
activeTabforTourDatasetPage = 1;
|
||||
activeTabforTourDatasetPage = EntityTabs.SCHEMA;
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this, {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card } from 'antd';
|
||||
import { Card, Tabs } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
@ -29,7 +29,7 @@ import { getEntityName } from 'utils/EntityUtils';
|
||||
import { bytesToSize } from 'utils/StringsUtils';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
|
||||
import { EntityField } from '../../constants/Feeds.constants';
|
||||
import { EntityInfo, FqnPart } from '../../enums/entity.enum';
|
||||
import { EntityInfo, EntityTabs, FqnPart } from '../../enums/entity.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import { TagLabel } from '../../generated/type/tagLabel';
|
||||
import { getPartialNameFromTableFQN } from '../../utils/CommonUtils';
|
||||
@ -42,7 +42,6 @@ import {
|
||||
import { TagLabelWithStatus } from '../../utils/EntityVersionUtils.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import VersionTable from '../VersionTable/VersionTable.component';
|
||||
@ -374,9 +373,8 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.schema'),
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.schema'),
|
||||
key: EntityTabs.SCHEMA,
|
||||
},
|
||||
];
|
||||
|
||||
@ -411,7 +409,7 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.SCHEMA} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -11,11 +11,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Space, Table } from 'antd';
|
||||
import { Card, Space, Table, Tabs } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { ExtraInfo } from 'Models';
|
||||
import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||
@ -42,7 +43,6 @@ import SVGIcons from '../../utils/SvgUtils';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPreviewer';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import { DashboardVersionProp } from './DashboardVersion.interface';
|
||||
@ -65,9 +65,8 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
|
||||
);
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.detail-plural'),
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.detail-plural'),
|
||||
key: EntityTabs.SCHEMA,
|
||||
},
|
||||
];
|
||||
|
||||
@ -294,7 +293,11 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs
|
||||
activeKey={EntityTabs.SCHEMA}
|
||||
data-testid="tabs"
|
||||
items={tabs}
|
||||
/>
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -32,10 +32,6 @@ jest.mock('../common/description/Description', () => {
|
||||
return jest.fn().mockImplementation(() => <div>Description.component</div>);
|
||||
});
|
||||
|
||||
jest.mock('../common/TabsPane/TabsPane', () => {
|
||||
return jest.fn().mockImplementation(() => <div>TabsPane.component</div>);
|
||||
});
|
||||
|
||||
jest.mock('../EntityVersionTimeLine/EntityVersionTimeLine', () => {
|
||||
return jest
|
||||
.fn()
|
||||
@ -106,7 +102,7 @@ describe('Test DashboardVersion page', () => {
|
||||
container,
|
||||
'EntityVersionTimeLine.component'
|
||||
);
|
||||
const tabs = await findByText(container, 'TabsPane.component');
|
||||
const tabs = await findByTestId(container, 'tabs');
|
||||
const description = await findByText(container, 'Description.component');
|
||||
const richTextEditorPreviewer = await findByText(
|
||||
container,
|
||||
@ -150,7 +146,7 @@ describe('Test DashboardVersion page', () => {
|
||||
container,
|
||||
'EntityVersionTimeLine.component'
|
||||
);
|
||||
const tabs = await findByText(container, 'TabsPane.component');
|
||||
const tabs = await findByTestId(container, 'tabs');
|
||||
const description = await findByText(container, 'Description.component');
|
||||
const richTextEditorPreviewer = await findByText(
|
||||
container,
|
||||
@ -192,7 +188,7 @@ describe('Test DashboardVersion page', () => {
|
||||
container,
|
||||
'EntityVersionTimeLine.component'
|
||||
);
|
||||
const tabs = await findByText(container, 'TabsPane.component');
|
||||
const tabs = await findByTestId(container, 'tabs');
|
||||
const description = await findByText(container, 'Description.component');
|
||||
|
||||
expect(dashboardVersionContainer).toBeInTheDocument();
|
||||
|
||||
@ -11,12 +11,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card } from 'antd';
|
||||
import { Card, Tabs } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import VersionTable from 'components/VersionTable/VersionTable.component';
|
||||
import { FqnPart } from 'enums/entity.enum';
|
||||
import { EntityTabs, FqnPart } from 'enums/entity.enum';
|
||||
import {
|
||||
ChangeDescription,
|
||||
Column,
|
||||
@ -42,7 +42,6 @@ import {
|
||||
import { TagLabelWithStatus } from '../../utils/EntityVersionUtils.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import { DataModelVersionProp } from './DataModelVersion.interface';
|
||||
@ -66,9 +65,8 @@ const DataModelVersion: FC<DataModelVersionProp> = ({
|
||||
);
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.detail-plural'),
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.model'),
|
||||
key: EntityTabs.MODEL,
|
||||
},
|
||||
];
|
||||
|
||||
@ -415,7 +413,7 @@ const DataModelVersion: FC<DataModelVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.MODEL} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -11,13 +11,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Col, Row, Skeleton, Space, Typography } from 'antd';
|
||||
import { Card, Col, Row, Skeleton, Space, Tabs, Typography } from 'antd';
|
||||
import AppState from 'AppState';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { ActivityFilters } from 'components/ActivityFeed/ActivityFeedList/ActivityFeedList.interface';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.interface';
|
||||
import { ROUTES } from 'constants/constants';
|
||||
import TabsLabel from 'components/TabsLabel/TabsLabel.component';
|
||||
import { getTableTabPath, ROUTES } from 'constants/constants';
|
||||
import { mockTablePermission } from 'constants/mockTourData.constants';
|
||||
import { SearchIndex } from 'enums/search.enum';
|
||||
import { isEqual, isNil, isUndefined } from 'lodash';
|
||||
@ -30,7 +32,7 @@ import React, {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
||||
import { searchQuery } from 'rest/searchAPI';
|
||||
import { restoreTable } from 'rest/tableAPI';
|
||||
import {
|
||||
@ -45,7 +47,12 @@ import {
|
||||
} from '../../constants/char.constants';
|
||||
import { EntityField } from '../../constants/Feeds.constants';
|
||||
import { observerOptions } from '../../constants/Mydata.constants';
|
||||
import { EntityInfo, EntityType, FqnPart } from '../../enums/entity.enum';
|
||||
import {
|
||||
EntityInfo,
|
||||
EntityTabs,
|
||||
EntityType,
|
||||
FqnPart,
|
||||
} from '../../enums/entity.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import {
|
||||
JoinedWith,
|
||||
@ -79,7 +86,6 @@ import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropert
|
||||
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import PageContainerV1 from '../containers/PageContainerV1';
|
||||
import EntityLineageComponent from '../EntityLineage/EntityLineage.component';
|
||||
import FrequentlyJoinedTables from '../FrequentlyJoinedTables/FrequentlyJoinedTables.component';
|
||||
@ -99,9 +105,6 @@ import './datasetDetails.style.less';
|
||||
import DbtTab from './DbtTab/DbtTab.component';
|
||||
|
||||
const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
datasetFQN,
|
||||
activeTab,
|
||||
setActiveTabHandler,
|
||||
tableProfile,
|
||||
followTableHandler,
|
||||
unfollowTableHandler,
|
||||
@ -124,6 +127,9 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
}: DatasetDetailsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const { datasetFQN, tab } =
|
||||
useParams<{ datasetFQN: string; tab: EntityTabs }>();
|
||||
const history = useHistory();
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
const [usage, setUsage] = useState('');
|
||||
const [threadLink, setThreadLink] = useState<string>('');
|
||||
@ -137,6 +143,8 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
const [tablePermissions, setTablePermissions] = useState<OperationPermission>(
|
||||
DEFAULT_ENTITY_PERMISSION
|
||||
);
|
||||
// For tour we have to maintain state
|
||||
const [activeTab, setActiveTab] = useState(tab ?? EntityTabs.SCHEMA);
|
||||
|
||||
const [activityFilter, setActivityFilter] = useState<ActivityFilters>();
|
||||
const {
|
||||
@ -146,11 +154,8 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
tableType,
|
||||
version,
|
||||
followers = [],
|
||||
deleted,
|
||||
columns,
|
||||
description,
|
||||
usageSummary,
|
||||
joins,
|
||||
entityName,
|
||||
} = useMemo(() => {
|
||||
const { tags } = tableDetails;
|
||||
@ -235,116 +240,87 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
};
|
||||
}, [followers]);
|
||||
|
||||
const tabs = useMemo(
|
||||
() => [
|
||||
const tabs = useMemo(() => {
|
||||
const allTabs = [
|
||||
{
|
||||
name: t('label.schema'),
|
||||
icon: {
|
||||
alt: 'schema',
|
||||
name: 'icon-schema',
|
||||
title: 'Schema',
|
||||
selectedName: 'icon-schemacolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: <TabsLabel name={t('label.schema')} />,
|
||||
key: EntityTabs.SCHEMA,
|
||||
},
|
||||
{
|
||||
name: t('label.activity-feed-and-task-plural'),
|
||||
icon: {
|
||||
alt: 'activity_feed',
|
||||
name: 'activity_feed',
|
||||
title: 'Activity Feed',
|
||||
selectedName: 'activity-feed-color',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 2,
|
||||
count: feedCount,
|
||||
label: (
|
||||
<TabsLabel
|
||||
count={feedCount}
|
||||
isActive={activeTab === EntityTabs.ACTIVITY_FEED}
|
||||
name={t('label.activity-feed-and-task-plural')}
|
||||
/>
|
||||
),
|
||||
key: EntityTabs.ACTIVITY_FEED,
|
||||
},
|
||||
{
|
||||
name: t('label.sample-data'),
|
||||
icon: {
|
||||
alt: 'sample_data',
|
||||
name: 'sample-data',
|
||||
title: 'Sample Data',
|
||||
selectedName: 'sample-data-color',
|
||||
},
|
||||
isProtected: false,
|
||||
label: <TabsLabel name={t('label.sample-data')} />,
|
||||
isHidden: !(
|
||||
tablePermissions.ViewAll ||
|
||||
tablePermissions.ViewBasic ||
|
||||
tablePermissions.ViewSampleData
|
||||
),
|
||||
position: 3,
|
||||
key: EntityTabs.SAMPLE_DATA,
|
||||
},
|
||||
{
|
||||
name: t('label.query-plural'),
|
||||
icon: {
|
||||
alt: 'table_queries',
|
||||
name: 'table_queries',
|
||||
title: 'Table Queries',
|
||||
selectedName: '',
|
||||
},
|
||||
isProtected: false,
|
||||
label: (
|
||||
<TabsLabel
|
||||
count={queryCount}
|
||||
isActive={activeTab === EntityTabs.TABLE_QUERIES}
|
||||
name={t('label.query-plural')}
|
||||
/>
|
||||
),
|
||||
isHidden: !(
|
||||
tablePermissions.ViewAll ||
|
||||
tablePermissions.ViewBasic ||
|
||||
tablePermissions.ViewQueries
|
||||
),
|
||||
position: 4,
|
||||
count: queryCount,
|
||||
key: EntityTabs.TABLE_QUERIES,
|
||||
},
|
||||
{
|
||||
name: t('label.profiler-amp-data-quality'),
|
||||
icon: {
|
||||
alt: 'profiler',
|
||||
name: 'icon-profiler',
|
||||
title: 'Profiler',
|
||||
selectedName: 'icon-profilercolor',
|
||||
},
|
||||
isProtected: false,
|
||||
label: <TabsLabel name={t('label.profiler-amp-data-quality')} />,
|
||||
isHidden: !(
|
||||
tablePermissions.ViewAll ||
|
||||
tablePermissions.ViewBasic ||
|
||||
tablePermissions.ViewDataProfile ||
|
||||
tablePermissions.ViewTests
|
||||
),
|
||||
position: 5,
|
||||
key: EntityTabs.PROFILER,
|
||||
},
|
||||
{
|
||||
name: t('label.lineage'),
|
||||
icon: {
|
||||
alt: 'lineage',
|
||||
name: 'icon-lineage',
|
||||
title: 'Lineage',
|
||||
selectedName: 'icon-lineagecolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 7,
|
||||
label: <TabsLabel name={t('label.lineage')} />,
|
||||
key: EntityTabs.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: t('label.dbt-lowercase'),
|
||||
icon: {
|
||||
alt: 'dbt-model',
|
||||
name: 'dbtmodel-light-grey',
|
||||
title: 'DBT',
|
||||
selectedName: 'dbtmodel-primery',
|
||||
},
|
||||
isProtected: false,
|
||||
isHidden: !dataModel?.sql,
|
||||
position: 8,
|
||||
label: <TabsLabel name={t('label.dbt-lowercase')} />,
|
||||
isHidden: !(dataModel?.sql ?? dataModel?.rawSql),
|
||||
key: EntityTabs.DBT,
|
||||
},
|
||||
{
|
||||
name: t('label.custom-property-plural'),
|
||||
isProtected: false,
|
||||
position: 9,
|
||||
label: <TabsLabel name={t('label.custom-property-plural')} />,
|
||||
key: EntityTabs.CUSTOM_PROPERTIES,
|
||||
},
|
||||
],
|
||||
[tablePermissions, dataModel, feedCount, queryCount]
|
||||
);
|
||||
];
|
||||
|
||||
return allTabs.filter((data) => !data.isHidden);
|
||||
}, [tablePermissions, dataModel, feedCount, queryCount, activeTab]);
|
||||
|
||||
const handleTabChange = (activeKey: string) => {
|
||||
if (activeKey !== activeTab) {
|
||||
if (!isTourPage) {
|
||||
history.push(getTableTabPath(datasetFQN, activeKey));
|
||||
}
|
||||
setActiveTab(activeKey as EntityTabs);
|
||||
}
|
||||
};
|
||||
|
||||
const getFrequentlyJoinedWithTables = (): Array<
|
||||
JoinedWith & { name: string }
|
||||
> => {
|
||||
const { joins } = tableDetails;
|
||||
const tableFQNGrouping = [
|
||||
...(joins?.columnJoins?.flatMap(
|
||||
(cjs) =>
|
||||
@ -384,6 +360,8 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
tableProfile?: TableProfile,
|
||||
numberOfColumns?: number
|
||||
) => {
|
||||
const { columns } = tableDetails;
|
||||
|
||||
if (isTableProfileLoading) {
|
||||
return (
|
||||
<Skeleton active paragraph={{ rows: 1, width: 50 }} title={false} />
|
||||
@ -464,7 +442,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
EntityInfo.COLUMNS,
|
||||
isTableProfileLoading,
|
||||
tableProfile,
|
||||
columns.length
|
||||
tableDetails.columns.length
|
||||
),
|
||||
},
|
||||
{
|
||||
@ -498,7 +476,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
};
|
||||
|
||||
const onColumnsUpdate = async (updateColumns: Table['columns']) => {
|
||||
if (!isEqual(columns, updateColumns)) {
|
||||
if (!isEqual(tableDetails.columns, updateColumns)) {
|
||||
const updatedTableDetails = {
|
||||
...tableDetails,
|
||||
columns: updateColumns,
|
||||
@ -627,7 +605,12 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
pagingObj: Paging,
|
||||
isLoading: boolean
|
||||
) => {
|
||||
if (isElementInView && pagingObj?.after && !isLoading && activeTab === 2) {
|
||||
if (
|
||||
isElementInView &&
|
||||
pagingObj?.after &&
|
||||
!isLoading &&
|
||||
activeTab === EntityTabs.ACTIVITY_FEED
|
||||
) {
|
||||
fetchFeedHandler(
|
||||
pagingObj.after,
|
||||
activityFilter?.feedFilter,
|
||||
@ -649,6 +632,173 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
fetchFeedHandler(undefined, feedType, threadType);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isTourPage) {
|
||||
setActiveTab(AppState.activeTabforTourDatasetPage);
|
||||
} else {
|
||||
setActiveTab(tab);
|
||||
}
|
||||
}, [tab, AppState.activeTabforTourDatasetPage]);
|
||||
|
||||
const tabDetails = useMemo(() => {
|
||||
switch (activeTab) {
|
||||
case EntityTabs.CUSTOM_PROPERTIES:
|
||||
return (
|
||||
<CustomPropertyTable
|
||||
entityDetails={tableDetails as CustomPropertyProps['entityDetails']}
|
||||
entityType={EntityType.TABLE}
|
||||
handleExtensionUpdate={onExtensionUpdate}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditCustomFields
|
||||
}
|
||||
/>
|
||||
);
|
||||
case EntityTabs.DBT:
|
||||
return <DbtTab dataModel={dataModel} />;
|
||||
case EntityTabs.LINEAGE:
|
||||
return (
|
||||
<Card className="card-body-full m-y-md h-70vh" id="lineageDetails">
|
||||
<EntityLineageComponent
|
||||
deleted={tableDetails.deleted}
|
||||
entityType={EntityType.TABLE}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditLineage
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
case EntityTabs.PROFILER:
|
||||
return (
|
||||
<TableProfilerV1
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
permissions={tablePermissions}
|
||||
tableFqn={tableDetails.fullyQualifiedName || ''}
|
||||
/>
|
||||
);
|
||||
case EntityTabs.TABLE_QUERIES:
|
||||
return (
|
||||
<TableQueries
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
tableId={tableDetails.id}
|
||||
/>
|
||||
);
|
||||
case EntityTabs.SAMPLE_DATA:
|
||||
return (
|
||||
<SampleDataTable
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
tableId={tableDetails.id}
|
||||
/>
|
||||
);
|
||||
case EntityTabs.ACTIVITY_FEED:
|
||||
return (
|
||||
<Card className="m-y-md h-min-full">
|
||||
<Row>
|
||||
<Col data-testid="activityfeed" offset={3} span={18}>
|
||||
<ActivityFeedList
|
||||
isEntityFeed
|
||||
withSidePanel
|
||||
deletePostHandler={deletePostHandler}
|
||||
entityName={entityName}
|
||||
feedList={entityThread}
|
||||
isFeedLoading={isEntityThreadLoading}
|
||||
postFeedHandler={postFeedHandler}
|
||||
updateThreadHandler={updateThreadHandler}
|
||||
onFeedFiltersUpdate={handleFeedFilterChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{loader}
|
||||
</Card>
|
||||
);
|
||||
case EntityTabs.SCHEMA:
|
||||
default:
|
||||
return (
|
||||
<Card className="m-y-md h-full">
|
||||
<Row id="schemaDetails">
|
||||
<Col span={17}>
|
||||
<Description
|
||||
description={description}
|
||||
entityFieldTasks={getEntityFieldThreadCounts(
|
||||
EntityField.DESCRIPTION,
|
||||
entityFieldTaskCount
|
||||
)}
|
||||
entityFieldThreads={getEntityFieldThreadCounts(
|
||||
EntityField.DESCRIPTION,
|
||||
entityFieldThreadCount
|
||||
)}
|
||||
entityFqn={datasetFQN}
|
||||
entityName={entityName}
|
||||
entityType={EntityType.TABLE}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditDescription
|
||||
}
|
||||
isEdit={isEdit}
|
||||
isReadOnly={tableDetails.deleted}
|
||||
owner={tableDetails.owner}
|
||||
onCancel={onCancel}
|
||||
onDescriptionEdit={onDescriptionEdit}
|
||||
onDescriptionUpdate={onDescriptionUpdate}
|
||||
onThreadLinkSelect={onThreadLinkSelect}
|
||||
/>
|
||||
</Col>
|
||||
<Col offset={1} span={6}>
|
||||
<div className="global-border rounded-4">
|
||||
<FrequentlyJoinedTables
|
||||
header={t('label.frequently-joined-table-plural')}
|
||||
tableList={getFrequentlyJoinedWithTables()}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col className="m-t-md" span={24}>
|
||||
<SchemaTab
|
||||
columnName={getPartialNameFromTableFQN(
|
||||
datasetFQN,
|
||||
[FqnPart['Column']],
|
||||
FQN_SEPARATOR_CHAR
|
||||
)}
|
||||
columns={tableDetails.columns}
|
||||
entityFieldTasks={getEntityFieldThreadCounts(
|
||||
EntityField.COLUMNS,
|
||||
entityFieldTaskCount
|
||||
)}
|
||||
entityFieldThreads={getEntityFieldThreadCounts(
|
||||
EntityField.COLUMNS,
|
||||
entityFieldThreadCount
|
||||
)}
|
||||
entityFqn={datasetFQN}
|
||||
hasDescriptionEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditDescription
|
||||
}
|
||||
hasTagEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditTags
|
||||
}
|
||||
isReadOnly={tableDetails.deleted}
|
||||
joins={tableDetails.joins?.columnJoins || []}
|
||||
tableConstraints={tableDetails.tableConstraints}
|
||||
onThreadLinkSelect={onThreadLinkSelect}
|
||||
onUpdate={onColumnsUpdate}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}, [
|
||||
activeTab,
|
||||
tableDetails,
|
||||
tablePermissions,
|
||||
entityFieldThreadCount,
|
||||
entityFieldTaskCount,
|
||||
isEdit,
|
||||
entityName,
|
||||
datasetFQN,
|
||||
description,
|
||||
entityThread,
|
||||
isEntityThreadLoading,
|
||||
dataModel,
|
||||
]);
|
||||
|
||||
return (
|
||||
<PageContainerV1>
|
||||
<PageLayoutV1
|
||||
@ -658,7 +808,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
<EntityPageInfo
|
||||
canDelete={tablePermissions.Delete}
|
||||
currentOwner={tableDetails.owner}
|
||||
deleted={deleted}
|
||||
deleted={tableDetails.deleted}
|
||||
displayName={tableDetails.displayName}
|
||||
entityFieldTasks={getEntityFieldThreadCounts(
|
||||
EntityField.TAGS,
|
||||
@ -706,11 +856,11 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
/>
|
||||
|
||||
<div className="m-t-md">
|
||||
<TabsPane
|
||||
activeTab={activeTab}
|
||||
className="flex-initial"
|
||||
setActiveTab={setActiveTabHandler}
|
||||
tabs={tabs}
|
||||
<Tabs
|
||||
activeKey={activeTab ?? EntityTabs.SCHEMA}
|
||||
data-testid="tabs"
|
||||
items={tabs}
|
||||
onChange={handleTabChange}
|
||||
/>
|
||||
<div
|
||||
className={classNames(
|
||||
@ -719,149 +869,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
|
||||
isTourPage ? 'h-70vh overflow-hidden' : 'h-full'
|
||||
)}
|
||||
id="tab-details">
|
||||
{activeTab === 1 && (
|
||||
<Card className="m-y-md h-full">
|
||||
<Row id="schemaDetails">
|
||||
<Col span={17}>
|
||||
<Description
|
||||
description={description}
|
||||
entityFieldTasks={getEntityFieldThreadCounts(
|
||||
EntityField.DESCRIPTION,
|
||||
entityFieldTaskCount
|
||||
)}
|
||||
entityFieldThreads={getEntityFieldThreadCounts(
|
||||
EntityField.DESCRIPTION,
|
||||
entityFieldThreadCount
|
||||
)}
|
||||
entityFqn={datasetFQN}
|
||||
entityName={entityName}
|
||||
entityType={EntityType.TABLE}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll ||
|
||||
tablePermissions.EditDescription
|
||||
}
|
||||
isEdit={isEdit}
|
||||
isReadOnly={deleted}
|
||||
owner={owner}
|
||||
onCancel={onCancel}
|
||||
onDescriptionEdit={onDescriptionEdit}
|
||||
onDescriptionUpdate={onDescriptionUpdate}
|
||||
onThreadLinkSelect={onThreadLinkSelect}
|
||||
/>
|
||||
</Col>
|
||||
<Col offset={1} span={6}>
|
||||
<div className="global-border rounded-4">
|
||||
<FrequentlyJoinedTables
|
||||
header={t('label.frequently-joined-table-plural')}
|
||||
tableList={getFrequentlyJoinedWithTables()}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col className="m-t-md" span={24}>
|
||||
<SchemaTab
|
||||
columnName={getPartialNameFromTableFQN(
|
||||
datasetFQN,
|
||||
[FqnPart['Column']],
|
||||
FQN_SEPARATOR_CHAR
|
||||
)}
|
||||
columns={columns}
|
||||
entityFieldTasks={getEntityFieldThreadCounts(
|
||||
EntityField.COLUMNS,
|
||||
entityFieldTaskCount
|
||||
)}
|
||||
entityFieldThreads={getEntityFieldThreadCounts(
|
||||
EntityField.COLUMNS,
|
||||
entityFieldThreadCount
|
||||
)}
|
||||
entityFqn={datasetFQN}
|
||||
hasDescriptionEditAccess={
|
||||
tablePermissions.EditAll ||
|
||||
tablePermissions.EditDescription
|
||||
}
|
||||
hasTagEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditTags
|
||||
}
|
||||
isReadOnly={deleted}
|
||||
joins={joins?.columnJoins || []}
|
||||
tableConstraints={tableDetails.tableConstraints}
|
||||
onThreadLinkSelect={onThreadLinkSelect}
|
||||
onUpdate={onColumnsUpdate}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
)}
|
||||
{activeTab === 2 && (
|
||||
<Card className="m-y-md h-min-full">
|
||||
<Row>
|
||||
<Col data-testid="activityfeed" offset={3} span={18}>
|
||||
<ActivityFeedList
|
||||
isEntityFeed
|
||||
withSidePanel
|
||||
className=""
|
||||
deletePostHandler={deletePostHandler}
|
||||
entityName={entityName}
|
||||
feedList={entityThread}
|
||||
isFeedLoading={isEntityThreadLoading}
|
||||
postFeedHandler={postFeedHandler}
|
||||
updateThreadHandler={updateThreadHandler}
|
||||
onFeedFiltersUpdate={handleFeedFilterChange}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{loader}
|
||||
</Card>
|
||||
)}
|
||||
{activeTab === 3 && (
|
||||
<SampleDataTable
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
tableId={tableDetails.id}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 4 && (
|
||||
<TableQueries
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
tableId={tableDetails.id}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 5 && (
|
||||
<TableProfilerV1
|
||||
isTableDeleted={tableDetails.deleted}
|
||||
permissions={tablePermissions}
|
||||
tableFqn={tableDetails.fullyQualifiedName || ''}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === 7 && (
|
||||
<Card
|
||||
className="card-body-full m-y-md h-70vh"
|
||||
id="lineageDetails">
|
||||
<EntityLineageComponent
|
||||
deleted={deleted}
|
||||
entityType={EntityType.TABLE}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditLineage
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
{activeTab === 8 &&
|
||||
Boolean(dataModel?.sql || dataModel?.rawSql) && (
|
||||
<DbtTab dataModel={dataModel} />
|
||||
)}
|
||||
{activeTab === 9 && (
|
||||
<CustomPropertyTable
|
||||
entityDetails={
|
||||
tableDetails as CustomPropertyProps['entityDetails']
|
||||
}
|
||||
entityType={EntityType.TABLE}
|
||||
handleExtensionUpdate={onExtensionUpdate}
|
||||
hasEditAccess={
|
||||
tablePermissions.EditAll || tablePermissions.EditCustomFields
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{tabDetails}
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
import { FeedFilter } from '../../enums/mydata.enum';
|
||||
import { CreateThread } from '../../generated/api/feed/createThread';
|
||||
import { Table, TableData } from '../../generated/entity/data/table';
|
||||
import { Table } from '../../generated/entity/data/table';
|
||||
import { Thread, ThreadType } from '../../generated/entity/feed/thread';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
import {
|
||||
@ -24,21 +24,16 @@ import {
|
||||
export interface DatasetDetailsProps {
|
||||
entityId?: string;
|
||||
tableDetails: Table;
|
||||
datasetFQN: string;
|
||||
dataModel?: Table['dataModel'];
|
||||
activeTab: number;
|
||||
tableProfile: Table['profile'];
|
||||
sampleData: TableData;
|
||||
entityThread: Thread[];
|
||||
isTableProfileLoading?: boolean;
|
||||
isSampleDataLoading?: boolean;
|
||||
isEntityThreadLoading: boolean;
|
||||
feedCount: number;
|
||||
entityFieldThreadCount: EntityFieldThreadCount[];
|
||||
entityFieldTaskCount: EntityFieldThreadCount[];
|
||||
paging: Paging;
|
||||
createThread: (data: CreateThread) => void;
|
||||
setActiveTabHandler: (value: number) => void;
|
||||
followTableHandler: () => void;
|
||||
unfollowTableHandler: () => void;
|
||||
versionHandler: () => void;
|
||||
|
||||
@ -15,12 +15,13 @@ import {
|
||||
findByTestId,
|
||||
findByText,
|
||||
getByTestId,
|
||||
queryByTestId,
|
||||
queryByText,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Table } from '../../generated/entity/data/table';
|
||||
import { ModelType, Table } from '../../generated/entity/data/table';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
import DatasetDetails from './DatasetDetails.component';
|
||||
import { DatasetDetailsProps } from './DatasetDetails.interface';
|
||||
@ -86,11 +87,7 @@ const mockThreads = [
|
||||
];
|
||||
|
||||
const datasetDetailsProps: DatasetDetailsProps = {
|
||||
activeTab: 1,
|
||||
datasetFQN: '',
|
||||
followTableHandler: jest.fn(),
|
||||
sampleData: {},
|
||||
setActiveTabHandler: jest.fn(),
|
||||
tableDetails: {
|
||||
columns: [],
|
||||
id: '',
|
||||
@ -113,6 +110,21 @@ const datasetDetailsProps: DatasetDetailsProps = {
|
||||
onTableUpdate: jest.fn(),
|
||||
};
|
||||
|
||||
const mockParams = {
|
||||
datasetFQN: 'test',
|
||||
tab: EntityTabs.SCHEMA,
|
||||
};
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
useHistory: jest.fn(),
|
||||
useLocation: jest.fn().mockReturnValue({ pathname: 'table' }),
|
||||
useParams: jest.fn().mockImplementation(() => mockParams),
|
||||
}));
|
||||
|
||||
jest.mock('../containers/PageContainerV1', () => {
|
||||
return jest.fn().mockImplementation(({ children }) => <div>{children}</div>);
|
||||
});
|
||||
|
||||
jest.mock('../EntityLineage/EntityLineage.component', () => {
|
||||
return jest.fn().mockReturnValue(<p data-testid="lineage">Lineage</p>);
|
||||
});
|
||||
@ -159,6 +171,9 @@ jest.mock('../SampleDataTable/SampleDataTable.component', () => {
|
||||
.fn()
|
||||
.mockReturnValue(<p data-testid="sample-data">Sample Data</p>);
|
||||
});
|
||||
jest.mock('./DbtTab/DbtTab.component', () => {
|
||||
return jest.fn().mockReturnValue(<div>DbtTab.component</div>);
|
||||
});
|
||||
|
||||
jest.mock('../../utils/CommonUtils', () => ({
|
||||
addToRecentViewed: jest.fn(),
|
||||
@ -240,19 +255,19 @@ describe('Test MyDataDetailsPage page', () => {
|
||||
const EntityPageInfo = await findByText(container, /EntityPageInfo/i);
|
||||
const description = await findByText(container, /Description/i);
|
||||
const tabs = await findByTestId(container, 'tabs');
|
||||
const schemaTab = await findByTestId(tabs, 'label.schema');
|
||||
const activityFeedTab = await findByTestId(
|
||||
const schemaTab = await findByText(tabs, 'label.schema');
|
||||
const activityFeedTab = await findByText(
|
||||
tabs,
|
||||
'label.activity-feed-and-task-plural'
|
||||
);
|
||||
const sampleDataTab = await findByTestId(tabs, 'label.sample-data');
|
||||
const queriesTab = await findByTestId(tabs, 'label.query-plural');
|
||||
const profilerTab = await findByTestId(
|
||||
const sampleDataTab = await findByText(tabs, 'label.sample-data');
|
||||
const queriesTab = await findByText(tabs, 'label.query-plural');
|
||||
const profilerTab = await findByText(
|
||||
tabs,
|
||||
'label.profiler-amp-data-quality'
|
||||
);
|
||||
const lineageTab = await findByTestId(tabs, 'label.lineage');
|
||||
const dbtTab = queryByTestId(tabs, 'DBT');
|
||||
const lineageTab = await findByText(tabs, 'label.lineage');
|
||||
const dbtTab = queryByText(tabs, 'label.dbt-lowercase');
|
||||
|
||||
expect(relatedTables).toBeInTheDocument();
|
||||
expect(EntityPageInfo).toBeInTheDocument();
|
||||
@ -277,72 +292,60 @@ describe('Test MyDataDetailsPage page', () => {
|
||||
});
|
||||
|
||||
it('Check if active tab is activity feed', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={2} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.ACTIVITY_FEED;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const activityFeedList = await findByText(container, /ActivityFeedList/i);
|
||||
|
||||
expect(activityFeedList).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is sample data', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={3} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.SAMPLE_DATA;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const sampleData = await findByTestId(container, 'sample-data');
|
||||
|
||||
expect(sampleData).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is queries', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={4} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.TABLE_QUERIES;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const tableQueries = await findByText(container, 'TableQueries');
|
||||
|
||||
expect(tableQueries).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is profiler', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={5} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.PROFILER;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const tableProfiler = await findByTestId(container, 'TableProfiler');
|
||||
|
||||
expect(tableProfiler).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is lineage', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={7} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.LINEAGE;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const lineage = await findByTestId(container, 'lineage');
|
||||
|
||||
expect(lineage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is custom properties', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={9} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
mockParams.tab = EntityTabs.CUSTOM_PROPERTIES;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const customProperties = await findByText(
|
||||
container,
|
||||
'CustomPropertyTable.component'
|
||||
@ -351,13 +354,27 @@ describe('Test MyDataDetailsPage page', () => {
|
||||
expect(customProperties).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
it('Check if active tab is dbt', async () => {
|
||||
mockParams.tab = EntityTabs.DBT;
|
||||
const { container } = render(
|
||||
<DatasetDetails {...datasetDetailsProps} activeTab={2} />,
|
||||
<DatasetDetails
|
||||
{...datasetDetailsProps}
|
||||
dataModel={{ sql: 'select * from table', modelType: ModelType.Dbt }}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const dbtComponent = await findByText(container, 'DbtTab.component');
|
||||
|
||||
expect(dbtComponent).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should create an observer if IntersectionObserver is available', async () => {
|
||||
mockParams.tab = EntityTabs.ACTIVITY_FEED;
|
||||
const { container } = render(<DatasetDetails {...datasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const obServerElement = await findByTestId(container, 'observer-element');
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card } from 'antd';
|
||||
import { Card, Tabs } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
@ -22,7 +22,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { getEntityName } from 'utils/EntityUtils';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
|
||||
import { EntityField } from '../../constants/Feeds.constants';
|
||||
import { FqnPart } from '../../enums/entity.enum';
|
||||
import { EntityTabs, FqnPart } from '../../enums/entity.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import {
|
||||
ChangeDescription,
|
||||
@ -41,7 +41,6 @@ import {
|
||||
import { TagLabelWithStatus } from '../../utils/EntityVersionUtils.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import VersionTable from '../VersionTable/VersionTable.component';
|
||||
@ -359,15 +358,8 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.schema'),
|
||||
icon: {
|
||||
alt: 'schema',
|
||||
name: 'icon-schema',
|
||||
title: 'Schema',
|
||||
selectedName: 'icon-schemacolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.schema'),
|
||||
key: EntityTabs.SCHEMA,
|
||||
},
|
||||
];
|
||||
|
||||
@ -402,7 +394,7 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.SCHEMA} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Col, Divider, Row, Space, Typography } from 'antd';
|
||||
import { Card, Col, Divider, Row, Space, Tabs, Typography } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer';
|
||||
@ -19,6 +19,7 @@ import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import SourceList from 'components/MlModelDetail/SourceList.component';
|
||||
import TagsViewer from 'components/Tag/TagsViewer/tags-viewer';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { MlFeature, Mlmodel } from 'generated/entity/data/mlmodel';
|
||||
import { cloneDeep, isEqual, isUndefined } from 'lodash';
|
||||
import { ExtraInfo } from 'Models';
|
||||
@ -44,7 +45,6 @@ import {
|
||||
import { TagLabelWithStatus } from '../../utils/EntityVersionUtils.interface';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import { MlModelVersionProp } from './MlModelVersion.interface';
|
||||
@ -68,15 +68,8 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
|
||||
);
|
||||
const tabs = [
|
||||
{
|
||||
name: 'Features',
|
||||
icon: {
|
||||
alt: t('label.feature-plural'),
|
||||
name: 'icon-schema',
|
||||
title: t('label.feature-plural'),
|
||||
selectedName: 'icon-schemacolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.feature-plural'),
|
||||
key: EntityTabs.FEATURES,
|
||||
},
|
||||
];
|
||||
|
||||
@ -368,7 +361,7 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="m-t-xss">
|
||||
<TabsPane activeTab={1} tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.FEATURES} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<Description
|
||||
isReadOnly
|
||||
|
||||
@ -11,12 +11,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card, Space, Table } from 'antd';
|
||||
import { Card, Space, Table, Tabs } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import TagsViewer from 'components/Tag/TagsViewer/tags-viewer';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { t } from 'i18next';
|
||||
import { ColumnDiffProps } from 'interface/EntityVersion.interface';
|
||||
import { cloneDeep, isEqual, isUndefined } from 'lodash';
|
||||
@ -48,7 +49,6 @@ import SVGIcons from '../../utils/SvgUtils';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPreviewer';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import { PipelineVersionProp } from './PipelineVersion.interface';
|
||||
@ -79,15 +79,8 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.detail-plural'),
|
||||
icon: {
|
||||
alt: 'schema',
|
||||
name: 'icon-schema',
|
||||
title: 'Details',
|
||||
selectedName: 'icon-schemacolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.task-plural'),
|
||||
key: EntityTabs.TASKS,
|
||||
},
|
||||
];
|
||||
|
||||
@ -484,7 +477,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.TASKS} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 { Space } from 'antd';
|
||||
import React from 'react';
|
||||
import { getCountBadge } from 'utils/CommonUtils';
|
||||
import { TabsLabelProps } from './TabsLabel.interface';
|
||||
|
||||
const TabsLabel = ({ name, count, isActive }: TabsLabelProps) => {
|
||||
return (
|
||||
<Space className="w-full" data-testid={name}>
|
||||
{name}
|
||||
{count && (
|
||||
<span className="p-l-xs" data-testid="count">
|
||||
{getCountBadge(count, '', isActive)}
|
||||
</span>
|
||||
)}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
export default TabsLabel;
|
||||
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
export interface TabsLabelProps {
|
||||
name: string;
|
||||
count?: number;
|
||||
isActive?: boolean;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import TabsLabel from './TabsLabel.component';
|
||||
import { TabsLabelProps } from './TabsLabel.interface';
|
||||
|
||||
const mockProps: TabsLabelProps = {
|
||||
name: 'Test tab',
|
||||
};
|
||||
|
||||
describe('TabsLabel component', () => {
|
||||
it('Component should render', async () => {
|
||||
render(<TabsLabel {...mockProps} />);
|
||||
|
||||
expect(await screen.findByText(mockProps.name)).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('count')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Count should be visible if provided', async () => {
|
||||
render(<TabsLabel {...mockProps} count={3} />);
|
||||
const count = await screen.findByTestId('count');
|
||||
|
||||
expect(count).toBeVisible();
|
||||
expect(count.textContent).toStrictEqual('3');
|
||||
});
|
||||
});
|
||||
@ -11,10 +11,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Card } from 'antd';
|
||||
import { Card, Tabs } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||
import PageLayoutV1 from 'components/containers/PageLayoutV1';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { isUndefined } from 'lodash';
|
||||
import { ExtraInfo } from 'Models';
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
@ -35,7 +36,6 @@ import { TagLabelWithStatus } from '../../utils/EntityVersionUtils.interface';
|
||||
import { bytesToSize } from '../../utils/StringsUtils';
|
||||
import Description from '../common/description/Description';
|
||||
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import EntityVersionTimeLine from '../EntityVersionTimeLine/EntityVersionTimeLine';
|
||||
import Loader from '../Loader/Loader';
|
||||
import SchemaEditor from '../schema-editor/SchemaEditor';
|
||||
@ -59,15 +59,8 @@ const TopicVersion: FC<TopicVersionProp> = ({
|
||||
);
|
||||
const tabs = [
|
||||
{
|
||||
name: t('label.schema'),
|
||||
icon: {
|
||||
alt: 'schema',
|
||||
name: 'icon-schema',
|
||||
title: 'Schema',
|
||||
selectedName: 'icon-schemacolor',
|
||||
},
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
label: t('label.schema'),
|
||||
key: EntityTabs.SCHEMA,
|
||||
},
|
||||
];
|
||||
|
||||
@ -285,7 +278,7 @@ const TopicVersion: FC<TopicVersionProp> = ({
|
||||
versionHandler={backHandler}
|
||||
/>
|
||||
<div className="tw-mt-1 d-flex flex-col flex-grow ">
|
||||
<TabsPane activeTab={1} className="flex-initial" tabs={tabs} />
|
||||
<Tabs activeKey={EntityTabs.SCHEMA} items={tabs} />
|
||||
<Card className="m-y-md">
|
||||
<div className="tw-grid tw-grid-cols-4 tw-gap-4 tw-w-full">
|
||||
<div className="tw-col-span-full">
|
||||
|
||||
@ -129,3 +129,17 @@ export enum EntityInfo {
|
||||
DATA_MODEL_TYPE = 'data-model-type',
|
||||
QUERIES = 'queries',
|
||||
}
|
||||
|
||||
export enum EntityTabs {
|
||||
SCHEMA = 'schema',
|
||||
ACTIVITY_FEED = 'activity_feed',
|
||||
SAMPLE_DATA = 'sample_data',
|
||||
TABLE_QUERIES = 'table_queries',
|
||||
PROFILER = 'profiler',
|
||||
LINEAGE = 'lineage',
|
||||
DBT = 'dbt',
|
||||
CUSTOM_PROPERTIES = 'custom_properties',
|
||||
MODEL = 'model',
|
||||
FEATURES = 'Features',
|
||||
TASKS = 'Tasks',
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import {
|
||||
} from 'components/PermissionProvider/PermissionProvider.interface';
|
||||
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
|
||||
import { compare, Operation } from 'fast-json-patch';
|
||||
import { isEmpty, isUndefined } from 'lodash';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
@ -41,16 +41,11 @@ import {
|
||||
removeFollower,
|
||||
} from 'rest/tableAPI';
|
||||
import AppState from '../../AppState';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
|
||||
import {
|
||||
getTableTabPath,
|
||||
getVersionPath,
|
||||
pagingObject,
|
||||
} from '../../constants/constants';
|
||||
import { EntityType, FqnPart, TabSpecificField } from '../../enums/entity.enum';
|
||||
import { getVersionPath, pagingObject } from '../../constants/constants';
|
||||
import { EntityTabs, EntityType } from '../../enums/entity.enum';
|
||||
import { FeedFilter } from '../../enums/mydata.enum';
|
||||
import { CreateThread } from '../../generated/api/feed/createThread';
|
||||
import { Table, TableData } from '../../generated/entity/data/table';
|
||||
import { Table } from '../../generated/entity/data/table';
|
||||
import { Post, Thread, ThreadType } from '../../generated/entity/feed/thread';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
import { EntityFieldThreadCount } from '../../interface/feed.interface';
|
||||
@ -59,15 +54,9 @@ import {
|
||||
getCurrentUserId,
|
||||
getEntityMissingError,
|
||||
getFeedCounts,
|
||||
getFields,
|
||||
getPartialNameFromTableFQN,
|
||||
sortTagsCaseInsensitive,
|
||||
} from '../../utils/CommonUtils';
|
||||
import {
|
||||
datasetTableTabs,
|
||||
defaultFields,
|
||||
getCurrentDatasetTab,
|
||||
} from '../../utils/DatasetDetailsUtils';
|
||||
import { defaultFields } from '../../utils/DatasetDetailsUtils';
|
||||
import { getEntityFeedLink, getEntityName } from '../../utils/EntityUtils';
|
||||
import { deletePost, updateThreadData } from '../../utils/FeedUtils';
|
||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||
@ -76,30 +65,17 @@ import { showErrorToast } from '../../utils/ToastUtils';
|
||||
const DatasetDetailsPage: FunctionComponent = () => {
|
||||
const history = useHistory();
|
||||
const { t } = useTranslation();
|
||||
const { datasetFQN, tab } =
|
||||
useParams<{ datasetFQN: string; tab: EntityTabs }>();
|
||||
const { getEntityPermissionByFqn } = usePermissionProvider();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [isSampleDataLoading, setIsSampleDataLoading] =
|
||||
useState<boolean>(false);
|
||||
const [isEntityThreadLoading, setIsEntityThreadLoading] =
|
||||
useState<boolean>(false);
|
||||
const [isTableProfileLoading, setIsTableProfileLoading] =
|
||||
useState<boolean>(false);
|
||||
const USERId = getCurrentUserId();
|
||||
const [sampleData, setSampleData] = useState<TableData>({
|
||||
columns: [],
|
||||
rows: [],
|
||||
});
|
||||
const [tableProfile, setTableProfile] = useState<Table['profile']>();
|
||||
const [tableDetails, setTableDetails] = useState<Table>({} as Table);
|
||||
const { datasetFQN, tab } = useParams() as Record<string, string>;
|
||||
const [activeTab, setActiveTab] = useState<number>(getCurrentDatasetTab(tab));
|
||||
const [tableFQN, setTableFQN] = useState<string>(
|
||||
getPartialNameFromTableFQN(
|
||||
datasetFQN,
|
||||
[FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table],
|
||||
FQN_SEPARATOR_CHAR
|
||||
)
|
||||
);
|
||||
const [isError, setIsError] = useState(false);
|
||||
const [entityThread, setEntityThread] = useState<Thread[]>([]);
|
||||
|
||||
@ -119,21 +95,6 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
|
||||
const { id: tableId, followers, version: currentVersion = '' } = tableDetails;
|
||||
|
||||
const activeTabHandler = (tabValue: number) => {
|
||||
const currentTabIndex = tabValue - 1;
|
||||
if (datasetTableTabs[currentTabIndex].path !== tab) {
|
||||
setActiveTab(
|
||||
getCurrentDatasetTab(datasetTableTabs[currentTabIndex].path)
|
||||
);
|
||||
history.push({
|
||||
pathname: getTableTabPath(
|
||||
tableFQN,
|
||||
datasetTableTabs[currentTabIndex].path
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getFeedData = async (
|
||||
after?: string,
|
||||
feedType?: FeedFilter,
|
||||
@ -142,7 +103,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
setIsEntityThreadLoading(true);
|
||||
try {
|
||||
const { data, paging: pagingObj } = await getAllFeeds(
|
||||
getEntityFeedLink(EntityType.TABLE, tableFQN),
|
||||
getEntityFeedLink(EntityType.TABLE, datasetFQN),
|
||||
after,
|
||||
threadType,
|
||||
feedType,
|
||||
@ -194,10 +155,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const res = await getTableDetailsByFQN(
|
||||
tableFQN,
|
||||
getFields(defaultFields, datasetTableTabs[activeTab - 1].field ?? '')
|
||||
);
|
||||
const res = await getTableDetailsByFQN(datasetFQN, defaultFields);
|
||||
|
||||
const { id, fullyQualifiedName, serviceType } = res;
|
||||
setTableDetails(res);
|
||||
@ -218,7 +176,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
error as AxiosError,
|
||||
t('server.entity-details-fetch-error', {
|
||||
entityType: t('label.pipeline'),
|
||||
entityName: tableFQN,
|
||||
entityName: datasetFQN,
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -250,60 +208,16 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTabSpecificData = async (tabField = '') => {
|
||||
switch (tabField) {
|
||||
case TabSpecificField.SAMPLE_DATA: {
|
||||
if (!isUndefined(sampleData)) {
|
||||
break;
|
||||
} else {
|
||||
setIsSampleDataLoading(true);
|
||||
|
||||
try {
|
||||
const res = await getTableDetailsByFQN(tableFQN, tabField);
|
||||
const { sampleData } = res;
|
||||
setSampleData(sampleData as TableData);
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
t('server.entity-details-fetch-error', {
|
||||
entityType: t('label.table'),
|
||||
entityName: datasetFQN,
|
||||
})
|
||||
);
|
||||
} finally {
|
||||
setIsSampleDataLoading(false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case TabSpecificField.ACTIVITY_FEED: {
|
||||
getFeedData();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (datasetTableTabs[activeTab - 1].path !== tab) {
|
||||
setActiveTab(getCurrentDatasetTab(tab));
|
||||
if (EntityTabs.ACTIVITY_FEED === tab) {
|
||||
getFeedData();
|
||||
}
|
||||
setEntityThread([]);
|
||||
}, [tab]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTabSpecificData(datasetTableTabs[activeTab - 1].field);
|
||||
}, [activeTab, feedCount]);
|
||||
}, [tab, feedCount]);
|
||||
|
||||
const getEntityFeedCount = () => {
|
||||
getFeedCounts(
|
||||
EntityType.TABLE,
|
||||
tableFQN,
|
||||
datasetFQN,
|
||||
setEntityFieldThreadCount,
|
||||
setEntityFieldTaskCount,
|
||||
setFeedCount
|
||||
@ -384,7 +298,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
|
||||
const versionHandler = () => {
|
||||
history.push(
|
||||
getVersionPath(EntityType.TABLE, tableFQN, currentVersion as string)
|
||||
getVersionPath(EntityType.TABLE, datasetFQN, currentVersion as string)
|
||||
);
|
||||
};
|
||||
|
||||
@ -454,7 +368,6 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
useEffect(() => {
|
||||
if (tablePermissions.ViewAll || tablePermissions.ViewBasic) {
|
||||
fetchTableDetail();
|
||||
setActiveTab(getCurrentDatasetTab(tab));
|
||||
getEntityFeedCount();
|
||||
}
|
||||
}, [tablePermissions]);
|
||||
@ -464,17 +377,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
}, [tableDetails]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchResourcePermission(tableFQN);
|
||||
}, [tableFQN]);
|
||||
|
||||
useEffect(() => {
|
||||
setTableFQN(
|
||||
getPartialNameFromTableFQN(
|
||||
datasetFQN,
|
||||
[FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table],
|
||||
FQN_SEPARATOR_CHAR
|
||||
)
|
||||
);
|
||||
fetchResourcePermission(datasetFQN);
|
||||
}, [datasetFQN]);
|
||||
|
||||
if (isLoading) {
|
||||
@ -483,7 +386,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
if (isError) {
|
||||
return (
|
||||
<ErrorPlaceHolder>
|
||||
{getEntityMissingError('table', tableFQN)}
|
||||
{getEntityMissingError('table', datasetFQN)}
|
||||
</ErrorPlaceHolder>
|
||||
);
|
||||
}
|
||||
@ -494,10 +397,8 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
|
||||
return (
|
||||
<DatasetDetails
|
||||
activeTab={activeTab}
|
||||
createThread={createThread}
|
||||
dataModel={tableDetails.dataModel}
|
||||
datasetFQN={tableFQN}
|
||||
deletePostHandler={deletePostHandler}
|
||||
entityFieldTaskCount={entityFieldTaskCount}
|
||||
entityFieldThreadCount={entityFieldThreadCount}
|
||||
@ -506,12 +407,9 @@ const DatasetDetailsPage: FunctionComponent = () => {
|
||||
fetchFeedHandler={handleFeedFetchFromFeedList}
|
||||
followTableHandler={followTable}
|
||||
isEntityThreadLoading={isEntityThreadLoading}
|
||||
isSampleDataLoading={isSampleDataLoading}
|
||||
isTableProfileLoading={isTableProfileLoading}
|
||||
paging={paging}
|
||||
postFeedHandler={postFeedHandler}
|
||||
sampleData={sampleData}
|
||||
setActiveTabHandler={activeTabHandler}
|
||||
tableDetails={tableDetails}
|
||||
tableProfile={tableProfile}
|
||||
unfollowTableHandler={unFollowTable}
|
||||
|
||||
@ -130,7 +130,6 @@ jest.mock('components/DatasetDetails/DatasetDetails.component', () => {
|
||||
handleAddColumnTestCase,
|
||||
handleTestModeChange,
|
||||
handleShowTestForm,
|
||||
setActiveTabHandler,
|
||||
qualityTestFormHandler,
|
||||
settingsUpdateHandler,
|
||||
loadNodeHandler,
|
||||
@ -180,11 +179,6 @@ jest.mock('components/DatasetDetails/DatasetDetails.component', () => {
|
||||
onClick={handleAddColumnTestCase}>
|
||||
add column test
|
||||
</button>
|
||||
<button
|
||||
data-testid="change-tab"
|
||||
onClick={() => setActiveTabHandler(2)}>
|
||||
change tab
|
||||
</button>
|
||||
<button
|
||||
data-testid="qualityTestFormHandler"
|
||||
onClick={() => qualityTestFormHandler(6, 'table', 'test')}>
|
||||
@ -382,7 +376,6 @@ describe('Test DatasetDetails page', () => {
|
||||
const testForm = await screen.findByTestId('test-form');
|
||||
const addTableTest = await screen.findByTestId('add-table-test');
|
||||
const addColumnTest = await screen.findByTestId('add-column-test');
|
||||
const changeTab = await screen.findByTestId('change-tab');
|
||||
const settingsUpdateHandler = await screen.findByTestId(
|
||||
'settingsUpdateHandler'
|
||||
);
|
||||
@ -415,7 +408,6 @@ describe('Test DatasetDetails page', () => {
|
||||
expect(testForm).toBeInTheDocument();
|
||||
expect(addTableTest).toBeInTheDocument();
|
||||
expect(addColumnTest).toBeInTheDocument();
|
||||
expect(changeTab).toBeInTheDocument();
|
||||
expect(settingsUpdateHandler).toBeInTheDocument();
|
||||
expect(loadNodeHandler).toBeInTheDocument();
|
||||
expect(addLineageHandler).toBeInTheDocument();
|
||||
@ -436,7 +428,6 @@ describe('Test DatasetDetails page', () => {
|
||||
fireEvent.click(testForm);
|
||||
fireEvent.click(addTableTest);
|
||||
fireEvent.click(addColumnTest);
|
||||
fireEvent.click(changeTab);
|
||||
fireEvent.click(settingsUpdateHandler);
|
||||
fireEvent.click(loadNodeHandler);
|
||||
fireEvent.click(addLineageHandler);
|
||||
|
||||
@ -18,6 +18,7 @@ import MyData from 'components/MyData/MyData.component';
|
||||
import { MyDataProps } from 'components/MyData/MyData.interface';
|
||||
import NavBar from 'components/nav-bar/NavBar';
|
||||
import Tour from 'components/tour/Tour';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { SearchResponse } from 'interface/search.interface';
|
||||
import { noop } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
@ -60,9 +61,6 @@ const TourPage = () => {
|
||||
AppState.currentTourPage
|
||||
);
|
||||
const [myDataSearchResult, setMyDataSearchResult] = useState(mockFeedData);
|
||||
const [datasetActiveTab, setdatasetActiveTab] = useState(
|
||||
AppState.activeTabforTourDatasetPage
|
||||
);
|
||||
const [explorePageCounts, setExplorePageCounts] = useState(exploreCount);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
|
||||
@ -101,17 +99,13 @@ const TourPage = () => {
|
||||
useEffect(() => {
|
||||
handleIsTourOpen(true);
|
||||
AppState.currentTourPage = CurrentTourPageType.MY_DATA_PAGE;
|
||||
AppState.activeTabforTourDatasetPage = 1;
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.SCHEMA;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentPage(AppState.currentTourPage);
|
||||
}, [AppState.currentTourPage]);
|
||||
|
||||
useEffect(() => {
|
||||
setdatasetActiveTab(AppState.activeTabforTourDatasetPage);
|
||||
}, [AppState.activeTabforTourDatasetPage]);
|
||||
|
||||
const getCurrentPage = (page: CurrentTourPageType) => {
|
||||
switch (page) {
|
||||
case CurrentTourPageType.MY_DATA_PAGE:
|
||||
@ -161,9 +155,7 @@ const TourPage = () => {
|
||||
case CurrentTourPageType.DATASET_PAGE:
|
||||
return (
|
||||
<DatasetDetails
|
||||
activeTab={datasetActiveTab}
|
||||
createThread={handleCountChange}
|
||||
datasetFQN={mockDatasetData.datasetFQN}
|
||||
deletePostHandler={handleCountChange}
|
||||
entityFieldTaskCount={[]}
|
||||
entityFieldThreadCount={[]}
|
||||
@ -174,8 +166,6 @@ const TourPage = () => {
|
||||
isEntityThreadLoading={false}
|
||||
paging={{} as Paging}
|
||||
postFeedHandler={handleCountChange}
|
||||
sampleData={mockDatasetData.sampleData}
|
||||
setActiveTabHandler={(tab) => setdatasetActiveTab(tab)}
|
||||
tableDetails={mockDatasetData.tableDetails as unknown as Table}
|
||||
tableProfile={
|
||||
mockDatasetData.tableProfile as unknown as Table['profile']
|
||||
|
||||
@ -61,7 +61,7 @@ import {
|
||||
validEmailRegEx,
|
||||
} from '../constants/regex.constants';
|
||||
import { SIZE } from '../enums/common.enum';
|
||||
import { EntityType, FqnPart, TabSpecificField } from '../enums/entity.enum';
|
||||
import { EntityType, FqnPart } from '../enums/entity.enum';
|
||||
import { FilterPatternEnum } from '../enums/filterPattern.enum';
|
||||
import { ThreadTaskStatus, ThreadType } from '../generated/entity/feed/thread';
|
||||
import { PipelineType } from '../generated/entity/services/ingestionPipelines/ingestionPipeline';
|
||||
@ -417,23 +417,6 @@ export const isValidEmail = (email?: string) => {
|
||||
return isValid;
|
||||
};
|
||||
|
||||
export const getFields = (defaultFields: string, tabSpecificField: string) => {
|
||||
if (!tabSpecificField) {
|
||||
return defaultFields;
|
||||
}
|
||||
if (!defaultFields) {
|
||||
return tabSpecificField;
|
||||
}
|
||||
if (
|
||||
tabSpecificField === TabSpecificField.LINEAGE ||
|
||||
tabSpecificField === TabSpecificField.ACTIVITY_FEED
|
||||
) {
|
||||
return defaultFields;
|
||||
}
|
||||
|
||||
return `${defaultFields}, ${tabSpecificField}`;
|
||||
};
|
||||
|
||||
export const getEntityMissingError = (entityType: string, fqn: string) => {
|
||||
return (
|
||||
<p>
|
||||
|
||||
@ -11,103 +11,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import i18next from 'i18next';
|
||||
import { TabSpecificField } from '../enums/entity.enum';
|
||||
|
||||
export const defaultFields = `${TabSpecificField.COLUMNS}, ${TabSpecificField.USAGE_SUMMARY},
|
||||
${TabSpecificField.FOLLOWERS}, ${TabSpecificField.JOINS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
|
||||
${TabSpecificField.DATAMODEL},${TabSpecificField.TABLE_CONSTRAINTS},${TabSpecificField.EXTENSION}`;
|
||||
|
||||
export const datasetTableTabs = [
|
||||
{
|
||||
name: i18next.t('label.schema'),
|
||||
path: 'schema',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.activity-feed-and-task-plural'),
|
||||
path: 'activity_feed',
|
||||
field: TabSpecificField.ACTIVITY_FEED,
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.sample-data'),
|
||||
path: 'sample_data',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.query-plural'),
|
||||
path: 'table_queries',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.profiler'),
|
||||
path: 'profiler',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.data-entity', {
|
||||
entity: i18next.t('label.quality'),
|
||||
}),
|
||||
path: 'data-quality',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.lineage'),
|
||||
path: 'lineage',
|
||||
field: TabSpecificField.LINEAGE,
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.dbt-lowercase'),
|
||||
path: 'dbt',
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.custom-property-plural'),
|
||||
path: 'custom_properties',
|
||||
},
|
||||
];
|
||||
|
||||
export const getCurrentDatasetTab = (tab: string) => {
|
||||
let currentTab = 1;
|
||||
switch (tab) {
|
||||
case 'activity_feed':
|
||||
currentTab = 2;
|
||||
|
||||
break;
|
||||
case 'sample_data':
|
||||
currentTab = 3;
|
||||
|
||||
break;
|
||||
case 'table_queries':
|
||||
currentTab = 4;
|
||||
|
||||
break;
|
||||
|
||||
case 'profiler':
|
||||
currentTab = 5;
|
||||
|
||||
break;
|
||||
|
||||
case 'data-quality':
|
||||
currentTab = 6;
|
||||
|
||||
break;
|
||||
|
||||
case 'lineage':
|
||||
currentTab = 7;
|
||||
|
||||
break;
|
||||
|
||||
case 'dbt':
|
||||
currentTab = 8;
|
||||
|
||||
break;
|
||||
|
||||
case 'custom_properties':
|
||||
currentTab = 9;
|
||||
|
||||
break;
|
||||
|
||||
case 'schema':
|
||||
default:
|
||||
currentTab = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return currentTab;
|
||||
};
|
||||
|
||||
@ -11,12 +11,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import i18next from 'i18next';
|
||||
import React from 'react';
|
||||
import AppState from '../AppState';
|
||||
import { CurrentTourPageType } from '../enums/tour.enum';
|
||||
import { Transi18next } from './CommonUtils';
|
||||
import { getCurrentDatasetTab } from './DatasetDetailsUtils';
|
||||
|
||||
export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
return [
|
||||
@ -116,7 +116,7 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
</p>
|
||||
),
|
||||
actionType: 'click',
|
||||
selector: '[data-testid="BigQuery-dim_address"]',
|
||||
selector: '[data-testid="sample_data-dim_address"]',
|
||||
beforeNext: () => {
|
||||
AppState.currentTourPage = CurrentTourPageType.DATASET_PAGE;
|
||||
},
|
||||
@ -186,7 +186,7 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = getCurrentDatasetTab('schema');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.SCHEMA;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
@ -200,10 +200,9 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#sampleData',
|
||||
selector: '[data-testid="Sample Data"]',
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage =
|
||||
getCurrentDatasetTab('sample_data');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.SAMPLE_DATA;
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -218,15 +217,14 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#sampleDataDetails',
|
||||
selector: '#tab-details',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage =
|
||||
getCurrentDatasetTab('sample_data');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.SAMPLE_DATA;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = getCurrentDatasetTab('profiler');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.PROFILER;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
@ -240,7 +238,7 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#profilerDataQuality',
|
||||
selector: '[data-testid="Profiler & Data Quality"]',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
@ -257,14 +255,14 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
selector: '#profilerDetails',
|
||||
selector: '#tab-details',
|
||||
},
|
||||
{
|
||||
beforePrev: () => {
|
||||
AppState.activeTabforTourDatasetPage = getCurrentDatasetTab('profiler');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.PROFILER;
|
||||
},
|
||||
beforeNext: () => {
|
||||
AppState.activeTabforTourDatasetPage = getCurrentDatasetTab('lineage');
|
||||
AppState.activeTabforTourDatasetPage = EntityTabs.LINEAGE;
|
||||
},
|
||||
actionType: 'click',
|
||||
content: () => (
|
||||
@ -278,7 +276,7 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
/>
|
||||
</p>
|
||||
),
|
||||
selector: '#lineage',
|
||||
selector: '[data-testid="Lineage"]',
|
||||
},
|
||||
{
|
||||
content: () => (
|
||||
@ -293,7 +291,7 @@ export const getSteps = (value: string, clearSearchTerm: () => void) => {
|
||||
</p>
|
||||
),
|
||||
stepInteraction: false,
|
||||
selector: '#lineageDetails',
|
||||
selector: '#tab-details',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user