From 38b04b76a9652c6bb842ddd57c63f9b07fd5082d Mon Sep 17 00:00:00 2001 From: Sachin Chaurasiya Date: Wed, 29 Jun 2022 17:32:29 +0530 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Refactor=20:=20Refactor=20Table=20E?= =?UTF-8?q?ntity=20Conversation=20and=20Task=20Flow=20Logic=20=20#5734=20(?= =?UTF-8?q?#5736)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Refactor : Refactor Conversation and Task Flow Logic #5734 * Fix emoji multiple API call issue * Fix table query editor issue * Addressing review comments --- .../resources/ui/src/assets/svg/Task-ic.svg | 8 + .../resources/ui/src/axiosAPIs/feedsAPI.ts | 4 +- .../ActivityThreadPanel.interface.ts | 1 + .../ActivityThreadPanel.tsx | 17 +- .../ActivityThreadPanelBody.tsx | 9 +- .../DashboardDetails.component.tsx | 3 +- .../DashboardVersion.component.tsx | 3 +- .../DatasetDetails.component.tsx | 24 ++- .../DatasetDetails.interface.ts | 1 + .../DatasetDetails/DatasetDetails.test.tsx | 1 + .../DatasetVersion.component.tsx | 12 +- .../EntityTable/EntityTable.component.tsx | 185 ++++++++++-------- .../PipelineDetails.component.tsx | 3 +- .../PipelineVersion.component.tsx | 3 +- .../ui/src/components/Reactions/Emoji.jsx | 29 ++- .../SchemaTab/SchemaTab.component.tsx | 6 +- .../TopicDetails/TopicDetails.component.tsx | 3 +- .../TopicVersion/TopicVersion.component.tsx | 3 +- .../description/Description.interface.ts | 4 +- .../common/description/Description.tsx | 120 +++++++----- .../common/description/DescriptionV1.tsx | 9 +- .../ui/src/constants/feed.constants.ts | 12 ++ .../DatabaseSchemaPage.component.tsx | 3 +- .../DatasetDetailsPage.component.tsx | 30 ++- .../RequestDescriptionPage.tsx | 5 +- .../UpdateDescriptionPage.tsx | 5 +- .../ui/src/pages/database-details/index.tsx | 3 +- .../pages/tour-page/TourPage.component.tsx | 1 + .../main/resources/ui/src/styles/x-master.css | 5 + .../resources/ui/src/utils/CommonUtils.tsx | 53 ++++- .../ui/src/utils/EntityVersionUtils.tsx | 9 +- .../ui/src/utils/FeedElementUtils.tsx | 35 ++-- .../main/resources/ui/src/utils/SvgUtils.tsx | 6 + 33 files changed, 409 insertions(+), 206 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/assets/svg/Task-ic.svg diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/Task-ic.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/Task-ic.svg new file mode 100644 index 00000000000..a795ba1ab86 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/Task-ic.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/feedsAPI.ts b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/feedsAPI.ts index be95a893adf..b4fc8764c5c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/feedsAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/feedsAPI.ts @@ -66,11 +66,13 @@ export const getFeedsWithFilter: Function = ( }; export const getFeedCount: Function = ( - entityLink?: string + entityLink?: string, + type?: ThreadType ): Promise => { return APIClient.get(`/feed/count`, { params: { entityLink: entityLink, + type, }, }); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.interface.ts index b539f97cf85..605ad3fb80d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.interface.ts @@ -20,6 +20,7 @@ import { ConfirmState } from '../ActivityFeedCard/ActivityFeedCard.interface'; export interface ActivityThreadPanelProp extends HTMLAttributes { threadLink: string; + threadType?: ThreadType; open?: boolean; postFeedHandler: (value: string, id: string) => void; createThread: (data: CreateThread) => void; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx index c20bc2d2091..76b7e8f5064 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx @@ -13,8 +13,10 @@ import { Tabs } from 'antd'; import classNames from 'classnames'; +import { isEqual } from 'lodash'; import React, { FC, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; +import { PanelTab } from '../../../constants/feed.constants'; import { ThreadType } from '../../../generated/entity/feed/thread'; import FeedPanelOverlay from '../ActivityFeedPanel/FeedPanelOverlay'; import { ActivityThreadPanelProp } from './ActivityThreadPanel.interface'; @@ -29,14 +31,21 @@ const ActivityThreadPanel: FC = ({ createThread, deletePostHandler, updateThreadHandler, + threadType, }) => { const { TabPane } = Tabs; - const [activeTab, setActiveTab] = useState('1'); + const [activeTab, setActiveTab] = useState(PanelTab.TASKS); const onTabChange = (key: string) => { - setActiveTab(key); + setActiveTab(key as PanelTab); }; + useEffect(() => { + if (isEqual(threadType, ThreadType.Conversation)) { + setActiveTab(PanelTab.CONVERSATIONS); + } + }, [threadType]); + useEffect(() => { document.body.style.overflow = 'hidden'; }, []); @@ -60,7 +69,7 @@ const ActivityThreadPanel: FC = ({ activeKey={activeTab} className="ant-tabs-custom-line ant-tabs-custom-threadpanel" onChange={onTabChange}> - + = ({ onTabChange={onTabChange} /> - + = ({ useAfterMount(() => { if (threadType === ThreadType.Task && !isThreadLoading) { - isEqual(threads.length, 0) && onTabChange && onTabChange('2'); + isEqual(threads.length, 0) && + onTabChange && + onTabChange(PanelTab.CONVERSATIONS); } }, [threads, isThreadLoading]); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx index 06f5124415d..a8c00fa5b1b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx @@ -20,6 +20,7 @@ import { Link } from 'react-router-dom'; import AppState from '../../AppState'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { getTeamAndUserDetailsPath } from '../../constants/constants'; +import { EntityField } from '../../constants/feed.constants'; import { observerOptions } from '../../constants/Mydata.constants'; import { SettledStatus } from '../../enums/axios.enum'; import { EntityType } from '../../enums/entity.enum'; @@ -497,7 +498,7 @@ const DashboardDetails = ({ = ({ const getDashboardDescription = () => { const descriptionDiff = getDiffByFieldName( - 'description', + EntityField.DESCRIPTION, changeDescription ); const oldDescription = diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx index d0817ca05e4..cc50967b750 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx @@ -24,6 +24,7 @@ import React, { import AppState from '../../AppState'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { getTeamAndUserDetailsPath, ROUTES } from '../../constants/constants'; +import { EntityField } from '../../constants/feed.constants'; import { observerOptions } from '../../constants/Mydata.constants'; import { CSMode } from '../../enums/codemirror.enum'; import { EntityType, FqnPart } from '../../enums/entity.enum'; @@ -34,6 +35,7 @@ import { TableJoins, TypeUsedToReturnUsageDetailsOfAnEntity, } from '../../generated/entity/data/table'; +import { ThreadType } from '../../generated/entity/feed/thread'; import { EntityReference } from '../../generated/type/entityReference'; import { Paging } from '../../generated/type/paging'; import { LabelType, State } from '../../generated/type/tagLabel'; @@ -138,6 +140,7 @@ const DatasetDetails: React.FC = ({ fetchFeedHandler, handleExtentionUpdate, updateThreadHandler, + entityFieldTaskCount, }: DatasetDetailsProps) => { const [isEdit, setIsEdit] = useState(false); const [followersCount, setFollowersCount] = useState(0); @@ -152,6 +155,9 @@ const DatasetDetails: React.FC = ({ }); const [threadLink, setThreadLink] = useState(''); + const [threadType, setThreadType] = useState( + ThreadType.Conversation + ); const [selectedField, setSelectedField] = useState(''); const [elementRef, isInView] = useInfiniteScroll(observerOptions); @@ -527,8 +533,11 @@ const DatasetDetails: React.FC = ({ }; }; - const onThreadLinkSelect = (link: string) => { + const onThreadLinkSelect = (link: string, threadType?: ThreadType) => { setThreadLink(link); + if (threadType) { + setThreadType(threadType); + } }; const onThreadPanelClose = () => { @@ -615,8 +624,12 @@ const DatasetDetails: React.FC = ({
= ({ FQN_SEPARATOR_CHAR )} columns={columns} + entityFieldTasks={getEntityFieldThreadCounts( + EntityField.COLUMNS, + entityFieldTaskCount + )} entityFieldThreads={getEntityFieldThreadCounts( - 'columns', + EntityField.COLUMNS, entityFieldThreadCount )} entityFqn={datasetFQN} @@ -818,6 +835,7 @@ const DatasetDetails: React.FC = ({ open={Boolean(threadLink)} postFeedHandler={postFeedHandler} threadLink={threadLink} + threadType={threadType} updateThreadHandler={updateThreadHandler} onCancel={onThreadPanelClose} /> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.interface.ts index 190a6f041cb..9b188cdd3d9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.interface.ts @@ -75,6 +75,7 @@ export interface DatasetDetailsProps { isentityThreadLoading: boolean; feedCount: number; entityFieldThreadCount: EntityFieldThreadCount[]; + entityFieldTaskCount: EntityFieldThreadCount[]; testMode: DatasetTestModeType; tableTestCase: TableTest[]; showTestForm: boolean; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx index eb60fb1d429..3c993955952 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx @@ -145,6 +145,7 @@ const DatasetDetailsProps = { postFeedHandler: jest.fn(), feedCount: 0, entityFieldThreadCount: [], + entityFieldTaskCount: [], showTestForm: false, testMode: 'table' as DatasetTestModeType, handleAddTableTestCase: jest.fn(), diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetVersion/DatasetVersion.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DatasetVersion/DatasetVersion.component.tsx index d13d9cb5cc1..3c25a11345e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetVersion/DatasetVersion.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetVersion/DatasetVersion.component.tsx @@ -16,6 +16,7 @@ import { cloneDeep, isEqual, isUndefined } from 'lodash'; import { ExtraInfo } from 'Models'; import React, { useEffect, useState } from 'react'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; +import { EntityField } from '../../constants/feed.constants'; import { FqnPart } from '../../enums/entity.enum'; import { OwnerType } from '../../enums/user.enum'; import { @@ -138,7 +139,7 @@ const DatasetVersion: React.FC = ({ const getTableDescription = () => { const descriptionDiff = getDiffByFieldName( - 'description', + EntityField.DESCRIPTION, changeDescription ); const oldDescription = @@ -159,7 +160,10 @@ const DatasetVersion: React.FC = ({ const updatedColumns = (): Table['columns'] => { const colList = cloneDeep(currentVersionData.columns); - const columnsDiff = getDiffByFieldName('columns', changeDescription); + const columnsDiff = getDiffByFieldName( + EntityField.COLUMNS, + changeDescription + ); const changedColName = getChangeColName( columnsDiff?.added?.name ?? columnsDiff?.deleted?.name ?? @@ -171,7 +175,7 @@ const DatasetVersion: React.FC = ({ columnsDiff?.added?.name ?? columnsDiff?.deleted?.name ?? columnsDiff?.updated?.name, - 'description' + EntityField.DESCRIPTION ) ) { const oldDescription = @@ -249,7 +253,7 @@ const DatasetVersion: React.FC = ({ return colList ?? []; } else { const columnsDiff = getDiffByFieldName( - 'columns', + EntityField.COLUMNS, changeDescription, true ); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx index 88dbf1722bc..5e5e41e055e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx @@ -13,6 +13,7 @@ import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Popover } from 'antd'; import classNames from 'classnames'; import { cloneDeep, isNil, isUndefined, lowerCase } from 'lodash'; import { EntityFieldThreads, EntityTags, TagOption } from 'Models'; @@ -22,6 +23,7 @@ import { useExpanded, useTable } from 'react-table'; import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { getTableDetailsPath } from '../../constants/constants'; +import { EntityField } from '../../constants/feed.constants'; import { SettledStatus } from '../../enums/axios.enum'; import { EntityType, FqnPart } from '../../enums/entity.enum'; import { @@ -31,6 +33,7 @@ import { JoinedWith, Table, } from '../../generated/entity/data/table'; +import { ThreadType } from '../../generated/entity/feed/thread'; import { Operation } from '../../generated/entity/policies/accessControl/rule'; import { TestCaseStatus } from '../../generated/tests/tableTest'; import { LabelType, State, TagLabel } from '../../generated/type/tagLabel'; @@ -43,7 +46,6 @@ import { } from '../../utils/CommonUtils'; import { ENTITY_LINK_SEPARATOR } from '../../utils/EntityUtils'; import { getFieldThreadElement } from '../../utils/FeedElementUtils'; -import { getThreadValue } from '../../utils/FeedUtils'; import { fetchGlossaryTerms, getGlossaryTermlist, @@ -77,8 +79,9 @@ interface Props { isReadOnly?: boolean; entityFqn?: string; entityFieldThreads?: EntityFieldThreads[]; + entityFieldTasks?: EntityFieldThreads[]; onUpdate?: (columns: ModifiedTableColumn[]) => void; - onThreadLinkSelect?: (value: string) => void; + onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void; onEntityFieldSelect?: (value: string) => void; } @@ -94,6 +97,7 @@ const EntityTable = ({ onThreadLinkSelect, entityFqn, tableConstraints, + entityFieldTasks, }: Props) => { const { isAdminUser, userPermissions } = useAuth(); const { isAuthDisabled } = useAuthContext(); @@ -356,7 +360,13 @@ const EntityTable = ({ return searchedValue; }; - /* eslint-disable-next-line */ + const checkPermission = () => + isAdminUser || + hasEditAccess || + isAuthDisabled || + userPermissions[Operation.UpdateDescription]; + + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const getColumnName = (cell: any) => { const fqn = cell?.row?.original?.fullyQualifiedName || ''; const columnName = getPartialNameFromTableFQN(fqn, [FqnPart.NestedColumn]); @@ -367,9 +377,9 @@ const EntityTable = ({ : columnName; }; - /* eslint-disable-next-line */ + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ const onRequestDescriptionHandler = (cell: any) => { - const field = 'columns'; + const field = EntityField.COLUMNS; const value = getColumnName(cell); history.push( getRequestDescriptionPath( @@ -381,6 +391,20 @@ const EntityTable = ({ ); }; + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + const onUpdateDescriptionHandler = (cell: any) => { + const field = EntityField.COLUMNS; + const value = getColumnName(cell); + history.push( + getUpdateDescriptionPath( + EntityType.TABLE, + entityFqn as string, + field, + value + ) + ); + }; + const prepareConstraintIcon = ( columnName: string, columnConstraint?: string @@ -399,28 +423,41 @@ const EntityTable = ({ } }; - /* eslint-disable-next-line */ - const handleUpdate = (column: Column, index: number, cell: any) => { - const check = - isAdminUser || - hasEditAccess || - isAuthDisabled || - userPermissions[Operation.UpdateDescription]; - if (check) { - handleEditColumn(column, index); - } else { - const field = 'columns'; - const value = getColumnName(cell); + const handleUpdate = (column: Column, index: number) => { + handleEditColumn(column, index); + }; - history.push( - getUpdateDescriptionPath( - EntityType.TABLE, - entityFqn as string, - field, - value - ) - ); - } + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + const getRequestDescriptionElement = (cell: any) => { + const hasDescription = Boolean(cell.value); + + return ( + + ); }; useEffect(() => { @@ -675,60 +712,52 @@ const EntityTable = ({ )}
- {!isReadOnly ? ( - - - - {isNil( - getThreadValue( - getColumnName(cell), - 'description', - entityFieldThreads as EntityFieldThreads[] - ) - ) && !cell.value ? ( - - ) : null} - {getFieldThreadElement( - getColumnName(cell), - 'description', - entityFieldThreads as EntityFieldThreads[], - onThreadLinkSelect, - EntityType.TABLE, - entityFqn, - `columns${ENTITY_LINK_SEPARATOR}${getColumnName( - cell - )}${ENTITY_LINK_SEPARATOR}description`, - Boolean(cell.value) - )} - - ) : null} + + )} + {getRequestDescriptionElement(cell)} + {getFieldThreadElement( + getColumnName(cell), + EntityField.DESCRIPTION, + entityFieldThreads as EntityFieldThreads[], + onThreadLinkSelect, + EntityType.TABLE, + entityFqn, + `columns${ENTITY_LINK_SEPARATOR}${getColumnName( + cell + )}${ENTITY_LINK_SEPARATOR}description`, + Boolean(cell.value) + )} + {getFieldThreadElement( + getColumnName(cell), + EntityField.DESCRIPTION, + entityFieldTasks as EntityFieldThreads[], + onThreadLinkSelect, + EntityType.TABLE, + entityFqn, + `columns${ENTITY_LINK_SEPARATOR}${getColumnName( + cell + )}${ENTITY_LINK_SEPARATOR}description`, + Boolean(cell.value), + ThreadType.Task + )} + + ) : null} + {checkIfJoinsAvailable(row.original.name) && ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx index 9d525a08320..3a16c546a0d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx @@ -17,6 +17,7 @@ import React, { RefObject, useCallback, useEffect, useState } from 'react'; import AppState from '../../AppState'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { getTeamAndUserDetailsPath } from '../../constants/constants'; +import { EntityField } from '../../constants/feed.constants'; import { observerOptions } from '../../constants/Mydata.constants'; import { EntityType } from '../../enums/entity.enum'; import { OwnerType } from '../../enums/user.enum'; @@ -392,7 +393,7 @@ const PipelineDetails = ({ = ({ const getPipelineDescription = () => { const descriptionDiff = getDiffByFieldName( - 'description', + EntityField.DESCRIPTION, changeDescription ); const oldDescription = diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Reactions/Emoji.jsx b/openmetadata-ui/src/main/resources/ui/src/components/Reactions/Emoji.jsx index 4b160ca0085..0ff02dea982 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Reactions/Emoji.jsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Reactions/Emoji.jsx @@ -16,17 +16,20 @@ import { Button, Popover } from 'antd'; import classNames from 'classnames'; import { observer } from 'mobx-react'; import PropTypes from 'prop-types'; -import React, { useMemo } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import AppState from '../../AppState'; import { REACTION_LIST } from '../../constants/reactions.constant'; import { ReactionOperation } from '../../enums/reactions.enum'; import useImage from '../../hooks/useImage'; const Emoji = ({ reaction, reactionList, onReactionSelect }) => { - // get reaction object based on cureent reaction + const [reactionType, setReactionType] = useState(reaction); + const [isClicked, setIsClicked] = useState(false); + + // get reaction object based on cureent reactionType const reactionObject = useMemo( - () => REACTION_LIST.find((value) => value.reaction === reaction), - [reaction] + () => REACTION_LIST.find((value) => value.reaction === reactionType), + [reactionType] ); const { image } = useImage(`emojis/${reactionObject.reaction}.png`); @@ -45,10 +48,13 @@ const Emoji = ({ reaction, reactionList, onReactionSelect }) => { const userList = reactionList.map((reactionItem) => reactionItem.user.name); const handleOnClick = () => { - const operation = isReacted - ? ReactionOperation.REMOVE - : ReactionOperation.ADD; - onReactionSelect(reactionObject.reaction, operation); + if (!isClicked) { + const operation = isReacted + ? ReactionOperation.REMOVE + : ReactionOperation.ADD; + onReactionSelect(reactionObject.reaction, operation); + setIsClicked(true); + } }; const popoverContent = ( @@ -56,10 +62,15 @@ const Emoji = ({ reaction, reactionList, onReactionSelect }) => { className="tw-w-44 tw-break-normal tw-m-0 tw-p-0" data-testid="popover-content"> {`${userList.join(', ')}`}{' '} - {`reacted with ${reaction} emoji`} + {`reacted with ${reactionType} emoji`}

); + useEffect(() => { + setReactionType(reaction); + setIsClicked(false); + }, [reaction]); + return ( void; + entityFieldTasks?: EntityFieldThreads[]; + onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void; onEntityFieldSelect?: (value: string) => void; onUpdate?: (columns: Table['columns']) => void; }; @@ -51,6 +53,7 @@ const SchemaTab: FunctionComponent = ({ isReadOnly = false, entityFqn, tableConstraints, + entityFieldTasks, }: Props) => { const [searchText, setSearchText] = useState(''); @@ -75,6 +78,7 @@ const SchemaTab: FunctionComponent = ({
= ({ = ({ const getTableDescription = () => { const descriptionDiff = getDiffByFieldName( - 'description', + EntityField.DESCRIPTION, changeDescription ); const oldDescription = diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.interface.ts index 79830c09c5e..c49c74b4d10 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.interface.ts @@ -13,6 +13,7 @@ import { EntityFieldThreads } from 'Models'; import { Table } from '../../../generated/entity/data/table'; +import { ThreadType } from '../../../generated/entity/feed/thread'; export interface DescriptionProps { entityName?: string; @@ -26,7 +27,8 @@ export interface DescriptionProps { entityType?: string; entityFqn?: string; entityFieldThreads?: EntityFieldThreads[]; - onThreadLinkSelect?: (value: string) => void; + entityFieldTasks?: EntityFieldThreads[]; + onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void; onDescriptionEdit?: () => void; onCancel?: () => void; onDescriptionUpdate?: (value: string) => void; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.tsx index 01c064c5d35..d9316e46200 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/description/Description.tsx @@ -11,14 +11,15 @@ * limitations under the License. */ +import { Popover } from 'antd'; import classNames from 'classnames'; import { isUndefined } from 'lodash'; import { EntityFieldThreads } from 'Models'; import React, { FC, Fragment } from 'react'; import { useHistory } from 'react-router-dom'; import { useAuthContext } from '../../../authentication/auth-provider/AuthProvider'; -import { TITLE_FOR_UPDATE_DESCRIPTION } from '../../../constants/constants'; -import { EntityType } from '../../../enums/entity.enum'; +import { EntityField } from '../../../constants/feed.constants'; +import { ThreadType } from '../../../generated/entity/feed/thread'; import { Operation } from '../../../generated/entity/policies/accessControl/rule'; import { useAuth } from '../../../hooks/authHooks'; import { getEntityFeedLink } from '../../../utils/EntityUtils'; @@ -26,11 +27,8 @@ import SVGIcons, { Icons } from '../../../utils/SvgUtils'; import { getRequestDescriptionPath, getUpdateDescriptionPath, - TASK_ENTITIES, } from '../../../utils/TasksUtils'; import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; -import NonAdminAction from '../non-admin-action/NonAdminAction'; -import PopOver from '../popover/PopOver'; import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer'; import { DescriptionProps } from './Description.interface'; @@ -50,6 +48,7 @@ const Description: FC = ({ onEntityFieldSelect, entityType, entityFqn, + entityFieldTasks, }) => { const history = useHistory(); @@ -57,6 +56,7 @@ const Description: FC = ({ const { isAuthDisabled } = useAuthContext(); const thread = entityFieldThreads?.[0]; + const tasks = entityFieldTasks?.[0]; const handleRequestDescription = () => { history.push( @@ -71,45 +71,44 @@ const Description: FC = ({ }; const checkPermission = () => { - if (!isAuthDisabled && !isAdminUser) { - return Boolean( - hasEditAccess || userPermissions[Operation.UpdateDescription] - ); - } - - return true; + return ( + isAdminUser || + Boolean(hasEditAccess) || + userPermissions[Operation.UpdateDescription] || + isAuthDisabled + ); }; const handleUpdate = () => { - if (checkPermission()) { - onDescriptionEdit && onDescriptionEdit(); - } else if (TASK_ENTITIES.includes(entityType as EntityType)) { - handleUpdateDescription(); - } + onDescriptionEdit && onDescriptionEdit(); }; - const RequestDescriptionEl = ({ - descriptionThread, - }: { - descriptionThread?: EntityFieldThreads; - }) => { - return isUndefined(descriptionThread) && - onEntityFieldSelect && - !description?.trim() ? ( + const RequestDescriptionEl = () => { + const hasDescription = Boolean(description.trim()); + + return onEntityFieldSelect ? ( ) : null; }; @@ -120,8 +119,8 @@ const Description: FC = ({ descriptionThread?: EntityFieldThreads; }) => { return !isUndefined(descriptionThread) ? ( -

onThreadLinkSelect?.(descriptionThread.entityLink)}> @@ -131,48 +130,61 @@ const Description: FC = ({ {descriptionThread.count} -

+ ) : ( {description?.trim() && onThreadLinkSelect ? ( -

onThreadLinkSelect?.( - getEntityFeedLink(entityType, entityFqn, 'description') + getEntityFeedLink( + entityType, + entityFqn, + EntityField.DESCRIPTION + ) ) }> -

+ ) : null}
); }; + const getDescriptionTaskElement = () => { + return !isUndefined(tasks) ? ( + + ) : null; + }; + const DescriptionActions = () => { return !isReadOnly ? ( -
- +
+ {checkPermission() && ( - + )} - + + {getDescriptionTaskElement()}
) : null; }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx index 14664f92575..8cdbefa47c2 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx @@ -15,6 +15,7 @@ import classNames from 'classnames'; import { isUndefined } from 'lodash'; import { EntityFieldThreads } from 'Models'; import React, { Fragment } from 'react'; +import { EntityField } from '../../../constants/feed.constants'; import { Table } from '../../../generated/entity/data/table'; import { Operation } from '../../../generated/entity/policies/accessControl/rule'; import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils'; @@ -130,7 +131,7 @@ const DescriptionV1 = ({ ) : ( - {entityType && entityFqn && entityField && flag ? ( -

{ e.preventDefault(); @@ -69,7 +80,7 @@ export const getFieldThreadElement = ( ); }}> -

+ ) : null}
); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx index f333cb53c5c..ef506233201 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx @@ -144,6 +144,7 @@ import IconTableGrey from '../assets/svg/table-grey.svg'; import IconTable from '../assets/svg/table.svg'; import IconTagGrey from '../assets/svg/tag-grey.svg'; import IconTag from '../assets/svg/tag.svg'; +import IconTaskColor from '../assets/svg/Task-ic.svg'; import IconTeamsGrey from '../assets/svg/teams-grey.svg'; import IconTerns from '../assets/svg/terms.svg'; import IconTier from '../assets/svg/tier.svg'; @@ -313,6 +314,7 @@ export const Icons = { STAR: 'ic-star', MENTIONS: 'ic-mentions', COMMENT_GREY: 'ic-comment-grey', + TASK_ICON: 'task-icon', }; const SVGIcons: FunctionComponent = ({ @@ -890,6 +892,10 @@ const SVGIcons: FunctionComponent = ({ case Icons.ALERT_BELL: IconComponent = IconAlertBell; + break; + case Icons.TASK_ICON: + IconComponent = IconTaskColor; + break; case Icons.TASK: