mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-31 20:51:26 +00:00
cleanup in getFormattedEntityData method (#14454)
* cleanup in getFormattedEntityData method * fix failed test after cleanup in entity-summary-panel-utils * added unit test for getMapOfListHighlights method * separate test of different functions in different describe block * in children table constraints will not pass * fix a type issue * children will only return for Column and Field type * cleanup and remove redundancy in mock * added unit test for getHighlightOfListItem method * some cleanup + improve type defination * minor change * some cleanup
This commit is contained in:
parent
e0f16cf39e
commit
d406bf39b8
@ -71,16 +71,10 @@ function ContainerSummary({
|
||||
|
||||
<SummaryTagsDescription
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ?? []
|
||||
}
|
||||
tags={getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)}
|
||||
/>
|
||||
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -112,15 +112,10 @@ function DashboardSummary({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -80,15 +80,10 @@ const DataModelSummary = ({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -54,15 +54,10 @@ const DatabaseSchemaSummary = ({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
|
@ -73,15 +73,10 @@ const DatabaseSummary = ({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
|
@ -82,15 +82,10 @@ function MlModelSummary({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -82,15 +82,10 @@ function PipelineSummary({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -97,15 +97,10 @@ function SearchIndexSummary({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -54,15 +54,10 @@ const ServiceSummary = ({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
|
@ -61,15 +61,10 @@ const StoredProcedureSummary = ({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -22,12 +22,16 @@ import {
|
||||
} from '../../../../generated/entity/data/table';
|
||||
import { TagLabel } from '../../../../generated/type/tagLabel';
|
||||
|
||||
export interface HighlightedTagLabel extends TagLabel {
|
||||
isHighlighted: boolean;
|
||||
}
|
||||
|
||||
export interface BasicEntityInfo {
|
||||
algorithm?: string;
|
||||
name: string;
|
||||
title: ReactNode;
|
||||
type?: DataType | ChartType | FeatureType | string;
|
||||
tags?: TagLabel[];
|
||||
tags?: Array<TagLabel | HighlightedTagLabel>;
|
||||
description?: string;
|
||||
columnConstraint?: Constraint;
|
||||
tableConstraints?: TableConstraint[];
|
||||
|
@ -247,15 +247,10 @@ function TableSummary({
|
||||
entityDetail={tableDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: tableDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
tableDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -167,15 +167,10 @@ function TopicSummary({
|
||||
entityDetail={entityDetails}
|
||||
tags={
|
||||
tags ??
|
||||
getSortedTagsWithHighlight({
|
||||
tags: entityDetails.tags,
|
||||
sortTagsBasedOnGivenTagFQNs: get(
|
||||
highlights,
|
||||
'tag.name',
|
||||
[] as string[]
|
||||
),
|
||||
}) ??
|
||||
[]
|
||||
getSortedTagsWithHighlight(
|
||||
entityDetails.tags,
|
||||
get(highlights, 'tag.name')
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Divider className="m-y-xs" />
|
||||
|
@ -22,11 +22,11 @@ import { ROUTES } from '../../../constants/constants';
|
||||
import { TAG_START_WITH } from '../../../constants/Tag.constants';
|
||||
import { TagSource } from '../../../generated/type/tagLabel';
|
||||
import { reduceColorOpacity } from '../../../utils/CommonUtils';
|
||||
import { HighlightedTagLabel } from '../../../utils/EntitySummaryPanelUtils';
|
||||
import { getEntityName } from '../../../utils/EntityUtils';
|
||||
import Fqn from '../../../utils/Fqn';
|
||||
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
||||
import { getTagDisplay, getTagTooltip } from '../../../utils/TagsUtils';
|
||||
import { HighlightedTagLabel } from '../../Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
import { TagsV1Props } from './TagsV1.interface';
|
||||
import './tagsV1.less';
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
import { TagProps } from 'antd';
|
||||
import { TAG_START_WITH } from '../../../constants/Tag.constants';
|
||||
import { TagLabel, TagSource } from '../../../generated/type/tagLabel';
|
||||
import { HighlightedTagLabel } from '../../../utils/EntitySummaryPanelUtils';
|
||||
import { HighlightedTagLabel } from '../../Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
|
||||
export type TagsV1Props = {
|
||||
tag: TagLabel | HighlightedTagLabel;
|
||||
|
@ -14,15 +14,15 @@ import { Col, Divider, Row, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import TagsViewer from '../../../components/Tag/TagsViewer/TagsViewer';
|
||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||
import { BasicEntityInfo } from '../../Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
import { EntityUnion } from '../../Explore/ExplorePage.interface';
|
||||
import RichTextEditorPreviewer from '../RichTextEditor/RichTextEditorPreviewer';
|
||||
|
||||
const SummaryTagsDescription = ({
|
||||
tags,
|
||||
tags = [],
|
||||
entityDetail,
|
||||
}: {
|
||||
tags: TagLabel[];
|
||||
tags: BasicEntityInfo['tags'];
|
||||
entityDetail: EntityUnion;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
@ -15,6 +15,8 @@ import { SummaryEntityType } from '../enums/EntitySummary.enum';
|
||||
import { Column } from '../generated/entity/data/table';
|
||||
import {
|
||||
getFormattedEntityData,
|
||||
getHighlightOfListItem,
|
||||
getMapOfListHighlights,
|
||||
getSortedTagsWithHighlight,
|
||||
getSummaryListItemType,
|
||||
getTitle,
|
||||
@ -24,87 +26,146 @@ import {
|
||||
mockEntityDataWithNestingResponse,
|
||||
mockEntityDataWithoutNesting,
|
||||
mockEntityDataWithoutNestingResponse,
|
||||
mockGetHighlightOfListItemResponse,
|
||||
mockGetMapOfListHighlightsResponse,
|
||||
mockGetSummaryListItemTypeResponse,
|
||||
mockHighlights,
|
||||
mockInvalidDataResponse,
|
||||
mockLinkBasedSummaryTitleResponse,
|
||||
mockListItemNameHighlight,
|
||||
mockTagFQNsForHighlight,
|
||||
mockTagsDataAfterSortAndHighlight,
|
||||
mockTagsDataBeforeSortAndHighlight,
|
||||
mockTagsSortAndHighlightResponse,
|
||||
mockTextBasedSummaryTitleResponse,
|
||||
} from './mocks/EntitySummaryPanelUtils.mock';
|
||||
|
||||
jest.mock('../constants/EntitySummaryPanelUtils.constant', () => ({
|
||||
...jest.requireActual('../constants/EntitySummaryPanelUtils.constant'),
|
||||
SummaryListHighlightKeys: [
|
||||
'columns.name',
|
||||
'columns.description',
|
||||
'columns.children.name',
|
||||
],
|
||||
}));
|
||||
|
||||
describe('EntitySummaryPanelUtils tests', () => {
|
||||
it('getFormattedEntityData should return formatted data properly for table columns data without nesting, and also sort the data based on given arr', () => {
|
||||
const highlights = {
|
||||
'tag.name': ['PersonalData.SpecialCategory'],
|
||||
};
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.COLUMN,
|
||||
mockEntityDataWithoutNesting,
|
||||
highlights
|
||||
);
|
||||
describe('getFormattedEntityData', () => {
|
||||
it('getFormattedEntityData should return formatted data properly for table columns data with nesting, and also sort the data based on highlights', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.COLUMN,
|
||||
mockEntityDataWithNesting,
|
||||
mockHighlights
|
||||
);
|
||||
|
||||
expect(resultFormattedData).toEqual(mockEntityDataWithoutNestingResponse);
|
||||
});
|
||||
|
||||
it('getFormattedEntityData should return formatted data properly for topic fields data with nesting', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.COLUMN,
|
||||
mockEntityDataWithNesting
|
||||
);
|
||||
|
||||
expect(resultFormattedData).toEqual(mockEntityDataWithNestingResponse);
|
||||
});
|
||||
|
||||
it('getFormattedEntityData should return empty array in case entityType is given other than from type SummaryEntityType', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
'otherType' as SummaryEntityType,
|
||||
mockEntityDataWithNesting
|
||||
);
|
||||
|
||||
expect(resultFormattedData).toEqual([]);
|
||||
});
|
||||
|
||||
it('getFormattedEntityData should not throw error if entityDetails sent does not have fields present', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.COLUMN,
|
||||
[{}] as Column[]
|
||||
);
|
||||
|
||||
expect(resultFormattedData).toEqual(mockInvalidDataResponse);
|
||||
});
|
||||
|
||||
it('getSortedTagsWithHighlight should return the sorted and highlighted tags data based on given tagFQN array', () => {
|
||||
const sortedTags = getSortedTagsWithHighlight({
|
||||
sortTagsBasedOnGivenTagFQNs: mockTagFQNsForHighlight,
|
||||
tags: mockTagsDataBeforeSortAndHighlight,
|
||||
expect(resultFormattedData).toEqual(mockEntityDataWithNestingResponse);
|
||||
});
|
||||
|
||||
expect(sortedTags).toEqual(mockTagsDataAfterSortAndHighlight);
|
||||
});
|
||||
it('getFormattedEntityData should return formatted data properly for pipeline data without nesting', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.TASK,
|
||||
mockEntityDataWithoutNesting
|
||||
);
|
||||
|
||||
it('getSummaryListItemType should return the summary item type based on given entityType', () => {
|
||||
const summaryItemType = getSummaryListItemType(
|
||||
SummaryEntityType.COLUMN,
|
||||
mockEntityDataWithoutNesting[0]
|
||||
);
|
||||
|
||||
expect(summaryItemType).toEqual(mockGetSummaryListItemTypeResponse);
|
||||
});
|
||||
|
||||
it('getTitle should return title as link or text based on sourceUrl present or not in given data', () => {
|
||||
const textBasedTitle = getTitle({
|
||||
content: 'Title1',
|
||||
sourceUrl: undefined,
|
||||
expect(resultFormattedData).toEqual(mockEntityDataWithoutNestingResponse);
|
||||
});
|
||||
|
||||
expect(textBasedTitle).toEqual(mockTextBasedSummaryTitleResponse);
|
||||
it('getFormattedEntityData should return empty array in case entityType is given other than from type SummaryEntityType', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
'otherType' as SummaryEntityType,
|
||||
mockEntityDataWithNesting
|
||||
);
|
||||
|
||||
const linkBasedTitle = getTitle({
|
||||
content: 'Title2',
|
||||
sourceUrl: 'https://task1.com',
|
||||
expect(resultFormattedData).toEqual([]);
|
||||
});
|
||||
|
||||
expect(linkBasedTitle).toEqual(mockLinkBasedSummaryTitleResponse);
|
||||
it('getFormattedEntityData should not throw error if entityDetails sent does not have fields present', () => {
|
||||
const resultFormattedData = getFormattedEntityData(
|
||||
SummaryEntityType.COLUMN,
|
||||
[{}] as Column[]
|
||||
);
|
||||
|
||||
expect(resultFormattedData).toEqual(mockInvalidDataResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSortedTagsWithHighlight', () => {
|
||||
it('getSortedTagsWithHighlight should return the sorted and highlighted tags data based on given tagFQN array', () => {
|
||||
const sortedTags = getSortedTagsWithHighlight(
|
||||
mockEntityDataWithNesting[2].tags,
|
||||
mockTagFQNsForHighlight
|
||||
);
|
||||
|
||||
expect(sortedTags).toEqual(mockTagsSortAndHighlightResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSummaryListItemType', () => {
|
||||
it('getSummaryListItemType should return the summary item type based on given entityType', () => {
|
||||
const summaryItemType = getSummaryListItemType(
|
||||
SummaryEntityType.TASK,
|
||||
mockEntityDataWithoutNesting[0]
|
||||
);
|
||||
|
||||
expect(summaryItemType).toEqual(mockGetSummaryListItemTypeResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTitle', () => {
|
||||
it('getTitle should return title as text if sourceUrl not present in listItem and also apply highlight if present', () => {
|
||||
const textBasedTitle = getTitle(
|
||||
mockEntityDataWithNesting[0],
|
||||
mockListItemNameHighlight
|
||||
);
|
||||
|
||||
expect(textBasedTitle).toEqual(mockTextBasedSummaryTitleResponse);
|
||||
});
|
||||
|
||||
it('getTitle should return title as link if sourceUrl present in listItem', () => {
|
||||
const linkBasedTitle = getTitle(mockEntityDataWithoutNesting[0]);
|
||||
|
||||
expect(linkBasedTitle).toEqual(mockLinkBasedSummaryTitleResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMapOfListHighlights', () => {
|
||||
it('getMapOfListHighlights should returns empty arrays and map when highlights is undefined', () => {
|
||||
const result = getMapOfListHighlights();
|
||||
|
||||
expect(result.listHighlights).toEqual([]);
|
||||
expect(result.listHighlightsMap).toEqual({});
|
||||
});
|
||||
|
||||
it('getMapOfListHighlights should returns listHighlights and listHighlightsMap correctly', () => {
|
||||
const result = getMapOfListHighlights(mockHighlights);
|
||||
|
||||
expect(result).toEqual(mockGetMapOfListHighlightsResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getHighlightOfListItem', () => {
|
||||
it('getHighlightOfListItem should return highlights of listItem undefined, if listHighlights and tagHighlights not passed in params', () => {
|
||||
const result = getHighlightOfListItem(
|
||||
mockEntityDataWithNesting[0],
|
||||
[] as string[],
|
||||
[] as string[],
|
||||
{} as { [key: string]: number }
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
highlightedTags: undefined,
|
||||
highlightedTitle: undefined,
|
||||
highlightedDescription: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('getHighlightOfListItem should return highlights of listItem if listHighlights and tagHighlights get in params', () => {
|
||||
const result = getHighlightOfListItem(
|
||||
mockEntityDataWithNesting[1],
|
||||
mockTagFQNsForHighlight,
|
||||
mockGetMapOfListHighlightsResponse.listHighlights,
|
||||
mockGetMapOfListHighlightsResponse.listHighlightsMap
|
||||
);
|
||||
|
||||
expect(result).toEqual(mockGetHighlightOfListItemResponse);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -17,7 +17,10 @@ import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { SearchedDataProps } from '../../src/components/SearchedData/SearchedData.interface';
|
||||
import { ReactComponent as IconExternalLink } from '../assets/svg/external-links.svg';
|
||||
import { BasicEntityInfo } from '../components/Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
import {
|
||||
BasicEntityInfo,
|
||||
HighlightedTagLabel,
|
||||
} from '../components/Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
import { NO_DATA_PLACEHOLDER } from '../constants/constants';
|
||||
import { SummaryListHighlightKeys } from '../constants/EntitySummaryPanelUtils.constant';
|
||||
import { SummaryEntityType } from '../enums/EntitySummary.enum';
|
||||
@ -37,20 +40,30 @@ export interface EntityNameProps {
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export interface HighlightedTagLabel extends TagLabel {
|
||||
isHighlighted: boolean;
|
||||
export type SummaryListItem = Column | Field | Chart | Task | MlFeature;
|
||||
|
||||
export interface ListItemHighlights {
|
||||
highlightedTags?: BasicEntityInfo['tags'];
|
||||
highlightedTitle?: string;
|
||||
highlightedDescription?: string;
|
||||
}
|
||||
|
||||
const getTitleName = (data: EntityNameProps) =>
|
||||
getEntityName(data) || NO_DATA_PLACEHOLDER;
|
||||
/* @param {
|
||||
listItem: SummaryItem,
|
||||
highlightedTitle: will be a string if the title of given summaryItem is present in highlights | undefined
|
||||
}
|
||||
|
||||
@return SummaryItemTitle
|
||||
*/
|
||||
export const getTitle = (
|
||||
listItem: SummaryListItem,
|
||||
highlightedTitle?: ListItemHighlights['highlightedTitle']
|
||||
): JSX.Element | JSX.Element[] => {
|
||||
const title = highlightedTitle
|
||||
? stringToHTML(highlightedTitle)
|
||||
: getEntityName(listItem) || NO_DATA_PLACEHOLDER;
|
||||
const sourceUrl = (listItem as Chart | Task).sourceUrl;
|
||||
|
||||
export const getTitle = ({
|
||||
content,
|
||||
sourceUrl,
|
||||
}: {
|
||||
content: string | JSX.Element | JSX.Element[] | undefined;
|
||||
sourceUrl: string | undefined;
|
||||
}) => {
|
||||
return sourceUrl ? (
|
||||
<Link target="_blank" to={{ pathname: sourceUrl }}>
|
||||
<div className="d-flex">
|
||||
@ -58,65 +71,189 @@ export const getTitle = ({
|
||||
className="entity-title text-link-color font-medium m-r-xss"
|
||||
data-testid="entity-title"
|
||||
ellipsis={{ tooltip: true }}>
|
||||
{content}
|
||||
{title}
|
||||
</Text>
|
||||
<IconExternalLink width={12} />
|
||||
</div>
|
||||
</Link>
|
||||
) : (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
{content}
|
||||
{title}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
/* @param {
|
||||
entityType: will be any type of SummaryEntityType,
|
||||
listItem: SummaryItem
|
||||
}
|
||||
@return listItemType
|
||||
*/
|
||||
export const getSummaryListItemType = (
|
||||
entityType: SummaryEntityType,
|
||||
listItemInfo: Column | Field | Chart | Task | MlFeature
|
||||
) => {
|
||||
listItem: SummaryListItem
|
||||
): BasicEntityInfo['type'] => {
|
||||
switch (entityType) {
|
||||
case SummaryEntityType.COLUMN:
|
||||
case SummaryEntityType.FIELD:
|
||||
case SummaryEntityType.MLFEATURE:
|
||||
case SummaryEntityType.SCHEMAFIELD:
|
||||
return (listItemInfo as Column | Field | MlFeature).dataType;
|
||||
return (listItem as Column | Field | MlFeature).dataType;
|
||||
case SummaryEntityType.CHART:
|
||||
return (listItemInfo as Chart).chartType;
|
||||
return (listItem as Chart).chartType;
|
||||
case SummaryEntityType.TASK:
|
||||
return (listItemInfo as Task).taskType;
|
||||
return (listItem as Task).taskType;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
export const getSortedTagsWithHighlight = ({
|
||||
sortTagsBasedOnGivenTagFQNs,
|
||||
tags,
|
||||
}: {
|
||||
sortTagsBasedOnGivenTagFQNs: string[];
|
||||
tags?: TagLabel[];
|
||||
}): (TagLabel | HighlightedTagLabel)[] => {
|
||||
const ColumnDataTags: {
|
||||
tagForSort: HighlightedTagLabel[];
|
||||
remainingTags: TagLabel[];
|
||||
} = { tagForSort: [], remainingTags: [] };
|
||||
|
||||
tags?.reduce((acc, tag) => {
|
||||
if (sortTagsBasedOnGivenTagFQNs.includes(tag.tagFQN)) {
|
||||
acc.tagForSort.push({ ...tag, isHighlighted: true });
|
||||
} else {
|
||||
acc.remainingTags.push(tag);
|
||||
/*
|
||||
@params {
|
||||
sortTagsBasedOnGivenTagFQNs: array of TagFQNs,
|
||||
tags: Tags array,
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, ColumnDataTags);
|
||||
@return array of tags highlighted and sorted if tagFQN present in sortTagsBasedOnGivenTagFQNs
|
||||
*/
|
||||
export const getSortedTagsWithHighlight = (
|
||||
tags: TagLabel[] = [],
|
||||
sortTagsBasedOnGivenTagFQNs: string[] = []
|
||||
): ListItemHighlights['highlightedTags'] => {
|
||||
const { sortedTags, remainingTags } = tags.reduce(
|
||||
(acc, tag) => {
|
||||
if (sortTagsBasedOnGivenTagFQNs.includes(tag.tagFQN)) {
|
||||
acc.sortedTags.push({ ...tag, isHighlighted: true });
|
||||
} else {
|
||||
acc.remainingTags.push(tag);
|
||||
}
|
||||
|
||||
return [...ColumnDataTags.tagForSort, ...ColumnDataTags.remainingTags];
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
sortedTags: [] as HighlightedTagLabel[],
|
||||
remainingTags: [] as TagLabel[],
|
||||
}
|
||||
);
|
||||
|
||||
return [...sortedTags, ...remainingTags];
|
||||
};
|
||||
|
||||
/*
|
||||
@param {highlights: all the other highlights come from the query api
|
||||
only omitted displayName and description key as it is already updated in parent component
|
||||
}
|
||||
|
||||
@return {
|
||||
listHighlights: single array of all highlights get from query api
|
||||
listHighlightsMap: to reduce the search time complexity in listHighlight
|
||||
}
|
||||
|
||||
Todo: apply highlights on entityData in parent where we apply highlight for entityDisplayName and entityDescription
|
||||
for that we need to update multiple summary components
|
||||
*/
|
||||
export const getMapOfListHighlights = (
|
||||
highlights?: SearchedDataProps['data'][number]['highlight']
|
||||
): {
|
||||
listHighlights: string[];
|
||||
listHighlightsMap: { [key: string]: number };
|
||||
} => {
|
||||
// checking for the all highlight key present in highlight get from query api
|
||||
// and create a array of highlights
|
||||
const listHighlights: string[] = [];
|
||||
SummaryListHighlightKeys.forEach((highlightKey) => {
|
||||
listHighlights.push(...get(highlights, highlightKey, []));
|
||||
});
|
||||
|
||||
// using hashmap methodology to reduce the search time complexity from O(n) to O(1)
|
||||
// to get highlight from the listHighlights array for applying highlight
|
||||
const listHighlightsMap: { [key: string]: number } = {};
|
||||
|
||||
listHighlights?.reduce((acc, colHighlight, index) => {
|
||||
acc[colHighlight.replaceAll(/<\/?span(.*?)>/g, '')] = index;
|
||||
|
||||
return acc;
|
||||
}, listHighlightsMap);
|
||||
|
||||
return { listHighlights, listHighlightsMap };
|
||||
};
|
||||
|
||||
/*
|
||||
@params {
|
||||
listItem: SummaryItem
|
||||
tagsHighlights: tagFQNs array to highlight and sort tags
|
||||
listHighlights: single array of all highlights get from query api
|
||||
listHighlightsMap: to reduce the search time complexity in listHighlight
|
||||
}
|
||||
@return highlights of listItem
|
||||
*/
|
||||
export const getHighlightOfListItem = (
|
||||
listItem: SummaryListItem,
|
||||
tagHighlights: string[],
|
||||
listHighlights: string[],
|
||||
listHighlightsMap: { [key: string]: number }
|
||||
): ListItemHighlights => {
|
||||
let highlightedTags;
|
||||
let highlightedTitle;
|
||||
let highlightedDescription;
|
||||
|
||||
// if any of the listItem.tags present in given tagHighlights list then sort and highlights the tag
|
||||
const shouldSortListItemTags = listItem.tags?.find((tag) =>
|
||||
tagHighlights.includes(tag.tagFQN)
|
||||
);
|
||||
|
||||
if (shouldSortListItemTags) {
|
||||
highlightedTags = getSortedTagsWithHighlight(listItem.tags, tagHighlights);
|
||||
}
|
||||
|
||||
// highlightedListItemNameIndex will be undefined if listItem.name is not present in highlights
|
||||
const highlightedListItemNameIndex = listHighlightsMap[listItem.name ?? ''];
|
||||
|
||||
const shouldApplyHighlightOnTitle = !isUndefined(
|
||||
highlightedListItemNameIndex
|
||||
);
|
||||
|
||||
if (shouldApplyHighlightOnTitle) {
|
||||
highlightedTitle = listHighlights[highlightedListItemNameIndex];
|
||||
}
|
||||
|
||||
// highlightedListItemDescriptionIndex will be undefined if listItem.description is not present in highlights
|
||||
const highlightedListItemDescriptionIndex =
|
||||
listHighlightsMap[listItem.description ?? ''];
|
||||
|
||||
const shouldApplyHighlightOnDescription = !isUndefined(
|
||||
highlightedListItemDescriptionIndex
|
||||
);
|
||||
|
||||
if (shouldApplyHighlightOnDescription) {
|
||||
highlightedDescription =
|
||||
listHighlights[highlightedListItemDescriptionIndex];
|
||||
}
|
||||
|
||||
return {
|
||||
highlightedTags,
|
||||
highlightedTitle,
|
||||
highlightedDescription,
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
@params {
|
||||
entityType: SummaryEntityType,
|
||||
entityInfo: Array<SummaryListItem> = [],
|
||||
highlights: highlights get from the query api + highlights added for tags (i.e. tag.name)
|
||||
tableConstraints: only pass for SummayEntityType.Column
|
||||
}
|
||||
@return sorted and highlighted listItem array, but listItem will be type of BasicEntityInfo
|
||||
|
||||
Note: SummaryItem will be sort and highlight only if -
|
||||
# if listItem.tags present in highlights.tags
|
||||
# if listItem.name present in highlights comes from query api
|
||||
# if listItem.description present in highlights comes from query api
|
||||
*/
|
||||
export const getFormattedEntityData = (
|
||||
entityType: SummaryEntityType,
|
||||
entityInfo?: Array<Column | Field | Chart | Task | MlFeature>,
|
||||
entityInfo: Array<SummaryListItem> = [],
|
||||
highlights?: SearchedDataProps['data'][number]['highlight'],
|
||||
tableConstraints?: TableConstraint[]
|
||||
): BasicEntityInfo[] => {
|
||||
@ -124,97 +261,68 @@ export const getFormattedEntityData = (
|
||||
return [];
|
||||
}
|
||||
|
||||
// sort and highlights list items based on tags and global search highlights data
|
||||
// Only go ahead if entityType is present in SummaryEntityType enum
|
||||
if (Object.values(SummaryEntityType).includes(entityType)) {
|
||||
// tagHighlights is the array of tagFQNs for highlighting tags
|
||||
const tagHighlights = get(highlights, 'tag.name', [] as string[]);
|
||||
const listHighlights: string[] = [];
|
||||
const listHighlightsMap: { [key: string]: number } = {};
|
||||
const SummaryListData = {
|
||||
listItemWithSortOption: [] as BasicEntityInfo[],
|
||||
listItemWithoutSortOption: [] as BasicEntityInfo[],
|
||||
};
|
||||
|
||||
SummaryListHighlightKeys.forEach((highlightKey) => {
|
||||
listHighlights.push(...get(highlights, highlightKey, []));
|
||||
});
|
||||
// listHighlights i.e. highlight get from query api
|
||||
// listHighlightsMap i.e. map of highlight get from api to reduce search time complexity in highlights array
|
||||
const { listHighlights, listHighlightsMap } =
|
||||
getMapOfListHighlights(highlights);
|
||||
|
||||
listHighlights?.reduce((acc, colHighlight, index) => {
|
||||
acc[colHighlight.replaceAll(/<\/?span(.*?)>/g, '')] = index;
|
||||
const { highlightedListItem, remainingListItem } = entityInfo.reduce(
|
||||
(acc, listItem) => {
|
||||
// return the highlight of listItem
|
||||
const { highlightedTags, highlightedTitle, highlightedDescription } =
|
||||
getHighlightOfListItem(
|
||||
listItem,
|
||||
tagHighlights,
|
||||
listHighlights,
|
||||
listHighlightsMap
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, listHighlightsMap);
|
||||
// convert listItem in BasicEntityInfo type
|
||||
const listItemModifiedData = {
|
||||
name: listItem.name ?? '',
|
||||
title: getTitle(listItem, highlightedTitle),
|
||||
type: getSummaryListItemType(entityType, listItem),
|
||||
tags: highlightedTags ?? listItem.tags,
|
||||
description: highlightedDescription ?? listItem.description,
|
||||
...(entityType === SummaryEntityType.COLUMN && {
|
||||
columnConstraint: (listItem as Column).constraint,
|
||||
tableConstraints: tableConstraints,
|
||||
}),
|
||||
...(entityType === SummaryEntityType.MLFEATURE && {
|
||||
algorithm: (listItem as MlFeature).featureAlgorithm,
|
||||
}),
|
||||
...((entityType === SummaryEntityType.COLUMN ||
|
||||
entityType === SummaryEntityType.FIELD) && {
|
||||
children: getFormattedEntityData(
|
||||
entityType,
|
||||
(listItem as Column | Field).children,
|
||||
highlights
|
||||
),
|
||||
}),
|
||||
};
|
||||
|
||||
entityInfo?.reduce((acc, listItem) => {
|
||||
const listItemModifiedData = {
|
||||
name: listItem.name ?? '',
|
||||
title: getTitle({
|
||||
content: getTitleName(listItem),
|
||||
sourceUrl: (listItem as Chart | Task).sourceUrl,
|
||||
}),
|
||||
type: getSummaryListItemType(entityType, listItem),
|
||||
tags: listItem.tags,
|
||||
description: listItem.description,
|
||||
...(entityType === SummaryEntityType.COLUMN && {
|
||||
columnConstraint: (listItem as Column).constraint,
|
||||
tableConstraints: tableConstraints,
|
||||
}),
|
||||
...(entityType === SummaryEntityType.MLFEATURE && {
|
||||
algorithm: (listItem as MlFeature).featureAlgorithm,
|
||||
}),
|
||||
children: getFormattedEntityData(
|
||||
entityType,
|
||||
(listItem as Column | Field).children,
|
||||
highlights,
|
||||
tableConstraints
|
||||
),
|
||||
};
|
||||
|
||||
const isTagHighlightsPresentInListItemTags = listItem.tags?.find((tag) =>
|
||||
tagHighlights.includes(tag.tagFQN)
|
||||
);
|
||||
|
||||
const highlightedListItemNameIndex =
|
||||
listHighlightsMap[listItem.name ?? ''];
|
||||
const highlightedListItemDescriptionIndex =
|
||||
listHighlightsMap[listItem.description ?? ''];
|
||||
|
||||
if (
|
||||
isTagHighlightsPresentInListItemTags ||
|
||||
!isUndefined(highlightedListItemNameIndex) ||
|
||||
!isUndefined(highlightedListItemDescriptionIndex)
|
||||
) {
|
||||
if (isTagHighlightsPresentInListItemTags) {
|
||||
listItemModifiedData.tags = getSortedTagsWithHighlight({
|
||||
sortTagsBasedOnGivenTagFQNs: tagHighlights,
|
||||
tags: listItem.tags,
|
||||
});
|
||||
// if highlights present in listItem then sort the listItem
|
||||
if (highlightedTags || highlightedTitle || highlightedDescription) {
|
||||
acc.highlightedListItem.push(listItemModifiedData);
|
||||
} else {
|
||||
acc.remainingListItem.push(listItemModifiedData);
|
||||
}
|
||||
|
||||
if (!isUndefined(highlightedListItemNameIndex)) {
|
||||
listItemModifiedData.title = getTitle({
|
||||
content: stringToHTML(listHighlights[highlightedListItemNameIndex]),
|
||||
sourceUrl: (listItem as Chart | Task).sourceUrl,
|
||||
});
|
||||
}
|
||||
|
||||
if (!isUndefined(highlightedListItemDescriptionIndex)) {
|
||||
listItemModifiedData.description =
|
||||
listHighlights[highlightedListItemDescriptionIndex];
|
||||
}
|
||||
|
||||
acc.listItemWithSortOption.push(listItemModifiedData);
|
||||
} else {
|
||||
acc.listItemWithoutSortOption.push(listItemModifiedData);
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
highlightedListItem: [] as BasicEntityInfo[],
|
||||
remainingListItem: [] as BasicEntityInfo[],
|
||||
}
|
||||
);
|
||||
|
||||
return acc;
|
||||
}, SummaryListData);
|
||||
|
||||
return [
|
||||
...SummaryListData.listItemWithSortOption,
|
||||
...SummaryListData.listItemWithoutSortOption,
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
return [...highlightedListItem, ...remainingListItem];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
@ -14,6 +14,8 @@
|
||||
import { Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { BasicEntityInfo } from '../../components/Explore/EntitySummaryPanel/SummaryList/SummaryList.interface';
|
||||
import { Task } from '../../generated/entity/data/pipeline';
|
||||
import {
|
||||
Column,
|
||||
DataType,
|
||||
@ -21,21 +23,189 @@ import {
|
||||
State,
|
||||
TagSource,
|
||||
} from '../../generated/entity/data/table';
|
||||
import { DataTypeTopic, Field } from '../../generated/entity/data/topic';
|
||||
import { ReactComponent as IconExternalLink } from '../assets/svg/external-links.svg';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
export const mockEntityDataWithoutNesting: Column[] = [
|
||||
export const mockTextBasedSummaryTitleResponse = (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
<span className="text-highlighter">title2</span>
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const mockLinkBasedSummaryTitleResponse = (
|
||||
<Link
|
||||
target="_blank"
|
||||
to={{
|
||||
pathname:
|
||||
'http://localhost:8080/taskinstance/list/?flt1_dag_id_equals=dim_address_task',
|
||||
}}>
|
||||
<div className="d-flex">
|
||||
<Text
|
||||
className="entity-title text-link-color font-medium m-r-xss"
|
||||
data-testid="entity-title"
|
||||
ellipsis={{ tooltip: true }}>
|
||||
dim_address Task
|
||||
</Text>
|
||||
<IconExternalLink width={12} />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
export const mockGetSummaryListItemTypeResponse = 'PrestoOperator';
|
||||
|
||||
export const mockTagsSortAndHighlightResponse = [
|
||||
{
|
||||
name: 'title',
|
||||
tagFQN: 'PersonalData.SpecialCategory',
|
||||
description:
|
||||
'GDPR special category data is personal information of data subjects that is especially sensitive.',
|
||||
source: TagSource.Classification,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
isHighlighted: true,
|
||||
},
|
||||
{
|
||||
tagFQN: 'PersonalData.Category1',
|
||||
description:
|
||||
'GDPR special category data is personal information of data subjects that is especially sensitive.',
|
||||
source: TagSource.Classification,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTagFQNsForHighlight = ['PersonalData.SpecialCategory'];
|
||||
|
||||
export const mockListItemNameHighlight =
|
||||
'<span className="text-highlighter">title2</span>';
|
||||
|
||||
const mockListItemDescriptionHighlight =
|
||||
'some description of <span className="text-highlighter">title2</span>';
|
||||
|
||||
export const mockHighlights = {
|
||||
'columns.name': [mockListItemNameHighlight],
|
||||
'columns.description': [mockListItemDescriptionHighlight],
|
||||
'tag.name': mockTagFQNsForHighlight,
|
||||
};
|
||||
|
||||
export const mockGetMapOfListHighlightsResponse = {
|
||||
listHighlights: [mockListItemNameHighlight, mockListItemDescriptionHighlight],
|
||||
listHighlightsMap: {
|
||||
title2: 0,
|
||||
'some description of title2': 1,
|
||||
},
|
||||
};
|
||||
|
||||
export const mockGetHighlightOfListItemResponse = {
|
||||
highlightedTags: undefined,
|
||||
highlightedTitle: mockListItemNameHighlight,
|
||||
highlightedDescription: mockListItemDescriptionHighlight,
|
||||
};
|
||||
|
||||
export const mockEntityDataWithoutNesting: Task[] = [
|
||||
{
|
||||
name: 'dim_address_task',
|
||||
displayName: 'dim_address Task',
|
||||
fullyQualifiedName: 'sample_airflow.dim_address_etl.dim_address_task',
|
||||
description:
|
||||
'Airflow operator to perform ETL and generate dim_address table',
|
||||
sourceUrl:
|
||||
'http://localhost:8080/taskinstance/list/?flt1_dag_id_equals=dim_address_task',
|
||||
downstreamTasks: ['assert_table_exists'],
|
||||
taskType: 'PrestoOperator',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'assert_table_exists',
|
||||
displayName: 'Assert Table Exists',
|
||||
fullyQualifiedName: 'sample_airflow.dim_address_etl.assert_table_exists',
|
||||
description: 'Assert if a table exists',
|
||||
sourceUrl:
|
||||
'http://localhost:8080/taskinstance/list/?flt1_dag_id_equals=assert_table_exists',
|
||||
downstreamTasks: [],
|
||||
taskType: 'HiveOperator',
|
||||
tags: [],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockEntityDataWithoutNestingResponse: BasicEntityInfo[] = [
|
||||
{
|
||||
name: 'dim_address_task',
|
||||
title: mockLinkBasedSummaryTitleResponse,
|
||||
description:
|
||||
'Airflow operator to perform ETL and generate dim_address table',
|
||||
type: mockGetSummaryListItemTypeResponse,
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'assert_table_exists',
|
||||
title: (
|
||||
<Link
|
||||
target="_blank"
|
||||
to={{
|
||||
pathname:
|
||||
'http://localhost:8080/taskinstance/list/?flt1_dag_id_equals=assert_table_exists',
|
||||
}}>
|
||||
<div className="d-flex">
|
||||
<Text
|
||||
className="entity-title text-link-color font-medium m-r-xss"
|
||||
data-testid="entity-title"
|
||||
ellipsis={{ tooltip: true }}>
|
||||
Assert Table Exists
|
||||
</Text>
|
||||
<IconExternalLink width={12} />
|
||||
</div>
|
||||
</Link>
|
||||
),
|
||||
description: 'Assert if a table exists',
|
||||
type: 'HiveOperator',
|
||||
tags: [],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockEntityDataWithNesting: Column[] = [
|
||||
{
|
||||
name: 'Customer',
|
||||
dataType: DataType.Varchar,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer',
|
||||
tags: [],
|
||||
description:
|
||||
'Full name of the app or channel. For example, Point of Sale, Online Store.',
|
||||
children: [
|
||||
{
|
||||
name: 'id',
|
||||
dataType: DataType.Varchar,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.id',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
dataType: DataType.Varchar,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.first_name',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
dataType: DataType.Varchar,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.last_name',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
dataType: DataType.Varchar,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.email',
|
||||
tags: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'title2',
|
||||
dataType: DataType.Varchar,
|
||||
dataLength: 100,
|
||||
dataTypeDisplay: 'varchar',
|
||||
description:
|
||||
'Full name of the app or channel. For example, Point of Sale, Online Store.',
|
||||
description: 'some description of title2',
|
||||
fullyQualifiedName:
|
||||
'sample_data.ecommerce_db.shopify."dim.api/client".title',
|
||||
'sample_data.ecommerce_db.shopify."dim.api/client".title2',
|
||||
tags: [],
|
||||
ordinalPosition: 2,
|
||||
},
|
||||
@ -69,227 +239,103 @@ export const mockEntityDataWithoutNesting: Column[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const mockEntityDataWithoutNestingResponse = [
|
||||
export const mockEntityDataWithNestingResponse: BasicEntityInfo[] = [
|
||||
{
|
||||
name: 'title2',
|
||||
title: mockTextBasedSummaryTitleResponse,
|
||||
type: DataType.Varchar,
|
||||
description: mockListItemDescriptionHighlight,
|
||||
tags: [],
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
children: [],
|
||||
description:
|
||||
'ID of the API client that called the Shopify API. For example, the ID for the online store is 580111.',
|
||||
},
|
||||
{
|
||||
name: 'api_client_id',
|
||||
tags: [
|
||||
{
|
||||
tagFQN: 'PersonalData.SpecialCategory',
|
||||
description:
|
||||
'GDPR special category data is personal information of data subjects that is especially sensitive.',
|
||||
source: 'Classification',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
isHighlighted: true,
|
||||
},
|
||||
{
|
||||
tagFQN: 'PersonalData.Category1',
|
||||
description:
|
||||
'GDPR special category data is personal information of data subjects that is especially sensitive.',
|
||||
source: 'Classification',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
},
|
||||
],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
api_client_id
|
||||
</Text>
|
||||
),
|
||||
type: 'NUMERIC',
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
type: DataType.Numeric,
|
||||
description:
|
||||
'Full name of the app or channel. For example, Point of Sale, Online Store.',
|
||||
name: 'title',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
title
|
||||
</Text>
|
||||
),
|
||||
type: 'VARCHAR',
|
||||
'ID of the API client that called the Shopify API. For example, the ID for the online store is 580111.',
|
||||
tags: mockTagsSortAndHighlightResponse,
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockEntityDataWithNesting: Field[] = [
|
||||
{
|
||||
name: 'Customer',
|
||||
dataType: DataTypeTopic.Record,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer',
|
||||
tags: [],
|
||||
children: [
|
||||
{
|
||||
name: 'id',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.id',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.first_name',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.last_name',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.email',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'address_line_1',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName:
|
||||
'sample_kafka.customer_events.Customer.address_line_1',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'address_line_2',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName:
|
||||
'sample_kafka.customer_events.Customer.address_line_2',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'post_code',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.post_code',
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
dataType: DataTypeTopic.String,
|
||||
fullyQualifiedName: 'sample_kafka.customer_events.Customer.country',
|
||||
tags: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockEntityDataWithNestingResponse = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'id',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
id
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'first_name',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
first_name
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'last_name',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
last_name
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'email',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
email
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'address_line_1',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
address_line_1
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'address_line_2',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
address_line_2
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'post_code',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
post_code
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
description: undefined,
|
||||
name: 'country',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
country
|
||||
</Text>
|
||||
),
|
||||
type: 'STRING',
|
||||
},
|
||||
],
|
||||
description: undefined,
|
||||
name: 'Customer',
|
||||
tags: [],
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
Customer
|
||||
</Text>
|
||||
),
|
||||
type: 'RECORD',
|
||||
type: DataType.Varchar,
|
||||
tags: [],
|
||||
description:
|
||||
'Full name of the app or channel. For example, Point of Sale, Online Store.',
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
children: [
|
||||
{
|
||||
name: 'id',
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
id
|
||||
</Text>
|
||||
),
|
||||
type: DataType.Varchar,
|
||||
tags: [],
|
||||
children: [],
|
||||
description: undefined,
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
},
|
||||
{
|
||||
name: 'first_name',
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
first_name
|
||||
</Text>
|
||||
),
|
||||
type: DataType.Varchar,
|
||||
tags: [],
|
||||
children: [],
|
||||
description: undefined,
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
},
|
||||
{
|
||||
name: 'last_name',
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
last_name
|
||||
</Text>
|
||||
),
|
||||
type: DataType.Varchar,
|
||||
tags: [],
|
||||
children: [],
|
||||
description: undefined,
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
title: (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
email
|
||||
</Text>
|
||||
),
|
||||
type: DataType.Varchar,
|
||||
tags: [],
|
||||
children: [],
|
||||
description: undefined,
|
||||
tableConstraints: undefined,
|
||||
columnConstraint: undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -309,94 +355,3 @@ export const mockInvalidDataResponse = [
|
||||
type: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTagsDataBeforeSortAndHighlight = [
|
||||
{
|
||||
tagFQN: 'gs1.term1',
|
||||
name: 'term1',
|
||||
displayName: '',
|
||||
description: 'term1 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
{
|
||||
tagFQN: 'gs1.term2',
|
||||
name: 'term2',
|
||||
displayName: '',
|
||||
description: 'term2 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
{
|
||||
tagFQN: 'gs1.term3',
|
||||
name: 'term3',
|
||||
displayName: '',
|
||||
description: 'term3 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTagsDataAfterSortAndHighlight = [
|
||||
{
|
||||
tagFQN: 'gs1.term2',
|
||||
name: 'term2',
|
||||
displayName: '',
|
||||
description: 'term2 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
isHighlighted: true,
|
||||
},
|
||||
{
|
||||
tagFQN: 'gs1.term1',
|
||||
name: 'term1',
|
||||
displayName: '',
|
||||
description: 'term1 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
{
|
||||
tagFQN: 'gs1.term3',
|
||||
name: 'term3',
|
||||
displayName: '',
|
||||
description: 'term3 desc',
|
||||
style: {},
|
||||
source: TagSource.Glossary,
|
||||
labelType: LabelType.Manual,
|
||||
state: State.Confirmed,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTagFQNsForHighlight = ['gs1.term2'];
|
||||
|
||||
export const mockGetSummaryListItemTypeResponse = DataType.Varchar;
|
||||
|
||||
export const mockTextBasedSummaryTitleResponse = (
|
||||
<Text className="entity-title" data-testid="entity-title">
|
||||
Title1
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const mockLinkBasedSummaryTitleResponse = (
|
||||
<Link target="_blank" to={{ pathname: 'https://task1.com' }}>
|
||||
<div className="d-flex">
|
||||
<Text
|
||||
className="entity-title text-link-color font-medium m-r-xss"
|
||||
data-testid="entity-title"
|
||||
ellipsis={{ tooltip: true }}>
|
||||
Title2
|
||||
</Text>
|
||||
<IconExternalLink width={12} />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user