+
{entityThread.length === 0 && (
)}
{entityThread.map((feed) => (
-
+
))}
- {isDrawerOpen && (
- <>
-
- >
- )}
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.test.tsx
deleted file mode 100644
index ba72f5afc31..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.test.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2022 Collate.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { findAllByTestId, render } from '@testing-library/react';
-import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
-import FeedListBody from './FeedListBody';
-
-jest.mock('../ActivityFeedCard/ActivityFeedCard', () => {
- return jest.fn().mockReturnValue(
ActivityFeedCard
);
-});
-
-jest.mock('../ActivityFeedEditor/ActivityFeedEditor', () => {
- return jest.fn().mockReturnValue(
ActivityFeedEditor
);
-});
-
-jest.mock('../ActivityFeedCard/FeedCardFooter/FeedCardFooter', () => {
- return jest.fn().mockReturnValue(
FeedCardFooter
);
-});
-
-const mockThreads = [
- {
- id: '465b2dfb-300e-45f5-a1a6-e19c6225e9e7',
- href: 'http://localhost:8585/api/v1/feed/465b2dfb-300e-45f5-a1a6-e19c6225e9e7',
- threadTs: 1647434125848,
- about: '<#E::table::bigquery_gcp.shopify.raw_product_catalog::description>',
- entityId: 'f1ebcfdf-d4b8-43bd-add2-1789e25ddde3',
- createdBy: 'aaron_johnson0',
- updatedAt: 1647434125848,
- updatedBy: 'anonymous',
- resolved: false,
- message: 'New thread.',
- postsCount: 0,
- posts: [],
- relativeDay: 'Today',
- },
- {
- id: '40c2faec-0159-4d86-9b15-c17f3e1c081b',
- href: 'http://localhost:8585/api/v1/feed/40c2faec-0159-4d86-9b15-c17f3e1c081b',
- threadTs: 1647411418056,
- about: '<#E::table::bigquery_gcp.shopify.raw_product_catalog::description>',
- entityId: 'f1ebcfdf-d4b8-43bd-add2-1789e25ddde3',
- createdBy: 'sachin.c',
- updatedAt: 1647434031435,
- updatedBy: 'anonymous',
- resolved: false,
- message: 'New thread.',
- postsCount: 3,
- posts: [
- {
- id: 'afc5648f-9f30-4588-bd26-319c66af7c46',
- message: 'reply2',
- postTs: 1647434021493,
- from: 'aaron_johnson0',
- },
- {
- id: '8ec9283f-a671-48d6-8328-f537dadd9fc7',
- message: 'reply3',
- postTs: 1647434025868,
- from: 'aaron_johnson0',
- },
- {
- id: 'a8559fd6-940c-4f14-9808-6c376b6f872c',
- message: 'reply4',
- postTs: 1647434031430,
- from: 'aaron_johnson0',
- },
- ],
- relativeDay: 'Today',
- },
-];
-
-const onThreadIdSelect = jest.fn();
-
-const mockFeedListBodyProp = {
- updatedFeedList: mockThreads,
- relativeDay: 'Today',
- isEntityFeed: false,
- onThreadSelect: jest.fn(),
- onThreadIdSelect,
- postFeed: jest.fn(),
- onViewMore: jest.fn(),
- selectedThreadId: '',
- onConfirmation: jest.fn(),
- onThreadIdDeselect: jest.fn(),
- updateThreadHandler: jest.fn(),
-};
-
-describe('Test FeedListBody Component', () => {
- it('Check if FeedListBody has all the child elements', async () => {
- const { container } = render(
, {
- wrapper: MemoryRouter,
- });
-
- const messages = await findAllByTestId(container, 'message-container');
-
- expect(messages).toHaveLength(2);
- });
-});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.tsx
deleted file mode 100644
index bf04e067462..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2022 Collate.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { Card } from 'antd';
-import classNames from 'classnames';
-import { isEqual } from 'lodash';
-import React, { FC, Fragment } from 'react';
-import { useTranslation } from 'react-i18next';
-import { useHistory } from 'react-router-dom';
-import {
- Post,
- ThreadTaskStatus,
- ThreadType,
-} from '../../../generated/entity/feed/thread';
-import { getTaskDetailPath } from '../../../utils/TasksUtils';
-import AssigneeList from '../../common/AssigneeList/AssigneeList';
-import ActivityFeedCard from '../ActivityFeedCard/ActivityFeedCard';
-import FeedCardFooter from '../ActivityFeedCard/FeedCardFooter/FeedCardFooter';
-import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor';
-import AnnouncementBadge from '../Shared/AnnouncementBadge';
-import TaskBadge from '../Shared/TaskBadge';
-import { FeedListBodyProp } from './ActivityFeedList.interface';
-import './FeedListBody.less';
-
-const FeedListBody: FC
= ({
- updatedFeedList,
- relativeDay,
- isEntityFeed,
- onThreadSelect,
- onThreadIdSelect,
- postFeed,
- onViewMore,
- selectedThreadId,
- onConfirmation,
- updateThreadHandler,
-}) => {
- const { t } = useTranslation();
- const history = useHistory();
- const toggleReplyEditor = (id: string) => {
- onThreadIdSelect(selectedThreadId === id ? '' : id);
- };
-
- const onReplyThread = (id: string) => {
- onThreadSelect(id);
- onViewMore();
- };
-
- const getFeedEditor = (id: string) => {
- return selectedThreadId === id ? (
-
- ) : null;
- };
-
- const getThreadFooter = (
- postLength: number,
- repliedUsers: Array,
- replies: number,
- threadId: string,
- lastPost?: Post
- ) => {
- return (
-
- {Boolean(lastPost) &&
}
- {postLength > 1 ? (
-
- {
- onThreadIdSelect('');
- onThreadSelect(id);
- onViewMore();
- }}
- />
-
- ) : null}
-
- );
- };
-
- const handleCardClick = (taskId: number, isTask: boolean) => {
- if (isTask) {
- history.push(getTaskDetailPath(String(taskId)));
- }
- };
-
- return (
-
- {updatedFeedList
- .filter((f) => f.relativeDay === relativeDay)
- .map((feed, index) => {
- const mainFeed = {
- message: feed.message,
- postTs: feed.threadTs,
- from: feed.createdBy,
- id: feed.id,
- reactions: feed.reactions,
- } as Post;
- const isTask = isEqual(feed.type, ThreadType.Task);
- const isAnnouncement = feed.type === ThreadType.Announcement;
- const postLength = feed?.posts?.length || 0;
- const replies = feed.postsCount ? feed.postsCount - 1 : 0;
- const repliedUsers = [
- ...new Set((feed?.posts || []).map((f) => f.from)),
- ];
- const repliedUniqueUsersList = repliedUsers.slice(
- 0,
- postLength >= 3 ? 2 : 1
- );
- const lastPost = feed?.posts?.[postLength - 1];
-
- return (
-
- feed.task && handleCardClick(feed.task.id, isTask)
- }>
- {isTask && (
-
- )}
- {isAnnouncement && }
-
-
onReplyThread(feed.id)}
- />
- {postLength > 0 ? (
-
- {getThreadFooter(
- postLength,
- repliedUniqueUsersList,
- replies,
- feed.id,
- lastPost
- )}
- toggleReplyEditor(feed.id)}
- />
- {getFeedEditor(feed.id)}
-
- ) : null}
-
- {feed.task && (
-
-
- {t('label.assignee-plural')}:{' '}
-
-
-
- )}
-
- );
- })}
-
- );
-};
-
-export default FeedListBody;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/activity-feed-list.less b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/activity-feed-list.less
index 8acc12193df..8437a8b9244 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/activity-feed-list.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/activity-feed-list.less
@@ -10,7 +10,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@import url('../../../styles/variables.less');
.activity-feed-card-container.has-replies > .activity-feed-card,
.activity-feed-card-container:last-child > .activity-feed-card {
@@ -19,10 +18,4 @@
.feed-posts {
margin-left: 24px;
- .activity-feed-card {
- border-bottom: 1px solid @border-color;
- &:last-child {
- border-bottom: none;
- }
- }
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.interface.ts
index 824dc2398ea..ef0a208e001 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.interface.ts
@@ -38,6 +38,7 @@ export interface FeedPanelHeaderProp
noun?: string;
threadType?: ThreadType;
onShowNewConversation?: (v: boolean) => void;
+ hideCloseIcon?: boolean;
}
export interface FeedPanelOverlayProp
extends HTMLAttributes,
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.test.tsx
deleted file mode 100644
index c5a91f2a5b9..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.test.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2022 Collate.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { render, screen } from '@testing-library/react';
-import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
-import ActivityFeedPanel from './ActivityFeedPanel';
-
-const mockThreadData = {
- id: '35442ff6-ad28-4725-9fa0-3eab9078c3a6',
- href: 'http://localhost:8585/api/v1/feed/35442ff6-ad28-4725-9fa0-3eab9078c3a6',
- threadTs: 1647838571960,
- about: '<#E::table::bigquery_gcp.shopify.raw_product_catalog::description>',
- entityId: 'cb7944d3-f5fe-4289-8672-f8ba6036d551',
- createdBy: 'anonymous',
- updatedAt: 1647852740613,
- updatedBy: 'anonymous',
- resolved: false,
- message:
- 'Updated **description** : This is a raw product catalog table contains the product listing, price, seller etc.. represented in our online DB.',
- postsCount: 2,
- posts: [
- {
- id: '4452fd7c-0e7d-435c-823c-c668de0a2940',
- message: 'reply1',
- postTs: 1647852726255,
- from: 'aaron_johnson0',
- },
- {
- id: '061dfeb2-378c-4078-8b37-0ba3f36beb97',
- message: 'reply2',
- postTs: 1647852740607,
- from: 'aaron_johnson0',
- },
- ],
-};
-
-const mockFeedPanelProp = {
- open: true,
- selectedThread: mockThreadData,
- onCancel: jest.fn(),
-
- postFeed: jest.fn(),
- deletePostHandler: jest.fn(),
- updateThreadHandler: jest.fn(),
-};
-
-jest.mock('../../../utils/FeedUtils', () => ({
- getEntityField: jest.fn(),
- getEntityFQN: jest.fn(),
-}));
-
-jest.mock('../ActivityFeedEditor/ActivityFeedEditor', () => {
- return jest.fn().mockReturnValue(ActivityFeedEditor
);
-});
-
-jest.mock('./FeedPanelBody', () => {
- return jest.fn().mockReturnValue(FeedPanelBody
);
-});
-
-jest.mock('./FeedPanelHeader', () => {
- return jest.fn().mockReturnValue(FeedPanelHeader
);
-});
-
-jest.mock('rest/feedsAPI', () => ({
- getFeedById: jest.fn().mockImplementation(() => Promise.resolve()),
-}));
-
-jest.mock('../../../utils/ToastUtils', () => ({
- showErrorToast: jest
- .fn()
- .mockImplementation(({ children }) => {children}
),
-}));
-
-describe('Test FeedPanel Component', () => {
- it('Check if FeedPanel has all child elements', async () => {
- render(, {
- wrapper: MemoryRouter,
- });
- const FeedPanelHeader = await screen.findByText(/FeedPanelHeader/i);
- const FeedPanelBody = await screen.findByText(/FeedPanelBody/i);
- const FeedPanelEditor = await screen.findByText(/ActivityFeedEditor/i);
- const DeleteConfirmationModal = screen.queryByTestId('confirmation-modal');
-
- expect(FeedPanelHeader).toBeInTheDocument();
- expect(FeedPanelBody).toBeInTheDocument();
- expect(FeedPanelEditor).toBeInTheDocument();
- expect(DeleteConfirmationModal).toBeFalsy();
- });
-});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.tsx
deleted file mode 100644
index 92ba01ab0ea..00000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/ActivityFeedPanel.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2022 Collate.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { Drawer } from 'antd';
-import { AxiosError } from 'axios';
-import classNames from 'classnames';
-import React, { FC, useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { getFeedById } from 'rest/feedsAPI';
-import { confirmStateInitialValue } from '../../../constants/Feeds.constants';
-import { Thread } from '../../../generated/entity/feed/thread';
-import { getEntityField, getEntityFQN } from '../../../utils/FeedUtils';
-import { showErrorToast } from '../../../utils/ToastUtils';
-import { ConfirmState } from '../ActivityFeedCard/ActivityFeedCard.interface';
-import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor';
-import DeleteConfirmationModal from '../DeleteConfirmationModal/DeleteConfirmationModal';
-import { ActivityFeedPanelProp } from './ActivityFeedPanel.interface';
-import FeedPanelBody from './FeedPanelBody';
-import FeedPanelHeader from './FeedPanelHeader';
-
-const ActivityFeedPanel: FC = ({
- open,
- selectedThread,
- onCancel,
- className,
- postFeed,
- deletePostHandler,
- updateThreadHandler,
-}) => {
- const { t } = useTranslation();
- const [threadData, setThreadData] = useState(selectedThread);
- const [isLoading, setIsLoading] = useState(false);
- const entityField = getEntityField(selectedThread.about);
- const entityFQN = getEntityFQN(selectedThread.about);
-
- const [confirmationState, setConfirmationState] = useState(
- confirmStateInitialValue
- );
-
- const onDiscard = () => {
- setConfirmationState(confirmStateInitialValue);
- };
-
- const onPostDelete = () => {
- if (confirmationState.postId && confirmationState.threadId) {
- deletePostHandler?.(
- confirmationState.threadId,
- confirmationState.postId,
- confirmationState.isThread
- );
- }
- onDiscard();
- };
-
- const onConfirmation = (data: ConfirmState) => {
- setConfirmationState(data);
- };
-
- useEffect(() => {
- getFeedById(selectedThread.id)
- .then((res) => {
- setThreadData(res.data);
- })
- .catch((err: AxiosError) => {
- showErrorToast(
- err,
- t('server.entity-fetch-error', {
- entity: t('label.message-plural-lowercase'),
- })
- );
- })
- .finally(() => setIsLoading(false));
- }, [selectedThread]);
-
- return (
-
- }
- width={576}
- onClose={onCancel}>
-
-
-
- );
-};
-
-export default ActivityFeedPanel;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelBodyV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelBodyV1.tsx
index 0b756f699e6..34c5164366c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelBodyV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelBodyV1.tsx
@@ -13,7 +13,7 @@
import classNames from 'classnames';
import { Post, Thread, ThreadType } from 'generated/entity/feed/thread';
-import React, { FC } from 'react';
+import React, { FC, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { getReplyText } from '../../../utils/FeedUtils';
import ActivityFeedCardV1 from '../ActivityFeedCard/ActivityFeedCardV1';
@@ -24,6 +24,9 @@ interface FeedPanelBodyPropV1 {
className?: string;
showThread?: boolean;
isOpenInDrawer?: boolean;
+ onFeedClick?: (feed: Thread) => void;
+ isActive?: boolean;
+ hidePopover: boolean;
}
const FeedPanelBodyV1: FC = ({
@@ -31,6 +34,9 @@ const FeedPanelBodyV1: FC = ({
className,
showThread = true,
isOpenInDrawer = false,
+ onFeedClick,
+ isActive,
+ hidePopover = false,
}) => {
const { t } = useTranslation();
const mainFeed = {
@@ -42,15 +48,22 @@ const FeedPanelBodyV1: FC = ({
} as Post;
const postLength = feed?.posts?.length ?? 0;
+ const handleFeedClick = useCallback(() => {
+ onFeedClick && onFeedClick(feed);
+ }, [onFeedClick, feed]);
+
return (
0,
})}
- data-testid="message-container">
+ data-testid="message-container"
+ onClick={handleFeedClick}>
{feed.type === ThreadType.Task ? (
= ({
) : (
= ({
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.test.tsx
index 0a596df83f9..1d4a2efae34 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.test.tsx
@@ -40,13 +40,11 @@ describe('Test FeedPanelHeader Component', () => {
'add-new-conversation'
);
const drawerCloseButton = await findByTestId(container, 'closeDrawer');
- const bottomSeparator = await findByTestId(container, 'bottom-separator');
expect(title).toBeInTheDocument();
expect(noun).toHaveTextContent('Conversations label.on-lowercase');
expect(newConversationButton).toBeInTheDocument();
expect(drawerCloseButton).toBeInTheDocument();
- expect(bottomSeparator).toBeInTheDocument();
});
it('Check if FeedPanelHeader has onShowNewConversation as undefined', async () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.tsx
index dbea7c395fa..b8a350d6a44 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedPanel/FeedPanelHeader.tsx
@@ -20,6 +20,7 @@ import {
getFeedPanelHeaderText,
} from '../../../utils/FeedUtils';
import { FeedPanelHeaderProp } from './ActivityFeedPanel.interface';
+
const FeedPanelHeader: FC = ({
onCancel,
entityField,
@@ -28,12 +29,13 @@ const FeedPanelHeader: FC = ({
onShowNewConversation,
threadType,
entityFQN = '',
+ hideCloseIcon = false,
}) => {
const { t } = useTranslation();
return (
-
+
{noun ? noun : getFeedPanelHeaderText(threadType)}{' '}
@@ -62,24 +64,25 @@ const FeedPanelHeader: FC = ({
/>
) : null}
-
+ {hideCloseIcon ? null : (
+
+ )}
-
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider.tsx
index 6992e8963ea..5866f48ba6c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider.tsx
@@ -12,6 +12,7 @@
*/
import AppState from 'AppState';
import { AxiosError } from 'axios';
+import { EntityType } from 'enums/entity.enum';
import { FeedFilter } from 'enums/mydata.enum';
import { ReactionOperation } from 'enums/reactions.enum';
import { compare, Operation } from 'fast-json-patch';
@@ -22,6 +23,7 @@ import {
Thread,
ThreadType,
} from 'generated/entity/feed/thread';
+import { Paging } from 'generated/type/paging';
import { isEqual } from 'lodash';
import React, {
createContext,
@@ -35,14 +37,16 @@ import { useTranslation } from 'react-i18next';
import {
deletePostById,
deleteThread,
+ getAllFeeds,
getFeedById,
- getFeedsWithFilter,
postFeedById,
updatePost,
updateThread,
} from 'rest/feedsAPI';
+import { getEntityFeedLink } from 'utils/EntityUtils';
import { getUpdatedThread } from 'utils/FeedUtils';
import { showErrorToast } from 'utils/ToastUtils';
+import ActivityFeedDrawer from '../ActivityFeedDrawer/ActivityFeedDrawer';
import { ActivityFeedProviderContextType } from './ActivityFeedProviderContext.interface';
interface Props {
@@ -56,6 +60,7 @@ export const ActivityFeedContext = createContext(
const ActivityFeedProvider = ({ children }: Props) => {
const { t } = useTranslation();
const [entityThread, setEntityThread] = useState([]);
+ const [entityPaging, setEntityPaging] = useState({} as Paging);
const [focusReplyEditor, setFocusReplyEditor] = useState(false);
const [loading, setLoading] = useState(false);
const [isDrawerLoading, setIsDrawerLoading] = useState(false);
@@ -67,7 +72,7 @@ const ActivityFeedProvider = ({ children }: Props) => {
[AppState.userDetails, AppState.nonSecureUserDetails]
);
- const setActiveThread = useCallback((active: Thread) => {
+ const setActiveThread = useCallback((active?: Thread) => {
setSelectedThread(active);
}, []);
@@ -89,20 +94,35 @@ const ActivityFeedProvider = ({ children }: Props) => {
}, []);
const getFeedData = useCallback(
- async (filterType?: FeedFilter, after?: string, type?: ThreadType) => {
+ async (
+ filterType?: FeedFilter,
+ after?: string,
+ type?: ThreadType,
+ entityType?: EntityType,
+ fqn?: string
+ ) => {
try {
setLoading(true);
const feedFilterType = filterType ?? FeedFilter.ALL;
const userId =
feedFilterType === FeedFilter.ALL ? undefined : currentUser?.id;
- const { data } = await getFeedsWithFilter(
- userId,
- feedFilterType,
+ const { data, paging } = await getAllFeeds(
+ entityType !== EntityType.USER_NAME
+ ? getEntityFeedLink(entityType, fqn)
+ : undefined,
after,
- type
+ type,
+ feedFilterType,
+ undefined,
+ userId
);
setEntityThread([...data]);
+ setEntityPaging(paging);
+
+ setLoading(false);
+
+ return data;
} catch (err) {
showErrorToast(
err as AxiosError,
@@ -110,6 +130,8 @@ const ActivityFeedProvider = ({ children }: Props) => {
entity: t('label.activity-feed'),
})
);
+
+ return [];
} finally {
setLoading(false);
}
@@ -336,6 +358,8 @@ const ActivityFeedProvider = ({ children }: Props) => {
showDrawer,
hideDrawer,
updateEditorFocus,
+ setActiveThread,
+ entityPaging,
};
}, [
entityThread,
@@ -353,11 +377,18 @@ const ActivityFeedProvider = ({ children }: Props) => {
showDrawer,
hideDrawer,
updateEditorFocus,
+ setActiveThread,
+ entityPaging,
]);
return (
{children}
+ {isDrawerOpen && (
+ <>
+
+ >
+ )}
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProviderContext.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProviderContext.interface.ts
index 385bc24b7d9..7e4382dc0b2 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProviderContext.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedProvider/ActivityFeedProviderContext.interface.ts
@@ -10,6 +10,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import { EntityType } from 'enums/entity.enum';
import { FeedFilter } from 'enums/mydata.enum';
import { ReactionOperation } from 'enums/reactions.enum';
import { Operation } from 'fast-json-patch';
@@ -19,6 +20,7 @@ import {
Thread,
ThreadType,
} from 'generated/entity/feed/thread';
+import { Paging } from 'generated/type/paging';
export interface ActivityFeedProviderContextType {
loading: boolean;
@@ -27,6 +29,8 @@ export interface ActivityFeedProviderContextType {
selectedThread: Thread | undefined;
isDrawerOpen: boolean;
focusReplyEditor: boolean;
+ entityPaging: Paging;
+ setActiveThread: (thread?: Thread) => void;
deleteFeed: (
threadId: string,
postId: string,
@@ -43,8 +47,10 @@ export interface ActivityFeedProviderContextType {
getFeedData: (
filterType?: FeedFilter,
after?: string,
- type?: ThreadType
- ) => Promise;
+ type?: ThreadType,
+ entityType?: EntityType,
+ fqn?: string
+ ) => Promise;
showDrawer: (thread: Thread) => void;
hideDrawer: () => void;
updateEditorFocus: (isFocused: boolean) => void;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx
new file mode 100644
index 00000000000..722e53a60a9
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component.tsx
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Menu, Typography } from 'antd';
+import AppState from 'AppState';
+import classNames from 'classnames';
+import Loader from 'components/Loader/Loader';
+import { TaskTab } from 'components/Task/TaskTab/TaskTab.component';
+import { pagingObject } from 'constants/constants';
+import { observerOptions } from 'constants/Mydata.constants';
+import { EntityTabs, EntityType } from 'enums/entity.enum';
+import { FeedFilter } from 'enums/mydata.enum';
+import {
+ Thread,
+ ThreadTaskStatus,
+ ThreadType,
+} from 'generated/entity/feed/thread';
+import { Paging } from 'generated/type/paging';
+import { useElementInView } from 'hooks/useElementInView';
+import { noop } from 'lodash';
+import {
+ default as React,
+ RefObject,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { useTranslation } from 'react-i18next';
+import { useHistory, useParams } from 'react-router-dom';
+import { getAllFeeds, getFeedCount } from 'rest/feedsAPI';
+import { getCountBadge, getEntityDetailLink } from 'utils/CommonUtils';
+import { ENTITY_LINK_SEPARATOR, getEntityFeedLink } from 'utils/EntityUtils';
+import { getEntityField } from 'utils/FeedUtils';
+import '../../Widgets/FeedsWidget/feeds-widget.less';
+import ActivityFeedEditor from '../ActivityFeedEditor/ActivityFeedEditor';
+import ActivityFeedListV1 from '../ActivityFeedList/ActivityFeedListV1.component';
+import FeedPanelBodyV1 from '../ActivityFeedPanel/FeedPanelBodyV1';
+import FeedPanelHeader from '../ActivityFeedPanel/FeedPanelHeader';
+import { useActivityFeedProvider } from '../ActivityFeedProvider/ActivityFeedProvider';
+import './activity-feed-tab.less';
+import {
+ ActivityFeedTabProps,
+ ActivityFeedTabs,
+} from './ActivityFeedTab.interface';
+import { ReactComponent as CheckIcon } from '/assets/svg/ic-check.svg';
+import { ReactComponent as TaskIcon } from '/assets/svg/ic-task.svg';
+
+export const ActivityFeedTab = ({
+ fqn,
+ owner,
+ tags,
+ description,
+ columns,
+ entityType,
+}: ActivityFeedTabProps) => {
+ const [paging] = useState(pagingObject);
+ const history = useHistory();
+ const { t } = useTranslation();
+ const [elementRef, isInView] = useElementInView(observerOptions);
+ const { subTab: activeTab = 'all' } =
+ useParams<{ subTab: ActivityFeedTabs }>();
+ const [taskFilter, setTaskFilter] = useState<'open' | 'close'>('open');
+ const [allCount, setAllCount] = useState(0);
+ const [tasksCount, setTasksCount] = useState(0);
+
+ const currentUser = useMemo(
+ () => AppState.getCurrentUserDetails(),
+ [AppState.userDetails, AppState.nonSecureUserDetails]
+ );
+
+ const {
+ postFeed,
+ selectedThread,
+ setActiveThread,
+ entityThread,
+ getFeedData,
+ loading,
+ entityPaging,
+ } = useActivityFeedProvider();
+
+ const isUserEntity = useMemo(
+ () => entityType === EntityType.USER_NAME,
+ [entityType]
+ );
+
+ const entityTypeTask = useMemo(
+ () =>
+ selectedThread?.about?.split(ENTITY_LINK_SEPARATOR)?.[1] as Exclude<
+ EntityType,
+ EntityType.TABLE
+ >,
+ [selectedThread]
+ );
+
+ const handleTabChange = (subTab: string) => {
+ history.push(
+ getEntityDetailLink(entityType, fqn, EntityTabs.ACTIVITY_FEED, subTab)
+ );
+ setActiveThread();
+ };
+
+ const fetchFeedsCount = () => {
+ if (!isUserEntity) {
+ // To get conversation count
+ getFeedCount(
+ getEntityFeedLink(entityType, fqn),
+ ThreadType.Conversation
+ ).then((res) => {
+ if (res) {
+ setAllCount(res.totalCount);
+ } else {
+ throw t('server.entity-feed-fetch-error');
+ }
+ });
+
+ // To get open tasks count
+ getFeedCount(getEntityFeedLink(entityType, fqn), ThreadType.Task).then(
+ (res) => {
+ if (res) {
+ setTasksCount(res.totalCount);
+ } else {
+ throw t('server.entity-feed-fetch-error');
+ }
+ }
+ );
+ } else {
+ if (activeTab !== ActivityFeedTabs.TASKS) {
+ // count for task on userProfile page
+ getAllFeeds(
+ undefined,
+ undefined,
+ ThreadType.Task,
+ FeedFilter.OWNER,
+ undefined,
+ currentUser?.id
+ ).then((res) => {
+ if (res) {
+ setTasksCount(res.paging.total);
+ } else {
+ throw t('server.entity-feed-fetch-error');
+ }
+ });
+ }
+
+ if (activeTab !== ActivityFeedTabs.ALL) {
+ // count for all on userProfile page
+ getAllFeeds(
+ undefined,
+ undefined,
+ ThreadType.Conversation,
+ FeedFilter.OWNER,
+ undefined,
+ currentUser?.id
+ ).then((res) => {
+ if (res) {
+ setAllCount(res.paging.total);
+ } else {
+ throw t('server.entity-feed-fetch-error');
+ }
+ });
+ }
+ }
+ };
+
+ useEffect(() => {
+ fetchFeedsCount();
+ }, []);
+
+ useEffect(() => {
+ if (isUserEntity && activeTab === ActivityFeedTabs.ALL && !allCount) {
+ setAllCount(entityPaging.total);
+ }
+ if (isUserEntity && activeTab === ActivityFeedTabs.TASKS && !tasksCount) {
+ setTasksCount(entityPaging.total);
+ }
+ });
+
+ const { feedFilter, threadType } = useMemo(() => {
+ return {
+ threadType:
+ activeTab === 'tasks' ? ThreadType.Task : ThreadType.Conversation,
+ feedFilter:
+ activeTab === 'mentions'
+ ? FeedFilter.MENTIONS
+ : EntityType.USER_NAME === entityType
+ ? FeedFilter.OWNER
+ : undefined,
+ };
+ }, [activeTab]);
+
+ const handleFeedFetchFromFeedList = useCallback(
+ (after?: string) => {
+ getFeedData(feedFilter, after, threadType, entityType, fqn);
+ },
+ [threadType, feedFilter]
+ );
+
+ useEffect(() => {
+ getFeedData(feedFilter, undefined, threadType, entityType, fqn);
+ }, [feedFilter, threadType]);
+
+ const handleFeedClick = useCallback(
+ (feed: Thread) => {
+ setActiveThread(feed);
+ },
+ [setActiveThread]
+ );
+
+ const fetchMoreThread = (
+ isElementInView: boolean,
+ pagingObj: Paging,
+ isLoading: boolean
+ ) => {
+ if (isElementInView && pagingObj?.after && !isLoading) {
+ handleFeedFetchFromFeedList(pagingObj.after);
+ }
+ };
+
+ useEffect(() => {
+ fetchMoreThread(isInView, paging, loading);
+ }, [paging, loading, isInView]);
+
+ const loader = useMemo(() => (loading ? : null), [loading]);
+
+ const onSave = (message: string) => {
+ postFeed(message, selectedThread?.id ?? '').catch(() => {
+ // ignore since error is displayed in toast in the parent promise.
+ // Added block for sonar code smell
+ });
+ };
+
+ const entityField = selectedThread
+ ? getEntityField(selectedThread.about)
+ : '';
+
+ const threads = useMemo(() => {
+ if (activeTab === ActivityFeedTabs.TASKS) {
+ return entityThread.filter(
+ (thread) =>
+ taskFilter === 'open'
+ ? thread.task?.status === ThreadTaskStatus.Open
+ : thread.task?.status === ThreadTaskStatus.Closed,
+ []
+ );
+ }
+
+ return entityThread;
+ }, [activeTab, entityThread, taskFilter]);
+
+ const [openTasks, closedTasks] = useMemo(() => {
+ if (activeTab === ActivityFeedTabs.TASKS) {
+ return entityThread.reduce(
+ (acc, curr) => {
+ if (curr.task?.status === ThreadTaskStatus.Open) {
+ acc[0] = acc[0] + 1;
+ } else {
+ acc[1] = acc[1] + 1;
+ }
+
+ return acc;
+ },
+ [0, 0]
+ );
+ }
+
+ return [0, 0];
+ }, [entityThread, activeTab]);
+
+ return (
+
+
+ ),
+ key: 'all',
+ },
+ {
+ label: (
+
+ {t('label.mention-plural')}
+
+ ),
+ key: 'mentions',
+ },
+ {
+ label: (
+
+ {t('label.task-plural')}
+ {getCountBadge(tasksCount)}
+
+ ),
+ key: 'tasks',
+ },
+ ]}
+ mode="inline"
+ selectedKeys={[activeTab]}
+ style={{
+ flex: '0 0 250px',
+ borderRight: '1px solid rgba(0, 0, 0, 0.1)',
+ }}
+ onClick={(info) => handleTabChange(info.key)}
+ />
+
+
+ {activeTab === ActivityFeedTabs.TASKS && (
+
+ {
+ setTaskFilter('open');
+ setActiveThread();
+ }}>
+ {' '}
+ {openTasks}{' '}
+ {t('label.open')}
+
+ {
+ setTaskFilter('close');
+ setActiveThread();
+ }}>
+ {' '}
+ {closedTasks}{' '}
+ {t('label.close')}
+
+
+ )}
+
+
+
+ {loading && loader}
+ {selectedThread &&
+ !loading &&
+ (activeTab !== ActivityFeedTabs.TASKS ? (
+
+ ) : (
+
+ {entityType === EntityType.TABLE ? (
+
+ ) : (
+
+ )}
+
+ ))}
+
+ }
+ />
+ {loader}
+
+ );
+};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface.ts
new file mode 100644
index 00000000000..c299a076f05
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { EntityType } from 'enums/entity.enum';
+import { Column } from 'generated/entity/data/table';
+import { EntityReference } from 'generated/entity/type';
+import { TagLabel } from 'generated/type/tagLabel';
+
+export type FeedKeys = 'all' | 'mentions' | 'tasks';
+
+export enum ActivityFeedTabs {
+ ALL = 'all',
+ MENTIONS = 'mentions',
+ TASKS = 'tasks',
+}
+
+export interface ActivityFeedTabBasicProps {
+ fqn: string;
+ onFeedUpdate: () => void;
+ owner?: EntityReference;
+ tags?: TagLabel[];
+ description?: string;
+}
+
+export type ActivityFeedTabProps = ActivityFeedTabBasicProps &
+ (
+ | {
+ columns?: Column[];
+ entityType: EntityType.TABLE;
+ }
+ | { columns?: undefined; entityType: Exclude }
+ );
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.less b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/activity-feed-tab.less
similarity index 63%
rename from openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.less
rename to openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/activity-feed-tab.less
index 8c4cef33efc..d88a44ec4a9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListBody.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedTab/activity-feed-tab.less
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Collate.
+ * Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -10,16 +10,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@import url('../../../styles/variables.less');
-@task-card-border: #c6b5f6;
-@announcement-card-border: #ffc143;
-@announcement-background-color: #fffdf8;
-
-.task-feed-card {
- border: 1px solid @task-card-border;
-}
-
-.announcement-feed-card {
- border: 1px solid @announcement-card-border;
- background-color: @announcement-background-color;
+.feed-explore-heading {
+ background-color: @grey-1;
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadList.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadList.tsx
index dc478131ce7..c1ca0f4805f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadList.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/ActivityThreadList.tsx
@@ -68,7 +68,7 @@ const ActivityThreadList: FC = ({
return (
{updatedThreads
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/AnnouncementThreads.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/AnnouncementThreads.tsx
index a372cb7c8a8..e32a6a8f3c4 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/AnnouncementThreads.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityThreadPanel/AnnouncementThreads.tsx
@@ -88,6 +88,8 @@ const AnnouncementThreads: FC
= ({
);
const lastPost = thread?.posts?.[postLength - 1];
+ // ashish
+
return (
(false);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const {
- isDrawerOpen,
deleteFeed,
showDrawer,
hideDrawer,
@@ -110,9 +110,8 @@ const ActivityFeedActions = ({
});
const onReply = () => {
- if (!isDrawerOpen) {
- showDrawer(feed);
- }
+ showDrawer(feed);
+
updateEditorFocus(true);
};
@@ -121,7 +120,7 @@ const ActivityFeedActions = ({
return false;
} else if (feed.type === ThreadType.Task && !isPost) {
return false;
- } else if (isAuthor || currentUser?.isAdmin) {
+ } else if (isAuthor) {
return true;
}
@@ -129,19 +128,19 @@ const ActivityFeedActions = ({
}, [post, feed, currentUser]);
const deleteCheck = useMemo(() => {
- return isAuthor || currentUser?.isAdmin;
+ if (feed.type === ThreadType.Task && !isPost) {
+ return false;
+ } else if (isAuthor || currentUser?.isAdmin) {
+ return true;
+ }
+
+ return false;
}, [post, feed, isAuthor, currentUser]);
return (
<>
-
-
}
- size="small"
- />
-
-
+
+ {feed.type !== ThreadType.Task && !isPost && (
}
size="small"
type="text"
- onClick={(e) => e.stopPropagation()}>
-
-
+ onClick={(e) => e.stopPropagation()}
+ />
+ )}
- {!isPost && (
-
- )}
+ {!isPost && (
+ }
+ size="small"
+ type="text"
+ onClick={onReply}
+ />
+ )}
- {editCheck && (
- }
- size="small"
- title={t('label.edit')}
- type="text"
- onClick={onEditPost}
- />
- )}
+ {editCheck && (
+ }
+ size="small"
+ title={t('label.edit')}
+ type="text"
+ onClick={onEditPost}
+ />
+ )}
- {deleteCheck && (
- }
- size="small"
- title={t('label.delete')}
- type="text"
- onClick={() => setShowDeleteDialog(true)}
- />
- )}
-
-
+ {deleteCheck && (
+ }
+ size="small"
+ title={t('label.delete')}
+ type="text"
+ onClick={() => setShowDeleteDialog(true)}
+ />
+ )}
+ {/* */}
+
{
@@ -21,12 +22,11 @@ const AnnouncementBadge = () => {
return (
-
-
{t('label.announcement')}
+
+
+
+ {t('label.announcement')}
+
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/Badge.less b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/Badge.less
index 0a29aa46466..6a1ccb3133b 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/Badge.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/Badge.less
@@ -10,18 +10,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@background: #fffdf8;
-@border: #ffc143;
-@text: #37352f;
-@primary: #7147e8;
+
+@import url('../../../styles/variables.less');
.announcement-badge-container {
position: absolute;
top: -12px;
left: 16px;
- background: @background;
+ background: @announcement-background-dark;
border-radius: 4px;
- border: 1px solid @border;
+ border: 1px solid @announcement-border;
padding: 0 8px;
display: flex;
align-items: center;
@@ -31,14 +29,7 @@
.announcement-badge {
width: 14px;
height: 14px;
- background: @background;
-}
-
-.announcement-content {
- font-size: 12px;
- margin-left: 5px;
- color: @text;
- font-weight: 500;
+ color: @announcement-border;
}
.task-badge {
@@ -50,6 +41,6 @@
border: 1px solid #c6b5f6;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.06);
border-radius: 4px;
- color: @primary;
+ color: @primary-color;
font-size: 12px;
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/activity-feed-actions.less b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/activity-feed-actions.less
new file mode 100644
index 00000000000..72fe66c7162
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/Shared/activity-feed-actions.less
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@import url('../../../styles/variables.less');
+
+.feed-actions {
+ position: absolute;
+ right: 10px;
+ top: -12px;
+ transition: width 0.3s;
+ background: @white;
+ border: 1px solid @border-color;
+ padding: 4px 8px;
+ border-radius: 6px;
+ display: none;
+}
+
+.toolbar-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/TaskFeedCard/TaskFeedCard.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/TaskFeedCard/TaskFeedCard.component.tsx
index 4c1d3b7e4ea..b07f64b06ea 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/TaskFeedCard/TaskFeedCard.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/TaskFeedCard/TaskFeedCard.component.tsx
@@ -10,16 +10,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import Icon from '@ant-design/icons';
import { Col, Row, Tooltip, Typography } from 'antd';
import classNames from 'classnames';
import AssigneeList from 'components/common/AssigneeList/AssigneeList';
import EntityPopOverCard from 'components/common/PopOverCard/EntityPopOverCard';
import UserPopOverCard from 'components/common/PopOverCard/UserPopOverCard';
import ProfilePicture from 'components/common/ProfilePicture/ProfilePicture';
-import Reactions from 'components/Reactions/Reactions';
-import { ReactionOperation } from 'enums/reactions.enum';
-import { Post, ReactionType, Thread } from 'generated/entity/feed/thread';
-import { isUndefined, toString } from 'lodash';
+import { Post, Thread, ThreadTaskStatus } from 'generated/entity/feed/thread';
+import { isUndefined, noop } from 'lodash';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
@@ -30,7 +29,6 @@ import {
getEntityType,
prepareFeedLink,
} from 'utils/FeedUtils';
-import { getTaskDetailPath } from 'utils/TasksUtils';
import {
getDateTimeFromMilliSeconds,
getDayTimeByTimeStamp,
@@ -38,6 +36,7 @@ import {
import { useActivityFeedProvider } from '../ActivityFeedProvider/ActivityFeedProvider';
import ActivityFeedActions from '../Shared/ActivityFeedActions';
import './task-feed-card.less';
+import { ReactComponent as TaskCloseIcon } from '/assets/svg/ic-close-task.svg';
import { ReactComponent as TaskOpenIcon } from '/assets/svg/ic-open-task.svg';
import { ReactComponent as ThreadIcon } from '/assets/svg/thread.svg';
@@ -48,6 +47,8 @@ interface TaskFeedCardProps {
showThread?: boolean;
isEntityFeed?: boolean;
isOpenInDrawer?: boolean;
+ isActive?: boolean;
+ hidePopover: boolean;
}
const TaskFeedCard = ({
@@ -56,7 +57,8 @@ const TaskFeedCard = ({
className = '',
isEntityFeed = false,
showThread = true,
- isOpenInDrawer = false,
+ isActive,
+ hidePopover = false,
}: TaskFeedCardProps) => {
const { t } = useTranslation();
const timeStamp = feed.threadTs;
@@ -69,7 +71,7 @@ const TaskFeedCard = ({
const repliedUsers = [...new Set((feed?.posts ?? []).map((f) => f.from))];
const repliedUniqueUsersList = repliedUsers.slice(0, postLength >= 3 ? 2 : 1);
- const { showDrawer, updateReactions } = useActivityFeedProvider();
+ const { showDrawer } = useActivityFeedProvider();
const showReplies = () => {
showDrawer?.(feed);
@@ -79,21 +81,9 @@ const TaskFeedCard = ({
setIsEditPost(!isEditPost);
};
- const onReactionUpdate = (
- reaction: ReactionType,
- operation: ReactionOperation
- ) => {
- updateReactions(post, feed.id, true, reaction, operation);
- };
-
const getTaskLinkElement = entityCheck && (
- e.stopPropagation()}>
- {`#${taskDetails?.id} `}
-
+ {`#${taskDetails?.id} `}
{taskDetails?.type}
{t('label.for-lowercase')}
@@ -123,93 +113,98 @@ const TaskFeedCard = ({
-
-
-
-
- {getTaskLinkElement}
-
-
-
-
- {feed.createdBy}
-
- {t('message.created-this-task-lowercase')}
- {timeStamp && (
-
-
- {getDayTimeByTimeStamp(timeStamp)}
-
-
- )}
-
-
-
-
-
- {t('label.assignee-plural')}
-
+
-
-
- {!showThread && postLength > 0 && (
-
-
+ {getTaskLinkElement}
+
+
+
+
+ {feed.createdBy}
+
+ {t('message.created-this-task-lowercase')}
+ {timeStamp && (
+
+
+ {getDayTimeByTimeStamp(timeStamp)}
+
+
+ )}
+
+
+ {!showThread ? (
+
-
- {repliedUniqueUsersList.map((user) => (
-
-
-
-
-
- ))}
-
-
- {' '}
- {postLength}
-
- {Boolean(feed.reactions?.length) && (
-
+ {postLength > 0 && (
+ <>
+
+ {repliedUniqueUsersList.map((user) => (
+
+
+
+
+
+ ))}
+
+
+ {' '}
+ {postLength}
+
+ >
)}
+
+
0
+ ? 'm-l-sm text-sm text-grey-muted'
+ : 'text-sm text-grey-muted'
+ }>
+ {`${t('label.assignee-plural')}: `}
+
+
-
- )}
+ ) : null}
+
-
+ {!hidePopover && (
+
+ )}
>
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTest.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTest.interface.ts
index db6461a43ca..f3256705fe1 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTest.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTest.interface.ts
@@ -38,6 +38,7 @@ export interface TestCaseFormProps {
export interface TestSuiteIngestionProps {
testSuite: TestSuite;
ingestionPipeline?: IngestionPipeline;
+ table?: Table;
onCancel: () => void;
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTestV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTestV1.tsx
index 85a408f57d0..cfbef99b67e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTestV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/AddDataQualityTestV1.tsx
@@ -11,43 +11,33 @@
* limitations under the License.
*/
-import { Col, Row, Typography } from 'antd';
+import { Card, Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
+import ResizablePanels from 'components/common/ResizablePanels/ResizablePanels';
import { HTTP_STATUS_CODE } from 'constants/auth.constants';
import { CreateTestCase } from 'generated/api/tests/createTestCase';
import { t } from 'i18next';
-import { isUndefined, toString } from 'lodash';
+import { isUndefined } from 'lodash';
import { default as React, useCallback, useMemo, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
-import { createTestCase, createTestSuites } from 'rest/testAPI';
+import { createExecutableTestSuite, createTestCase } from 'rest/testAPI';
import { getEntityBreadcrumbs, getEntityName } from 'utils/EntityUtils';
import { getTableTabPath } from '../../constants/constants';
import { STEPS_FOR_ADD_TEST_CASE } from '../../constants/profiler.constant';
-import { EntityType, FqnPart } from '../../enums/entity.enum';
+import { EntityType } from '../../enums/entity.enum';
import { FormSubmitType } from '../../enums/form.enum';
-import { PageLayoutType } from '../../enums/layout.enum';
import { ProfilerDashboardType } from '../../enums/table.enum';
import { OwnerType } from '../../enums/user.enum';
import { TestCase } from '../../generated/tests/testCase';
import { TestSuite } from '../../generated/tests/testSuite';
-import {
- getCurrentUserId,
- getPartialNameFromTableFQN,
-} from '../../utils/CommonUtils';
-import { getTestSuitePath } from '../../utils/RouterUtils';
-import { getDecodedFqn } from '../../utils/StringsUtils';
+import { getCurrentUserId } from '../../utils/CommonUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import SuccessScreen from '../common/success-screen/SuccessScreen';
import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component';
import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface';
-import PageLayout from '../containers/PageLayout';
import IngestionStepper from '../IngestionStepper/IngestionStepper.component';
-import {
- AddDataQualityTestProps,
- SelectTestSuiteType,
-} from './AddDataQualityTest.interface';
+import { AddDataQualityTestProps } from './AddDataQualityTest.interface';
import RightPanel from './components/RightPanel';
-import SelectTestSuite from './components/SelectTestSuite';
import TestCaseForm from './components/TestCaseForm';
import { addTestSuiteRightPanel, INGESTION_DATA } from './rightPanelData';
import TestSuiteIngestion from './TestSuiteIngestion';
@@ -59,8 +49,6 @@ const AddDataQualityTestV1: React.FC = ({
const isColumnFqn = dashboardType === ProfilerDashboardType.COLUMN;
const history = useHistory();
const [activeServiceStep, setActiveServiceStep] = useState(1);
- const [selectedTestSuite, setSelectedTestSuite] =
- useState();
const [testCaseData, setTestCaseData] = useState();
const [testSuiteData, setTestSuiteData] = useState();
const [testCaseRes, setTestCaseRes] = useState();
@@ -73,95 +61,67 @@ const AddDataQualityTestV1: React.FC = ({
name: getEntityName(table),
url: getTableTabPath(table.fullyQualifiedName || '', 'profiler'),
},
- ];
-
- if (isColumnFqn) {
- const colVal = [
- {
- name: getPartialNameFromTableFQN(getDecodedFqn(entityTypeFQN), [
- FqnPart.NestedColumn,
- ]),
- url: getTableTabPath(table.fullyQualifiedName || '', 'profiler'),
- },
- {
- name: t('label.add-entity-test', { entity: t('label.column') }),
- url: '',
- activeTitle: true,
- },
- ];
- data.push(...colVal);
- } else {
- data.push({
- name: t('label.add-entity-test', { entity: t('label.table') }),
+ {
+ name: t('label.add-entity-test', {
+ entity: isColumnFqn ? t('label.column') : t('label.table'),
+ }),
url: '',
activeTitle: true,
- });
- }
+ },
+ ];
return data;
}, [table, entityTypeFQN, isColumnFqn]);
- const handleViewTestSuiteClick = () => {
- history.push(
- getTestSuitePath(
- selectedTestSuite?.data?.fullyQualifiedName ||
- testSuiteData?.fullyQualifiedName ||
- ''
- )
- );
+ const owner = useMemo(
+ () => ({
+ id: getCurrentUserId(),
+ type: OwnerType.USER,
+ }),
+ [getCurrentUserId]
+ );
+
+ const handleRedirection = () => {
+ history.goBack();
};
- const handleCancelClick = () => {
- setActiveServiceStep((pre) => pre - 1);
- };
+ const getTestSuiteFqn = async () => {
+ try {
+ if (isUndefined(table.testSuite)) {
+ const testSuite = {
+ name: `${table.name}.TestSuite`,
+ executableEntityReference: table.fullyQualifiedName,
+ owner,
+ };
+ const response = await createExecutableTestSuite(testSuite);
+ setTestSuiteData(response);
- const handleTestCaseBack = (testCase: CreateTestCase) => {
- setTestCaseData(testCase);
- handleCancelClick();
- };
+ return response.fullyQualifiedName ?? '';
+ }
+ setTestSuiteData(table.testSuite);
- const handleSelectTestSuite = (data: SelectTestSuiteType) => {
- setSelectedTestSuite(data);
- setActiveServiceStep(2);
+ return table.testSuite?.fullyQualifiedName ?? '';
+ } catch (error) {
+ showErrorToast(error as AxiosError);
+ }
+
+ return '';
};
const handleFormSubmit = async (data: CreateTestCase) => {
setTestCaseData(data);
- if (isUndefined(selectedTestSuite)) {
- return;
- }
+
try {
- const { parameterValues, testDefinition, name, entityLink, description } =
- data;
- const { isNewTestSuite, data: selectedSuite } = selectedTestSuite;
- const owner = {
- id: getCurrentUserId(),
- type: OwnerType.USER,
- };
+ const testSuite = await getTestSuiteFqn();
+
const testCasePayload: CreateTestCase = {
- name,
- description,
- entityLink,
- parameterValues,
+ ...data,
owner,
- testDefinition,
- testSuite: toString(selectedSuite?.fullyQualifiedName),
+ testSuite,
};
- if (isNewTestSuite && isUndefined(testSuiteData)) {
- const testSuitePayload = {
- name: selectedTestSuite.name || '',
- description: selectedTestSuite.description || '',
- owner,
- };
- const testSuiteResponse = await createTestSuites(testSuitePayload);
- testCasePayload.testSuite = testSuiteResponse.fullyQualifiedName || '';
- setTestSuiteData(testSuiteResponse);
- } else if (!isUndefined(testSuiteData)) {
- testCasePayload.testSuite = testSuiteData.fullyQualifiedName || '';
- }
const testCaseResponse = await createTestCase(testCasePayload);
- setActiveServiceStep(3);
+ setActiveServiceStep(2);
setTestCaseRes(testCaseResponse);
} catch (error) {
if (
@@ -187,22 +147,13 @@ const AddDataQualityTestV1: React.FC = ({
const RenderSelectedTab = useCallback(() => {
if (activeServiceStep === 2) {
- return (
-
- );
- } else if (activeServiceStep > 2) {
- const successName = selectedTestSuite?.isNewTestSuite
- ? `${testSuiteData?.name} & ${testCaseRes?.name}`
- : testCaseRes?.name || t('label.test-case') || '';
+ const isNewTestSuite = isUndefined(table.testSuite);
- const successMessage = selectedTestSuite?.isNewTestSuite ? undefined : (
+ const successMessage = isNewTestSuite ? undefined : (
- {`"${successName}"`}
+ {`"${
+ testCaseRes?.name ?? t('label.test-case')
+ }"`}
{`${t('message.has-been-created-successfully')}.`}
@@ -214,9 +165,9 @@ const AddDataQualityTestV1: React.FC = ({
return (
setAddIngestion(true)}
- handleViewServiceClick={handleViewTestSuiteClick}
- name={successName}
- showIngestionButton={selectedTestSuite?.isNewTestSuite || false}
+ handleViewServiceClick={handleRedirection}
+ name={testCaseRes?.name ?? t('label.test-case')}
+ showIngestionButton={isNewTestSuite}
state={FormSubmitType.ADD}
successMessage={successMessage}
viewServiceText={t('message.view-test-suite')}
@@ -225,67 +176,87 @@ const AddDataQualityTestV1: React.FC = ({
}
return (
-
);
}, [activeServiceStep, testCaseRes]);
return (
- }
- layout={PageLayoutType['2ColRTL']}
+
+
+
+ {addIngestion ? (
+ setAddIngestion(false)}
+ />
+ ) : (
+
+
+
+
+ {t('label.add-entity-test', {
+ entity: isColumnFqn
+ ? t('label.column')
+ : t('label.table'),
+ })}
+
+
+
+
+
+ {RenderSelectedTab()}
+
+
+ )}
+
+
+ ),
+ minWidth: 700,
+ flex: 0.7,
+ }}
pageTitle={t('label.add-entity', {
entity: t('label.data-quality-test'),
})}
- rightPanel={
-
- }>
- {addIngestion ? (
- setAddIngestion(false)}
- />
- ) : (
-
-
-
- {t('label.add-entity-test', {
- entity: isColumnFqn ? t('label.column') : t('label.table'),
- })}
-
-
-
-
-
- {RenderSelectedTab()}
-
- )}
-
+ secondPanel={{
+ children: (
+
+ ),
+ className: 'p-md service-doc-panel',
+ minWidth: 60,
+ overlay: {
+ displayThreshold: 200,
+ header: t('label.setup-guide'),
+ rotation: 'counter-clockwise',
+ },
+ }}
+ />
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/TestSuiteIngestion.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/TestSuiteIngestion.tsx
index 38560eebd6c..3d1fc0b6032 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/TestSuiteIngestion.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/TestSuiteIngestion.tsx
@@ -13,7 +13,7 @@
import { Col, Row, Typography } from 'antd';
import { AxiosError } from 'axios';
-import { camelCase, isEmpty } from 'lodash';
+import { isEmpty } from 'lodash';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useParams } from 'react-router-dom';
@@ -48,6 +48,7 @@ import TestSuiteScheduler from './components/TestSuiteScheduler';
const TestSuiteIngestion: React.FC = ({
ingestionPipeline,
+ table,
testSuite,
onCancel,
}) => {
@@ -125,12 +126,13 @@ const TestSuiteIngestion: React.FC = ({
name: `${updatedName}_${PipelineType.TestSuite}`,
pipelineType: PipelineType.TestSuite,
service: {
- id: testSuite.id || '',
- type: camelCase(PipelineType.TestSuite),
+ id: table?.service?.id ?? '',
+ type: table?.service?.type ?? '',
},
sourceConfig: {
config: {
type: ConfigType.TestSuite,
+ entityFullyQualifiedName: table?.fullyQualifiedName,
},
},
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/components/TestCaseForm.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/components/TestCaseForm.tsx
index 7d5de2dc46d..58d713a12a4 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/components/TestCaseForm.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/components/TestCaseForm.tsx
@@ -20,7 +20,10 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { getListTestCase, getListTestDefinitions } from 'rest/testAPI';
import { getEntityName } from 'utils/EntityUtils';
-import { API_RES_MAX_SIZE } from '../../../constants/constants';
+import {
+ API_RES_MAX_SIZE,
+ PAGE_SIZE_LARGE,
+} from '../../../constants/constants';
import { ProfilerDashboardType } from '../../../enums/table.enum';
import {
TestCase,
@@ -32,10 +35,7 @@ import {
TestDefinition,
TestPlatform,
} from '../../../generated/tests/testDefinition';
-import {
- getNameFromFQN,
- replaceAllSpacialCharWith_,
-} from '../../../utils/CommonUtils';
+import { replaceAllSpacialCharWith_ } from '../../../utils/CommonUtils';
import { getDecodedFqn } from '../../../utils/StringsUtils';
import { generateEntityLink } from '../../../utils/TableUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
@@ -83,7 +83,7 @@ const TestCaseForm: React.FC = ({
try {
const { data } = await getListTestCase({
fields: 'testDefinition',
- limit: API_RES_MAX_SIZE,
+ limit: PAGE_SIZE_LARGE,
entityLink: generateEntityLink(decodedEntityFQN, isColumnFqn),
});
@@ -170,22 +170,22 @@ const TestCaseForm: React.FC = ({
const handleValueChange: FormProps['onValuesChange'] = (value) => {
if (value.testTypeId) {
- const testType = testDefinitions.find(
- (test) => test.fullyQualifiedName === value.testTypeId
- );
+ // const testType = testDefinitions.find(
+ // (test) => test.fullyQualifiedName === value.testTypeId
+ // );
setSelectedTestType(value.testTypeId);
- const testCount = testCases.filter((test) =>
- test.name.includes(
- `${getNameFromFQN(decodedEntityFQN)}_${testType?.name}`
- )
- );
+ // const testCount = testCases.filter((test) =>
+ // test.name.includes(
+ // `${getNameFromFQN(decodedEntityFQN)}_${testType?.name}`
+ // )
+ // );
// generating dynamic unique name based on entity_testCase_number
- const name = `${getNameFromFQN(decodedEntityFQN)}_${testType?.name}${
- testCount.length ? `_${testCount.length}` : ''
- }`;
- form.setFieldsValue({
- testName: replaceAllSpacialCharWith_(name),
- });
+ // const name = `${getNameFromFQN(decodedEntityFQN)}_${testType?.name}${
+ // testCount.length ? `_${testCount.length}` : ''
+ // }`;
+ // form.setFieldsValue({
+ // testName: replaceAllSpacialCharWith_(name),
+ // });
}
};
@@ -197,9 +197,7 @@ const TestCaseForm: React.FC = ({
fetchAllTestCases();
}
form.setFieldsValue({
- testName: replaceAllSpacialCharWith_(
- initialValue?.name ?? getNameFromFQN(decodedEntityFQN)
- ),
+ testName: replaceAllSpacialCharWith_(initialValue?.name ?? ''),
testTypeId: initialValue?.testDefinition,
params: initialValue?.parameterValues?.length
? getParamsValue()
@@ -215,8 +213,30 @@ const TestCaseForm: React.FC = ({
preserve={false}
onFinish={handleFormSubmit}
onValuesChange={handleValueChange}>
+ {isColumnFqn && (
+
+
+
+ )}
= ({
= ({
{GenerateParamsField()}
-
+
+
{t('label.configure-entity', {
entity: t('label.glossary'),
@@ -88,7 +88,7 @@ const AddGlossary = ({
{t('message.create-new-glossary-guide')}
- >
+
);
const formFields: FieldProp[] = [
@@ -215,76 +215,94 @@ const AddGlossary = ({
};
return (
- }
- layout={PageLayoutType['2ColRTL']}
- pageTitle={t('label.add-entity', { entity: t('label.glossary') })}
- rightPanel={rightPanel}>
-
-
- {header}
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {header}
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ minWidth: 700,
+ flex: 0.7,
+ }}
+ pageTitle={t('label.add-entity', {
+ entity: t('label.glossary'),
+ })}
+ secondPanel={{
+ children: rightPanel,
+ className: 'p-md service-doc-panel',
+ minWidth: 60,
+ overlay: {
+ displayThreshold: 200,
+ header: t('label.setup-guide'),
+ rotation: 'counter-clockwise',
+ },
+ }}
+ />
);
};
export default AddGlossary;
+PageLayoutV1;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddGlossary/AddGlossary.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddGlossary/AddGlossary.test.tsx
index 718263744fa..9e04a566f50 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddGlossary/AddGlossary.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddGlossary/AddGlossary.test.tsx
@@ -15,10 +15,6 @@ import { fireEvent, getByTestId, render } from '@testing-library/react';
import React, { forwardRef } from 'react';
import AddGlossary from './AddGlossary.component';
-jest.mock('../containers/PageLayout', () =>
- jest.fn().mockImplementation(({ children }) =>
{children}
)
-);
-
jest.mock('components/MyData/LeftSidebar/LeftSidebar.component', () =>
jest.fn().mockReturnValue(
Sidebar
)
);
@@ -48,6 +44,15 @@ jest.mock('rest/glossaryAPI', () => ({
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
}));
+jest.mock('components/common/ResizablePanels/ResizablePanels', () =>
+ jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
+ <>
+
{firstPanel.children}
+
{secondPanel.children}
+ >
+ ))
+);
+
const mockOnCancel = jest.fn();
const mockOnSave = jest.fn();
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddService/Steps/SelectServiceType.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddService/Steps/SelectServiceType.tsx
index 9d378be5c30..6f46baf8efd 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/AddService/Steps/SelectServiceType.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddService/Steps/SelectServiceType.tsx
@@ -13,6 +13,7 @@
import { Badge, Button, Col, Row, Select, Space } from 'antd';
import classNames from 'classnames';
+import { PRIMERY_COLOR } from 'constants/constants';
import { DatabaseServiceType } from 'generated/entity/data/database';
import { PipelineServiceType } from 'generated/entity/services/pipelineService';
import { startCase } from 'lodash';
@@ -141,7 +142,7 @@ const SelectServiceType = ({
) ? (
) : null}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddTestCaseModal/AddTestCaseModal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddTestCaseModal/AddTestCaseModal.component.tsx
new file mode 100644
index 00000000000..c07ced3481d
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/AddTestCaseModal/AddTestCaseModal.component.tsx
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Checkbox, Col, List, Modal, Row, Space, Typography } from 'antd';
+import { AxiosError } from 'axios';
+import Searchbar from 'components/common/searchbar/Searchbar';
+import Loader from 'components/Loader/Loader';
+import { getTableTabPath, PAGE_SIZE_MEDIUM } from 'constants/constants';
+import { SearchIndex } from 'enums/search.enum';
+import { TestCase } from 'generated/tests/testCase';
+import { SearchHitBody } from 'interface/search.interface';
+import VirtualList from 'rc-virtual-list';
+import React, { UIEventHandler, useCallback, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { searchQuery } from 'rest/searchAPI';
+import { addTestCaseToLogicalTestSuite } from 'rest/testAPI';
+import { getNameFromFQN } from 'utils/CommonUtils';
+import { getEntityName } from 'utils/EntityUtils';
+import { getDecodedFqn } from 'utils/StringsUtils';
+import { getEntityFqnFromEntityLink } from 'utils/TableUtils';
+import { showErrorToast } from 'utils/ToastUtils';
+import { AddTestCaseModalProps } from './AddTestCaseModal.interface';
+
+// Todo: need to help from backend guys for ES query
+// export const getQueryFilterToExcludeTest = (testCase: EntityReference[]) => ({
+// query: {
+// bool: {
+// must_not: testCase.map((test) => ({
+// term: {
+// name: test.name,
+// },
+// })),
+// },
+// },
+// });
+
+export const AddTestCaseModal = ({
+ open,
+ onCancel,
+ existingTest,
+ testSuiteId,
+ onSubmit,
+}: AddTestCaseModalProps) => {
+ const { t } = useTranslation();
+ const [searchTerm, setSearchTerm] = useState
('');
+ const [items, setItems] = useState<
+ SearchHitBody[]
+ >([]);
+ const [selectedItems, setSelectedItems] = useState
+ )}
+ >
+ )}
+