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 ? (
-
);
+ 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 ? (
-
+ onClick={
+ hasDescription ? handleUpdateDescription : handleRequestDescription
+ }>
+
-
+
) : 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) ? (
+ onThreadLinkSelect?.(tasks.entityLink, ThreadType.Task)}>
+
+ {' '}
+
+ {' '}
+ {tasks.count}
+
+
+
+ ) : 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 = ({
onEntityFieldSelect?.('description')}>
+ onClick={() => onEntityFieldSelect?.(EntityField.DESCRIPTION)}>
onThreadLinkSelect?.(
- getEntityFeedLink(entityType, entityFqn, 'description')
+ getEntityFeedLink(
+ entityType,
+ entityFqn,
+ EntityField.DESCRIPTION
+ )
)
}>
{
blurWithBodyBG
description={description}
entityFieldThreads={getEntityFieldThreadCounts(
- 'description',
+ EntityField.DESCRIPTION,
entityFieldThreadCount
)}
entityFqn={databaseSchemaFQN}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx
index 11ea316b6bf..e8c5e70ae9c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx
@@ -27,7 +27,6 @@ import { useHistory, useParams } from 'react-router-dom';
import AppState from '../../AppState';
import {
getAllFeeds,
- getFeedCount,
postFeedById,
postThread,
} from '../../axiosAPIs/feedsAPI';
@@ -90,6 +89,7 @@ import {
getCurrentUserId,
getEntityMissingError,
getEntityName,
+ getFeedCounts,
getFields,
getPartialNameFromTableFQN,
} from '../../utils/CommonUtils';
@@ -174,6 +174,9 @@ const DatasetDetailsPage: FunctionComponent = () => {
const [entityFieldThreadCount, setEntityFieldThreadCount] = useState<
EntityFieldThreadCount[]
>([]);
+ const [entityFieldTaskCount, setEntityFieldTaskCount] = useState<
+ EntityFieldThreadCount[]
+ >([]);
// Data Quality tab state
const [testMode, setTestMode] = useState('table');
@@ -490,23 +493,13 @@ const DatasetDetailsPage: FunctionComponent = () => {
}, [activeTab]);
const getEntityFeedCount = () => {
- getFeedCount(getEntityFeedLink(EntityType.TABLE, tableFQN))
- .then((res: AxiosResponse) => {
- if (res.data) {
- setFeedCount(res.data.totalCount);
- setEntityFieldThreadCount(res.data.counts);
- } else {
- showErrorToast(
- jsonData['api-error-messages']['fetch-entity-feed-count-error']
- );
- }
- })
- .catch((err: AxiosError) => {
- showErrorToast(
- err,
- jsonData['api-error-messages']['fetch-entity-feed-count-error']
- );
- });
+ getFeedCounts(
+ EntityType.TABLE,
+ tableFQN,
+ setEntityFieldThreadCount,
+ setEntityFieldTaskCount,
+ setFeedCount
+ );
};
const saveUpdatedTableData = (updatedData: Table): Promise => {
@@ -1030,6 +1023,7 @@ const DatasetDetailsPage: FunctionComponent = () => {
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
+ entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
index a540359f94c..b21e5aa1123 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
@@ -31,6 +31,7 @@ import ProfilePicture from '../../../components/common/ProfilePicture/ProfilePic
import RichTextEditor from '../../../components/common/rich-text-editor/RichTextEditor';
import TitleBreadcrumb from '../../../components/common/title-breadcrumb/title-breadcrumb.component';
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
+import { EntityField } from '../../../constants/feed.constants';
import { EntityType } from '../../../enums/entity.enum';
import {
CreateThread,
@@ -99,7 +100,7 @@ const RequestDescription = () => {
const back = () => history.goBack();
const getColumnDetails = useCallback(() => {
- if (!isNil(field) && !isNil(value) && field === 'columns') {
+ if (!isNil(field) && !isNil(value) && field === EntityField.COLUMNS) {
const column = getSanitizeValue.split(FQN_SEPARATOR_CHAR).slice(-1);
const columnObject = getColumnObject(column[0], entityData.columns || []);
@@ -127,7 +128,7 @@ const RequestDescription = () => {
if (field && value) {
return `${field}${ENTITY_LINK_SEPARATOR}${value}${ENTITY_LINK_SEPARATOR}description`;
} else {
- return 'description';
+ return EntityField.DESCRIPTION;
}
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx
index 67dff6fdea2..2d582db8621 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/UpdateDescriptionPage/UpdateDescriptionPage.tsx
@@ -29,6 +29,7 @@ import { postThread } from '../../../axiosAPIs/feedsAPI';
import ProfilePicture from '../../../components/common/ProfilePicture/ProfilePicture';
import TitleBreadcrumb from '../../../components/common/title-breadcrumb/title-breadcrumb.component';
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
+import { EntityField } from '../../../constants/feed.constants';
import { EntityType } from '../../../enums/entity.enum';
import {
CreateThread,
@@ -104,7 +105,7 @@ const UpdateDescription = () => {
}, [field, entityData]);
const getColumnDetails = useCallback(() => {
- if (!isNil(field) && !isNil(value) && field === 'columns') {
+ if (!isNil(field) && !isNil(value) && field === EntityField.COLUMNS) {
return (
Column Details
@@ -136,7 +137,7 @@ const UpdateDescription = () => {
if (field && value) {
return `${field}${ENTITY_LINK_SEPARATOR}${value}${ENTITY_LINK_SEPARATOR}description`;
} else {
- return 'description';
+ return EntityField.DESCRIPTION;
}
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx
index 02601e8ab48..44f8aed1abe 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/database-details/index.tsx
@@ -61,6 +61,7 @@ import {
PAGE_SIZE,
pagingObject,
} from '../../constants/constants';
+import { EntityField } from '../../constants/feed.constants';
import { observerOptions } from '../../constants/Mydata.constants';
import { EntityType, TabSpecificField } from '../../enums/entity.enum';
import { ServiceCategory } from '../../enums/service.enum';
@@ -674,7 +675,7 @@ const DatabaseDetails: FunctionComponent = () => {
blurWithBodyBG
description={description}
entityFieldThreads={getEntityFieldThreadCounts(
- 'description',
+ EntityField.DESCRIPTION,
entityFieldThreadCount
)}
entityFqn={databaseFQN}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/tour-page/TourPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/tour-page/TourPage.component.tsx
index ab7bee08454..31874009089 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/tour-page/TourPage.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/tour-page/TourPage.component.tsx
@@ -193,6 +193,7 @@ const TourPage = () => {
deletePostHandler={handleCountChange}
description={mockDatasetData.description}
descriptionUpdateHandler={handleCountChange}
+ entityFieldTaskCount={[]}
entityFieldThreadCount={[]}
entityLineage={mockDatasetData.entityLineage}
entityLineageHandler={handleCountChange}
diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css b/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css
index eda3f14f3c1..adaeee3268e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css
+++ b/openmetadata-ui/src/main/resources/ui/src/styles/x-master.css
@@ -1132,6 +1132,7 @@ code {
}
.ant-popover-feed > .ant-popover-content > .ant-popover-inner,
.ant-popover-card > .ant-popover-content > .ant-popover-inner,
+.ant-popover-request-description > .ant-popover-content > .ant-popover-inner,
.ant-popover-feed-reactions > .ant-popover-content > .ant-popover-inner {
border-radius: 6px;
border: 1px solid #dde3ea;
@@ -1341,3 +1342,7 @@ div.ant-typography-ellipsis-custom {
color: #7147e8;
background-color: #7147e825;
}
+
+.table-query-editor pre.CodeMirror-line {
+ padding-right: 60px !important;
+}
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx
index 90ebda95d11..866fdf92c75 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/CommonUtils.tsx
@@ -11,9 +11,11 @@
* limitations under the License.
*/
+import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames';
import { capitalize, isEmpty, isNull, isUndefined } from 'lodash';
import {
+ EntityFieldThreadCount,
RecentlySearched,
RecentlySearchedData,
RecentlyViewed,
@@ -22,6 +24,7 @@ import {
import React, { FormEvent } from 'react';
import { reactLocalStorage } from 'reactjs-localstorage';
import AppState from '../AppState';
+import { getFeedCount } from '../axiosAPIs/feedsAPI';
import { Button } from '../components/buttons/Button/Button';
import { FQN_SEPARATOR_CHAR } from '../constants/char.constants';
import {
@@ -36,12 +39,15 @@ import {
} from '../constants/regex.constants';
import { EntityType, FqnPart, TabSpecificField } from '../enums/entity.enum';
import { Ownership } from '../enums/mydata.enum';
+import { ThreadType } from '../generated/entity/feed/thread';
import { EntityReference, User } from '../generated/entity/teams/user';
-import { getTitleCase } from './EntityUtils';
+import jsonData from '../jsons/en';
+import { getEntityFeedLink, getTitleCase } from './EntityUtils';
import Fqn from './Fqn';
import { getExplorePathWithInitFilters } from './RouterUtils';
import { serviceTypeLogo } from './ServiceUtils';
import SVGIcons, { Icons } from './SvgUtils';
+import { showErrorToast } from './ToastUtils';
export const arraySorterByKey = (
key: string,
@@ -631,3 +637,48 @@ export const getExploreLinkByFilter = (
export const replaceSpaceWith_ = (text: string) => {
return text.replace(/\s/g, '_');
};
+
+export const getFeedCounts = (
+ entityType: string,
+ entityFQN: string,
+ conversationCallback: (
+ value: React.SetStateAction
+ ) => void,
+ taskCallback: (value: React.SetStateAction) => void,
+ entityCallback: (value: React.SetStateAction) => void
+) => {
+ getFeedCount(
+ getEntityFeedLink(entityType, entityFQN),
+ ThreadType.Conversation
+ )
+ .then((res: AxiosResponse) => {
+ if (res.data) {
+ entityCallback(res.data.totalCount);
+ conversationCallback(res.data.counts);
+ } else {
+ throw jsonData['api-error-messages']['fetch-entity-feed-count-error'];
+ }
+ })
+ .catch((err: AxiosError) => {
+ showErrorToast(
+ err,
+ jsonData['api-error-messages']['fetch-entity-feed-count-error']
+ );
+ });
+
+ getFeedCount(getEntityFeedLink(entityType, entityFQN), ThreadType.Task)
+ .then((res: AxiosResponse) => {
+ if (res.data) {
+ entityCallback(res.data.totalCount);
+ taskCallback(res.data.counts);
+ } else {
+ throw jsonData['api-error-messages']['fetch-entity-feed-count-error'];
+ }
+ })
+ .catch((err: AxiosError) => {
+ showErrorToast(
+ err,
+ jsonData['api-error-messages']['fetch-entity-feed-count-error']
+ );
+ });
+};
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/EntityVersionUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/EntityVersionUtils.tsx
index 1b2a0155588..913df663654 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/EntityVersionUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/EntityVersionUtils.tsx
@@ -26,6 +26,7 @@ import {
DESCRIPTIONLENGTH,
getTeamAndUserDetailsPath,
} from '../constants/constants';
+import { EntityField } from '../constants/feed.constants';
import { ChangeType } from '../enums/entity.enum';
import { Column } from '../generated/entity/data/table';
import {
@@ -301,7 +302,7 @@ export const feedSummaryFromatter = (
);
break;
- } else if (fieldChange?.name?.endsWith('description')) {
+ } else if (fieldChange?.name?.endsWith(EntityField.DESCRIPTION)) {
summary = (
{`${
@@ -321,7 +322,7 @@ export const feedSummaryFromatter = (
);
break;
- } else if (fieldChange?.name === 'columns') {
+ } else if (fieldChange?.name === EntityField.COLUMNS) {
const length = value?.length ?? 0;
summary = (
@@ -419,7 +420,7 @@ export const feedSummaryFromatter = (
break;
}
- case fieldChange?.name === 'description': {
+ case fieldChange?.name === EntityField.DESCRIPTION: {
summary = (
{`${
@@ -523,7 +524,7 @@ export const summaryFormatter = (fieldChange: FieldChange) => {
? fieldChange?.oldValue
: '{}'
);
- if (fieldChange.name === 'columns') {
+ if (fieldChange.name === EntityField.COLUMNS) {
return `columns ${value?.map((val: any) => val?.name).join(', ')}`;
} else if (
fieldChange.name === 'tags' ||
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/FeedElementUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/FeedElementUtils.tsx
index 05ce1717520..dc6fa68ecdb 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/FeedElementUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/FeedElementUtils.tsx
@@ -11,10 +11,11 @@
* limitations under the License.
*/
-import { isEmpty, isUndefined } from 'lodash';
+import { isEmpty, isEqual, isUndefined } from 'lodash';
import { EntityFieldThreads } from 'Models';
import React, { Fragment } from 'react';
import { entityUrlMap } from '../constants/feed.constants';
+import { ThreadType } from '../generated/entity/feed/thread';
import { EntityReference } from '../generated/entity/teams/user';
import { getEntityFeedLink } from './EntityUtils';
import { getThreadField } from './FeedUtils';
@@ -24,11 +25,12 @@ export const getFieldThreadElement = (
columnName: string,
columnField: string,
entityFieldThreads: EntityFieldThreads[],
- onThreadLinkSelect?: (value: string) => void,
+ onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void,
entityType?: string,
entityFqn?: string,
entityField?: string,
- flag = true
+ flag = true,
+ threadType?: ThreadType
) => {
let threadValue: EntityFieldThreads = {} as EntityFieldThreads;
@@ -39,27 +41,36 @@ export const getFieldThreadElement = (
}
});
+ const isTaskType = isEqual(threadType, ThreadType.Task);
+
return !isEmpty(threadValue) ? (
-
{
e.preventDefault();
e.stopPropagation();
- onThreadLinkSelect?.(threadValue.entityLink);
+ onThreadLinkSelect?.(
+ threadValue.entityLink,
+ isTaskType ? ThreadType.Task : ThreadType.Conversation
+ );
}}>
-
+
{threadValue.count}
-
+
) : (
- {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: