Fix issue-600: UI: doesn't allow table level tags to be added (#3547)

This commit is contained in:
Shailesh Parmar 2022-03-22 02:25:32 +05:30 committed by GitHub
parent 5bd7fae70d
commit a66ef4800c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 157 additions and 70 deletions

View File

@ -94,6 +94,7 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
isNodeLoading,
dataModel,
deleted,
tagUpdateHandler,
addLineageHandler,
removeLineageHandler,
entityLineageHandler,
@ -423,6 +424,18 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
}
};
/**
* Formulates updated tags and updates table entity data for API call
* @param selectedTags
*/
const onTagUpdate = (selectedTags?: Array<EntityTags>) => {
if (selectedTags) {
const updatedTags = [...(tier ? [tier] : []), ...selectedTags];
const updatedTable = { ...tableDetails, tags: updatedTags };
tagUpdateHandler(updatedTable);
}
};
const followTable = () => {
if (isFollowing) {
setFollowersCount((preValu) => preValu - 1);
@ -487,18 +500,28 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
<PageContainer>
<div className="tw-px-6 tw-w-full tw-h-full tw-flex tw-flex-col">
<EntityPageInfo
isTagEditable
deleted={deleted}
entityFieldThreads={getEntityFieldThreadCounts(
'tags',
entityFieldThreadCount
)}
entityFqn={datasetFQN}
entityName={entityName}
entityType={EntityType.DATASET}
extraInfo={extraInfo}
followHandler={followTable}
followers={followersCount}
followersList={followers}
hasEditAccess={hasEditAccess()}
isFollowing={isFollowing}
tags={tableTags}
tagsHandler={onTagUpdate}
tier={tier}
titleLinks={slashedTableName}
version={version}
versionHandler={versionHandler}
onThreadLinkSelect={onThreadLinkSelect}
/>
<div className="tw-mt-4 tw-flex tw-flex-col tw-flex-grow">

View File

@ -96,6 +96,7 @@ export interface DatasetDetailsProps {
settingsUpdateHandler: (updatedTable: Table) => Promise<void>;
columnsUpdateHandler: (updatedTable: Table) => void;
descriptionUpdateHandler: (updatedTable: Table) => void;
tagUpdateHandler: (updatedTable: Table) => void;
versionHandler: () => void;
handleSelectedColumn: (value: string | undefined) => void;
loadNodeHandler: (node: EntityReference, pos: LineagePos) => void;

View File

@ -112,6 +112,7 @@ const DatasetDetailsProps = {
handleTestModeChange: jest.fn(),
qualityTestFormHandler: jest.fn(),
deletePostHandler: jest.fn(),
tagUpdateHandler: jest.fn(),
};
jest.mock('../ManageTab/ManageTab.component', () => {
return jest.fn().mockReturnValue(<p>ManageTab</p>);

View File

@ -30,7 +30,6 @@ import {
getTagsDiff,
} from '../../utils/EntityVersionUtils';
import { getOwnerFromId } from '../../utils/TableUtils';
import { getTableTags } from '../../utils/TagsUtils';
import Description from '../common/description/Description';
import EntityPageInfo from '../common/entityPageInfo/EntityPageInfo';
import TabsPane from '../common/TabsPane/TabsPane';
@ -310,6 +309,47 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
}
};
/**
* Calculates tags for selected version.
* @returns current version's tag.
*/
const getTags = () => {
const tagsDiff = getDiffByFieldName('tags', changeDescription, true);
const oldTags: Array<TagLabel> = JSON.parse(
tagsDiff?.added?.oldValue ??
tagsDiff?.deleted?.oldValue ??
tagsDiff?.updated?.oldValue ??
'[]'
);
const newTags: Array<TagLabel> = JSON.parse(
tagsDiff?.added?.newValue ??
tagsDiff?.deleted?.newValue ??
tagsDiff?.updated?.newValue ??
'[]'
);
const flag: { [x: string]: boolean } = {};
const uniqueTags: Array<TagLabel & { added: boolean; removed: boolean }> =
[];
[
...(getTagsDiff(oldTags, newTags) ?? []),
...(currentVersionData.tags ?? []),
].forEach((elem: TagLabel & { added: boolean; removed: boolean }) => {
if (!flag[elem.tagFQN as string]) {
flag[elem.tagFQN as string] = true;
uniqueTags.push(elem);
}
});
return [
...uniqueTags.map((t) =>
t.tagFQN.startsWith('Tier')
? { ...t, tagFQN: t.tagFQN.split('.')[1] }
: t
),
];
};
const tabs = [
{
name: 'Schema',
@ -346,7 +386,7 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
entityName={currentVersionData.name ?? ''}
extraInfo={getExtraInfo()}
followersList={[]}
tags={getTableTags(currentVersionData.columns || [])}
tags={getTags()}
tier={tier}
titleLinks={slashedTableName}
version={version}

View File

@ -11,6 +11,8 @@
* limitations under the License.
*/
import { faExclamationCircle, faStar } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import { isEmpty, isUndefined } from 'lodash';
import {
@ -27,6 +29,10 @@ import { User } from '../../../generated/entity/teams/user';
import { LabelType, State, TagLabel } from '../../../generated/type/tagLabel';
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
import { getEntityFeedLink, getInfoElements } from '../../../utils/EntityUtils';
import {
fetchGlossaryTerms,
getGlossaryTermlist,
} from '../../../utils/GlossaryUtils';
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import { getFollowerDetail } from '../../../utils/TableUtils';
import { getTagCategories, getTaglist } from '../../../utils/TagsUtils';
@ -38,12 +44,6 @@ import PopOver from '../popover/PopOver';
import TitleBreadcrumb from '../title-breadcrumb/title-breadcrumb.component';
import { TitleBreadcrumbProps } from '../title-breadcrumb/title-breadcrumb.interface';
import FollowersModal from './FollowersModal';
import {
fetchGlossaryTerms,
getGlossaryTermlist,
} from '../../../utils/GlossaryUtils';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faExclamationCircle, faStar } from '@fortawesome/free-solid-svg-icons';
type Props = {
titleLinks: TitleBreadcrumbProps['titleLinks'];
@ -435,6 +435,7 @@ const EntityPageInfo = ({
setIsEditable(true);
}}>
<TagsContainer
dropDownHorzPosRight={false}
editable={isEditable}
isLoading={isTagLoading}
selectedTags={getSelectedTags()}

View File

@ -21,13 +21,21 @@ const jsonData = {
'delete-team-error': 'Error while deleting team!',
'elastic-search-error': 'Error while fetch data from Elasticsearch!',
'fetch-data-error': 'Error while fetching data!',
'fetch-entity-feed-error': 'Error while fetching entity feeds!',
'fetch-entity-feed-count-error': 'Error while fetching entity feed count!',
'fetch-feed-error': 'Error while fetching messages',
'fetch-glossary-error': 'Error while fetching glossary!',
'fetch-glossary-list-error': 'Error while fetching glossaries!',
'fetch-glossary-term-error': 'Error while fetching glossary term!',
'fetch-lineage-error': 'Error while fetching lineage data!',
'fetch-sample-data-error': 'Error while fetching sample data!',
'fetch-table-details-error': 'Error while fetching table details!',
'fetch-table-queries-error': 'Error while fetching table queries!',
'fetch-tags-error': 'Error while fetching tags!',
'update-glossary-term-error': 'Error while updating glossary term!',
'update-description-error': 'Error while updating description!',
'update-entity-error': 'Error while updating entity!',
'update-tags-error': 'Error while updating tags!',
},
'form-error-messages': {
'empty-email': 'Email is required.',

View File

@ -89,6 +89,7 @@ import {
DatasetTestModeType,
ModifiedTableColumn,
} from '../../interface/dataQuality.interface';
import jsonData from '../../jsons/en';
import {
addToRecentViewed,
getCurrentUserId,
@ -104,8 +105,7 @@ import {
import { getEntityFeedLink, getEntityLineage } from '../../utils/EntityUtils';
import { deletePost, getUpdatedThread } from '../../utils/FeedUtils';
import { serviceTypeLogo } from '../../utils/ServiceUtils';
import { getTierTags } from '../../utils/TableUtils';
import { getTableTags } from '../../utils/TagsUtils';
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
const DatasetDetailsPage: FunctionComponent = () => {
const history = useHistory();
@ -178,6 +178,13 @@ const DatasetDetailsPage: FunctionComponent = () => {
const [tableTestCase, setTableTestCase] = useState<TableTest[]>([]);
const [selectedColumn, setSelectedColumn] = useState<string>();
const handleShowErrorToast = (errMessage: string) => {
showToast({
variant: 'error',
body: errMessage,
});
};
const handleTestModeChange = (mode: DatasetTestModeType) => {
setTestMode(mode);
};
@ -226,10 +233,10 @@ const DatasetDetailsPage: FunctionComponent = () => {
setEntityLineage(res.data);
})
.catch((err: AxiosError) => {
showToast({
variant: 'error',
body: err.message ?? 'Error while fetching lineage data.',
});
const msg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-lineage-error'];
handleShowErrorToast(msg);
})
.finally(() => {
setIsLineageLoading(false);
@ -243,11 +250,11 @@ const DatasetDetailsPage: FunctionComponent = () => {
const { data } = res.data;
setEntityThread(data);
})
.catch(() => {
showToast({
variant: 'error',
body: 'Error while fetching entity feeds',
});
.catch((err: AxiosError) => {
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-entity-feed-error'];
handleShowErrorToast(errMsg);
})
.finally(() => setIsentityThreadLoading(false));
};
@ -325,7 +332,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
setColumns(columns || []);
setSampleData(sampleData);
setTableProfile(tableProfile || []);
setTableTags(getTableTags(columns || []));
setTableTags(getTagsWithoutTier(tags));
setUsageSummary(usageSummary);
setJoins(joins);
})
@ -333,11 +340,10 @@ const DatasetDetailsPage: FunctionComponent = () => {
if (err.response?.status === 404) {
setIsError(true);
} else {
const errMsg = err.message || 'Error while fetching table details.';
showToast({
variant: 'error',
body: errMsg,
});
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-table-details-error'];
handleShowErrorToast(errMsg);
}
})
.finally(() => {
@ -357,12 +363,12 @@ const DatasetDetailsPage: FunctionComponent = () => {
const { sampleData } = res.data;
setSampleData(sampleData);
})
.catch(() =>
showToast({
variant: 'error',
body: 'Error while getting sample data.',
})
)
.catch((err: AxiosError) => {
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-sample-data-error'];
handleShowErrorToast(errMsg);
})
.finally(() => setIsSampleDataLoading(false));
break;
@ -391,12 +397,12 @@ const DatasetDetailsPage: FunctionComponent = () => {
const { tableQueries } = res.data;
setTableQueries(tableQueries);
})
.catch(() =>
showToast({
variant: 'error',
body: 'Error while getting table queries',
})
)
.catch((err: AxiosError) => {
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-table-queries-error'];
handleShowErrorToast(errMsg);
})
.finally(() => setIsTableQueriesLoading(false));
break;
@ -429,11 +435,11 @@ const DatasetDetailsPage: FunctionComponent = () => {
setFeedCount(res.data.totalCount);
setEntityFieldThreadCount(res.data.counts);
})
.catch(() => {
showToast({
variant: 'error',
body: 'Error while fetching entity feed count',
});
.catch((err: AxiosError) => {
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['fetch-entity-feed-count-error'];
handleShowErrorToast(errMsg);
});
};
@ -457,12 +463,9 @@ const DatasetDetailsPage: FunctionComponent = () => {
})
.catch((err: AxiosError) => {
const msg =
err.response?.data.message ||
`Error while updating entity description.`;
showToast({
variant: 'error',
body: msg,
});
err.response?.data?.message ||
jsonData['api-error-messages']['update-description-error'];
handleShowErrorToast(msg);
});
};
@ -473,16 +476,35 @@ const DatasetDetailsPage: FunctionComponent = () => {
setCurrentVersion(version);
setTableDetails(res.data);
setColumns(columns);
setTableTags(getTableTags(columns || []));
getEntityFeedCount();
})
.catch((err: AxiosError) => {
const msg =
err.response?.data.message || `Error while updating entity.`;
showToast({
variant: 'error',
body: msg,
});
err.response?.data?.message ||
jsonData['api-error-messages']['update-entity-error'];
handleShowErrorToast(msg);
});
};
const onTagUpdate = (updatedTable: Table) => {
saveUpdatedTableData(updatedTable)
.then((res: AxiosResponse) => {
if (res.data) {
setTier(getTierTags(res.data.tags));
setCurrentVersion(res.data.version);
setTableTags(getTagsWithoutTier(res.data.tags));
getEntityFeedCount();
} else {
handleShowErrorToast(
jsonData['api-error-messages']['update-tags-error']
);
}
})
.catch((err: AxiosError) => {
const errMsg =
err.response?.data?.message ||
jsonData['api-error-messages']['update-tags-error'];
handleShowErrorToast(errMsg);
});
};
@ -500,16 +522,16 @@ const DatasetDetailsPage: FunctionComponent = () => {
})
.catch((err: AxiosError) => {
const msg =
err.response?.data.message || `Error while updating entity.`;
err.response?.data?.message ||
jsonData['api-error-messages']['update-entity-error'];
handleShowErrorToast(msg);
reject();
showToast({
variant: 'error',
body: msg,
});
});
});
};
// TODO: move all the error from below code to en.ts and use handleShowErrorToast to show error.
const followTable = () => {
addFollower(tableId, USERId).then((res: AxiosResponse) => {
const { newValue } = res.data.changeDescription.fieldsAdded[0];
@ -895,6 +917,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
tableTags={tableTags}
tableTestCase={tableTestCase}
tableType={tableType}
tagUpdateHandler={onTagUpdate}
testMode={testMode}
tier={tier as TagLabel}
unfollowTableHandler={unfollowTable}

View File

@ -88,7 +88,6 @@ import {
} from '../../utils/FeedUtils';
import { serviceTypeLogo } from '../../utils/ServiceUtils';
import { getOwnerFromId, getUsagePercentile } from '../../utils/TableUtils';
import { getTableTags } from '../../utils/TagsUtils';
const DatabaseDetails: FunctionComponent = () => {
// User Id for getting followers
@ -673,16 +672,6 @@ const DatabaseDetails: FunctionComponent = () => {
type="label"
/>
))}
{getTableTags(table.columns).map(
(tag, tagIdx) => (
<Tags
key={tagIdx}
startWith="#"
tag={tag}
type="label"
/>
)
)}
</td>
</tr>
))

View File

@ -224,6 +224,7 @@ const TourPage = () => {
tableTags={mockDatasetData.tableTags}
tableTestCase={[]}
tableType={mockDatasetData.tableType as TableType}
tagUpdateHandler={handleCountChange}
testMode="table"
tier={'' as unknown as TagLabel}
unfollowTableHandler={handleCountChange}