mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-07 14:53:28 +00:00
* Fix: #21276 Only 3 Comments Shown by Default in Incident View * fixed failing unit test * addressing comments.
This commit is contained in:
parent
78f523fd13
commit
436df10a7f
@ -365,6 +365,52 @@ test.describe('Activity feed', () => {
|
|||||||
await checkTaskCountInActivityFeed(page, 0, 1);
|
await checkTaskCountInActivityFeed(page, 0, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Replies should be visible in the task feed', async ({ page }) => {
|
||||||
|
const value: TaskDetails = {
|
||||||
|
term: entity2.entity.displayName,
|
||||||
|
assignee: user1.responseData.name,
|
||||||
|
};
|
||||||
|
await redirectToHomePage(page);
|
||||||
|
|
||||||
|
await entity2.visitEntityPage(page);
|
||||||
|
|
||||||
|
await page.getByTestId('request-description').click();
|
||||||
|
|
||||||
|
await createDescriptionTask(page, value);
|
||||||
|
|
||||||
|
// Task 1 - Update Description right panel check
|
||||||
|
const descriptionTask = await page.getByTestId('task-title').innerText();
|
||||||
|
|
||||||
|
expect(descriptionTask).toContain('Request to update description');
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const commentInput = page.locator('[data-testid="comments-input-field"]');
|
||||||
|
commentInput.click();
|
||||||
|
|
||||||
|
await page.fill(
|
||||||
|
'[data-testid="editor-wrapper"] .ql-editor',
|
||||||
|
`Reply message ${i}`
|
||||||
|
);
|
||||||
|
const sendReply = page.waitForResponse('/api/v1/feed/*/posts');
|
||||||
|
await page.getByTestId('send-button').click({ force: true });
|
||||||
|
await sendReply;
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.reload();
|
||||||
|
await page.waitForSelector('[data-testid="loader"]', {
|
||||||
|
state: 'hidden',
|
||||||
|
});
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
await expect(page.getByTestId('feed-reply-card')).toHaveCount(10);
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
await expect(
|
||||||
|
page.locator('.right-container [data-testid="feed-replies"]')
|
||||||
|
).toContainText(`Reply message ${i}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('Open and Closed Task Tab with approve from Task Feed Card', async ({
|
test('Open and Closed Task Tab with approve from Task Feed Card', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { Card, Col, Input, Space, Tooltip, Typography } from 'antd';
|
import { Card, Col, Input, Skeleton, Space, Tooltip, Typography } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
import { isUndefined } from 'lodash';
|
import { isUndefined, orderBy } from 'lodash';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
@ -75,10 +75,10 @@ const ActivityFeedCardNew = ({
|
|||||||
}, [feed.about]);
|
}, [feed.about]);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentUser } = useApplicationStore();
|
const { currentUser } = useApplicationStore();
|
||||||
const { selectedThread, postFeed } = useActivityFeedProvider();
|
const { selectedThread, postFeed, updateFeed, isPostsLoading } =
|
||||||
|
useActivityFeedProvider();
|
||||||
const [showFeedEditor, setShowFeedEditor] = useState<boolean>(false);
|
const [showFeedEditor, setShowFeedEditor] = useState<boolean>(false);
|
||||||
const [isEditPost, setIsEditPost] = useState<boolean>(false);
|
const [isEditPost, setIsEditPost] = useState<boolean>(false);
|
||||||
const { updateFeed } = useActivityFeedProvider();
|
|
||||||
const [, , user] = useUserProfile({
|
const [, , user] = useUserProfile({
|
||||||
permission: true,
|
permission: true,
|
||||||
name: feed.createdBy ?? '',
|
name: feed.createdBy ?? '',
|
||||||
@ -183,6 +183,38 @@ const ActivityFeedCardNew = ({
|
|||||||
setShowFeedEditor(false);
|
setShowFeedEditor(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const posts = useMemo(() => {
|
||||||
|
if (!showThread) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPostsLoading) {
|
||||||
|
return (
|
||||||
|
<Space className="m-y-md" direction="vertical" size={16}>
|
||||||
|
<Skeleton active />
|
||||||
|
<Skeleton active />
|
||||||
|
<Skeleton active />
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const posts = orderBy(feed.posts, ['postTs'], ['desc']);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className="p-l-0 p-r-0" data-testid="feed-replies">
|
||||||
|
{posts.map((reply, index, arr) => (
|
||||||
|
<CommentCard
|
||||||
|
closeFeedEditor={closeFeedEditor}
|
||||||
|
feed={feed}
|
||||||
|
isLastReply={index === arr.length - 1}
|
||||||
|
key={reply.id}
|
||||||
|
post={reply}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}, [feed, showThread, closeFeedEditor, isPostsLoading]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@ -330,22 +362,7 @@ const ActivityFeedCardNew = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showThread && feed?.posts && feed?.posts?.length > 0 && (
|
{posts}
|
||||||
<Col className="p-l-0 p-r-0" data-testid="feed-replies">
|
|
||||||
{feed?.posts
|
|
||||||
?.slice()
|
|
||||||
.sort((a, b) => (b.postTs as number) - (a.postTs as number))
|
|
||||||
.map((reply, index, arr) => (
|
|
||||||
<CommentCard
|
|
||||||
closeFeedEditor={closeFeedEditor}
|
|
||||||
feed={feed}
|
|
||||||
isLastReply={index === arr.length - 1}
|
|
||||||
key={reply.id}
|
|
||||||
post={reply}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -134,6 +134,7 @@ const CommentCard = ({
|
|||||||
className={classNames('d-flex justify-start relative reply-card', {
|
className={classNames('d-flex justify-start relative reply-card', {
|
||||||
'reply-card-border-bottom': !isLastReply,
|
'reply-card-border-bottom': !isLastReply,
|
||||||
})}
|
})}
|
||||||
|
data-testid="feed-reply-card"
|
||||||
onMouseEnter={() => setIsHovered(true)}
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
onMouseLeave={() => setIsHovered(false)}>
|
onMouseLeave={() => setIsHovered(false)}>
|
||||||
<div className="profile-picture m-r-xs">
|
<div className="profile-picture m-r-xs">
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
import { Col, Drawer, Row } from 'antd';
|
import { Col, Drawer, Row } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { Thread, ThreadType } from '../../../generated/entity/feed/thread';
|
import { ThreadType } from '../../../generated/entity/feed/thread';
|
||||||
import FeedPanelBodyV1 from '../ActivityFeedPanel/FeedPanelBodyV1';
|
import FeedPanelBodyV1 from '../ActivityFeedPanel/FeedPanelBodyV1';
|
||||||
import FeedPanelHeader from '../ActivityFeedPanel/FeedPanelHeader';
|
import FeedPanelHeader from '../ActivityFeedPanel/FeedPanelHeader';
|
||||||
import { useActivityFeedProvider } from '../ActivityFeedProvider/ActivityFeedProvider';
|
import { useActivityFeedProvider } from '../ActivityFeedProvider/ActivityFeedProvider';
|
||||||
@ -31,6 +31,10 @@ const ActivityFeedDrawer: FC<ActivityFeedDrawerProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { hideDrawer, selectedThread } = useActivityFeedProvider();
|
const { hideDrawer, selectedThread } = useActivityFeedProvider();
|
||||||
|
|
||||||
|
if (!selectedThread) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
className={classNames('activity-feed-drawer', className)}
|
className={classNames('activity-feed-drawer', className)}
|
||||||
@ -57,7 +61,7 @@ const ActivityFeedDrawer: FC<ActivityFeedDrawerProps> = ({
|
|||||||
showThreadIcon: false,
|
showThreadIcon: false,
|
||||||
showRepliesContainer: false,
|
showRepliesContainer: false,
|
||||||
}}
|
}}
|
||||||
feed={selectedThread as Thread}
|
feed={selectedThread}
|
||||||
hidePopover={false}
|
hidePopover={false}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty, isUndefined } from 'lodash';
|
||||||
import React, { ReactNode, useEffect, useMemo, useState } from 'react';
|
import React, { ReactNode, useEffect, useMemo, useState } from 'react';
|
||||||
import { ReactComponent as FeedEmptyIcon } from '../../../assets/svg/ic-task-empty.svg';
|
import { ReactComponent as FeedEmptyIcon } from '../../../assets/svg/ic-task-empty.svg';
|
||||||
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
|
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
|
||||||
@ -69,11 +69,10 @@ const ActivityFeedListV1New = ({
|
|||||||
}, [feedList]);
|
}, [feedList]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onFeedClick) {
|
const thread = entityThread.find((feed) => feed.id === selectedThread?.id);
|
||||||
onFeedClick(
|
|
||||||
entityThread.find((feed) => feed.id === selectedThread?.id) ??
|
if (onFeedClick && (isUndefined(selectedThread) || isUndefined(thread))) {
|
||||||
entityThread[0]
|
onFeedClick(entityThread[0]);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, [entityThread, selectedThread, onFeedClick]);
|
}, [entityThread, selectedThread, onFeedClick]);
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PAGE_SIZE_LARGE } from '../../../constants/constants';
|
import { PAGE_SIZE_LARGE } from '../../../constants/constants';
|
||||||
|
import { POST_FEED_PAGE_COUNT } from '../../../constants/Feeds.constants';
|
||||||
import { EntityType } from '../../../enums/entity.enum';
|
import { EntityType } from '../../../enums/entity.enum';
|
||||||
import { FeedFilter } from '../../../enums/mydata.enum';
|
import { FeedFilter } from '../../../enums/mydata.enum';
|
||||||
import { ReactionOperation } from '../../../enums/reactions.enum';
|
import { ReactionOperation } from '../../../enums/reactions.enum';
|
||||||
@ -43,6 +44,7 @@ import {
|
|||||||
deleteThread,
|
deleteThread,
|
||||||
getAllFeeds,
|
getAllFeeds,
|
||||||
getFeedById,
|
getFeedById,
|
||||||
|
getPostsFeedById,
|
||||||
postFeedById,
|
postFeedById,
|
||||||
updatePost,
|
updatePost,
|
||||||
updateThread,
|
updateThread,
|
||||||
@ -71,6 +73,9 @@ const ActivityFeedProvider = ({ children, user }: Props) => {
|
|||||||
const [entityPaging, setEntityPaging] = useState<Paging>({} as Paging);
|
const [entityPaging, setEntityPaging] = useState<Paging>({} as Paging);
|
||||||
const [focusReplyEditor, setFocusReplyEditor] = useState<boolean>(false);
|
const [focusReplyEditor, setFocusReplyEditor] = useState<boolean>(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [isPostsLoading, setIsPostsLoading] = useState(false);
|
||||||
|
const [isTestCaseResolutionLoading, setIsTestCaseResolutionLoading] =
|
||||||
|
useState(false);
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||||
const [selectedThread, setSelectedThread] = useState<Thread>();
|
const [selectedThread, setSelectedThread] = useState<Thread>();
|
||||||
const [testCaseResolutionStatus, setTestCaseResolutionStatus] = useState<
|
const [testCaseResolutionStatus, setTestCaseResolutionStatus] = useState<
|
||||||
@ -80,6 +85,7 @@ const ActivityFeedProvider = ({ children, user }: Props) => {
|
|||||||
const { currentUser } = useApplicationStore();
|
const { currentUser } = useApplicationStore();
|
||||||
|
|
||||||
const fetchTestCaseResolution = useCallback(async (id: string) => {
|
const fetchTestCaseResolution = useCallback(async (id: string) => {
|
||||||
|
setIsTestCaseResolutionLoading(true);
|
||||||
try {
|
try {
|
||||||
const { data } = await getListTestCaseIncidentByStateId(id, {
|
const { data } = await getListTestCaseIncidentByStateId(id, {
|
||||||
limit: PAGE_SIZE_LARGE,
|
limit: PAGE_SIZE_LARGE,
|
||||||
@ -90,22 +96,40 @@ const ActivityFeedProvider = ({ children, user }: Props) => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setTestCaseResolutionStatus([]);
|
setTestCaseResolutionStatus([]);
|
||||||
|
} finally {
|
||||||
|
setIsTestCaseResolutionLoading(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchPostsFeed = useCallback(async (active: Thread) => {
|
||||||
|
// If the posts count is greater than the page count, fetch the posts
|
||||||
|
if (
|
||||||
|
active?.postsCount &&
|
||||||
|
active?.postsCount > POST_FEED_PAGE_COUNT &&
|
||||||
|
active?.posts?.length !== active?.postsCount
|
||||||
|
) {
|
||||||
|
setIsPostsLoading(true);
|
||||||
|
try {
|
||||||
|
const { data } = await getPostsFeedById(active.id);
|
||||||
|
setSelectedThread((pre) =>
|
||||||
|
pre?.id === active?.id ? { ...active, posts: data } : pre
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setIsPostsLoading(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setActiveThread = useCallback((active?: Thread) => {
|
const setActiveThread = useCallback((active?: Thread) => {
|
||||||
setSelectedThread(active);
|
setSelectedThread(active);
|
||||||
|
active && fetchPostsFeed(active);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
active &&
|
active &&
|
||||||
active.task?.type === TaskType.RequestTestCaseFailureResolution &&
|
active.task?.type === TaskType.RequestTestCaseFailureResolution &&
|
||||||
active.task?.testCaseResolutionStatusId
|
active.task?.testCaseResolutionStatusId
|
||||||
) {
|
) {
|
||||||
setLoading(true);
|
fetchTestCaseResolution(active.task.testCaseResolutionStatusId);
|
||||||
fetchTestCaseResolution(active.task.testCaseResolutionStatusId).finally(
|
|
||||||
() => {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -408,6 +432,8 @@ const ActivityFeedProvider = ({ children, user }: Props) => {
|
|||||||
selectedThread,
|
selectedThread,
|
||||||
isDrawerOpen,
|
isDrawerOpen,
|
||||||
loading,
|
loading,
|
||||||
|
isPostsLoading,
|
||||||
|
isTestCaseResolutionLoading,
|
||||||
focusReplyEditor,
|
focusReplyEditor,
|
||||||
refreshActivityFeed,
|
refreshActivityFeed,
|
||||||
deleteFeed,
|
deleteFeed,
|
||||||
@ -431,6 +457,8 @@ const ActivityFeedProvider = ({ children, user }: Props) => {
|
|||||||
selectedThread,
|
selectedThread,
|
||||||
isDrawerOpen,
|
isDrawerOpen,
|
||||||
loading,
|
loading,
|
||||||
|
isPostsLoading,
|
||||||
|
isTestCaseResolutionLoading,
|
||||||
focusReplyEditor,
|
focusReplyEditor,
|
||||||
refreshActivityFeed,
|
refreshActivityFeed,
|
||||||
deleteFeed,
|
deleteFeed,
|
||||||
|
@ -26,6 +26,8 @@ import { Paging } from '../../../generated/type/paging';
|
|||||||
|
|
||||||
export interface ActivityFeedProviderContextType {
|
export interface ActivityFeedProviderContextType {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
isPostsLoading?: boolean;
|
||||||
|
isTestCaseResolutionLoading?: boolean;
|
||||||
entityThread: Thread[];
|
entityThread: Thread[];
|
||||||
selectedThread: Thread | undefined;
|
selectedThread: Thread | undefined;
|
||||||
isDrawerOpen: boolean;
|
isDrawerOpen: boolean;
|
||||||
|
@ -294,9 +294,11 @@ export const ActivityFeedTab = ({
|
|||||||
if (!feed && (isTaskActiveTab || isMentionTabSelected)) {
|
if (!feed && (isTaskActiveTab || isMentionTabSelected)) {
|
||||||
setIsFullWidth(false);
|
setIsFullWidth(false);
|
||||||
}
|
}
|
||||||
setActiveThread(feed);
|
if (selectedThread?.id !== feed?.id) {
|
||||||
|
setActiveThread(feed);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[setActiveThread, isTaskActiveTab, isMentionTabSelected]
|
[setActiveThread, isTaskActiveTab, isMentionTabSelected, selectedThread]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -336,17 +336,17 @@ const TaskFeedCard = ({
|
|||||||
width={20}
|
width={20}
|
||||||
onClick={isForFeedTab ? showReplies : undefined}
|
onClick={isForFeedTab ? showReplies : undefined}
|
||||||
/>
|
/>
|
||||||
{feed.posts && feed.posts?.length > 0 && (
|
{feed?.postsCount && feed?.postsCount > 0 && (
|
||||||
<Button
|
<Button
|
||||||
className="posts-length m-r-xss p-0 remove-button-default-styling"
|
className="posts-length m-r-xss p-0 remove-button-default-styling"
|
||||||
data-testid="replies-count"
|
data-testid="replies-count"
|
||||||
type="link"
|
type="link"
|
||||||
onClick={isForFeedTab ? showReplies : undefined}>
|
onClick={isForFeedTab ? showReplies : undefined}>
|
||||||
{t(
|
{t(
|
||||||
feed.posts.length === 1
|
feed.postsCount === 1
|
||||||
? 'label.one-reply'
|
? 'label.one-reply'
|
||||||
: 'label.number-reply-plural',
|
: 'label.number-reply-plural',
|
||||||
{ number: feed.posts.length }
|
{ number: feed.postsCount }
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
@ -33,11 +33,11 @@ import {
|
|||||||
import { useElementInView } from '../../../../hooks/useElementInView';
|
import { useElementInView } from '../../../../hooks/useElementInView';
|
||||||
import { useFqn } from '../../../../hooks/useFqn';
|
import { useFqn } from '../../../../hooks/useFqn';
|
||||||
import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store';
|
import { useTestCaseStore } from '../../../../pages/IncidentManager/IncidentManagerDetailPage/useTestCase.store';
|
||||||
import ActivityFeedListV1 from '../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1.component';
|
import ActivityFeedListV1New from '../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1New.component';
|
||||||
import { useActivityFeedProvider } from '../../../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
import { useActivityFeedProvider } from '../../../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
||||||
import { TaskFilter } from '../../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
import { TaskFilter } from '../../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||||
import Loader from '../../../common/Loader/Loader';
|
import Loader from '../../../common/Loader/Loader';
|
||||||
import { TaskTab } from '../../../Entity/Task/TaskTab/TaskTab.component';
|
import { TaskTabNew } from '../../../Entity/Task/TaskTab/TaskTabNew.component';
|
||||||
import './test-case-incident-tab.style.less';
|
import './test-case-incident-tab.style.less';
|
||||||
|
|
||||||
const TestCaseIncidentTab = () => {
|
const TestCaseIncidentTab = () => {
|
||||||
@ -83,9 +83,11 @@ const TestCaseIncidentTab = () => {
|
|||||||
|
|
||||||
const handleFeedClick = useCallback(
|
const handleFeedClick = useCallback(
|
||||||
(feed: Thread) => {
|
(feed: Thread) => {
|
||||||
setActiveThread(feed);
|
if (selectedThread?.id !== feed?.id) {
|
||||||
|
setActiveThread(feed);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[setActiveThread]
|
[setActiveThread, selectedThread]
|
||||||
);
|
);
|
||||||
|
|
||||||
const loader = useMemo(() => (loading ? <Loader /> : null), [loading]);
|
const loader = useMemo(() => (loading ? <Loader /> : null), [loading]);
|
||||||
@ -140,7 +142,7 @@ const TestCaseIncidentTab = () => {
|
|||||||
className="left-container"
|
className="left-container"
|
||||||
data-testid="left-container"
|
data-testid="left-container"
|
||||||
id="left-container">
|
id="left-container">
|
||||||
<div className="d-flex gap-4 p-sm p-x-lg activity-feed-task">
|
<div className="d-flex gap-4 p-sm p-x-lg">
|
||||||
<Typography.Text
|
<Typography.Text
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'cursor-pointer p-l-xss d-flex items-center',
|
'cursor-pointer p-l-xss d-flex items-center',
|
||||||
@ -164,13 +166,14 @@ const TestCaseIncidentTab = () => {
|
|||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ActivityFeedListV1
|
<ActivityFeedListV1New
|
||||||
hidePopover
|
hidePopover
|
||||||
activeFeedId={selectedThread?.id}
|
activeFeedId={selectedThread?.id}
|
||||||
emptyPlaceholderText={t('message.no-tasks-assigned')}
|
emptyPlaceholderText={t('message.no-tasks-assigned')}
|
||||||
feedList={threads}
|
feedList={threads}
|
||||||
isForFeedTab={false}
|
isForFeedTab={false}
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
|
selectedThread={selectedThread}
|
||||||
showThread={false}
|
showThread={false}
|
||||||
onFeedClick={handleFeedClick}
|
onFeedClick={handleFeedClick}
|
||||||
/>
|
/>
|
||||||
@ -187,7 +190,7 @@ const TestCaseIncidentTab = () => {
|
|||||||
{loader}
|
{loader}
|
||||||
{selectedThread && !loading && (
|
{selectedThread && !loading && (
|
||||||
<div id="task-panel">
|
<div id="task-panel">
|
||||||
<TaskTab
|
<TaskTabNew
|
||||||
entityType={EntityType.TEST_CASE}
|
entityType={EntityType.TEST_CASE}
|
||||||
isForFeedTab={false}
|
isForFeedTab={false}
|
||||||
owners={owners}
|
owners={owners}
|
||||||
|
@ -41,9 +41,9 @@ jest.mock(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.mock('../../../Entity/Task/TaskTab/TaskTab.component', () => {
|
jest.mock('../../../Entity/Task/TaskTab/TaskTabNew.component', () => {
|
||||||
return {
|
return {
|
||||||
TaskTab: jest.fn().mockImplementation(({ onAfterClose }) => (
|
TaskTabNew: jest.fn().mockImplementation(({ onAfterClose }) => (
|
||||||
<div>
|
<div>
|
||||||
TaskTab
|
TaskTab
|
||||||
<button data-testid="close-btn" onClick={onAfterClose}>
|
<button data-testid="close-btn" onClick={onAfterClose}>
|
||||||
@ -57,7 +57,7 @@ jest.mock('../../../common/Loader/Loader', () => {
|
|||||||
return jest.fn().mockImplementation(() => <div>Loader</div>);
|
return jest.fn().mockImplementation(() => <div>Loader</div>);
|
||||||
});
|
});
|
||||||
jest.mock(
|
jest.mock(
|
||||||
'../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1.component',
|
'../../../ActivityFeed/ActivityFeedList/ActivityFeedListV1New.component',
|
||||||
() => {
|
() => {
|
||||||
return jest.fn().mockImplementation(({ onFeedClick }) => (
|
return jest.fn().mockImplementation(({ onFeedClick }) => (
|
||||||
<div>
|
<div>
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
MenuProps,
|
MenuProps,
|
||||||
Row,
|
Row,
|
||||||
Select,
|
Select,
|
||||||
|
Skeleton,
|
||||||
Space,
|
Space,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
@ -35,6 +36,7 @@ import {
|
|||||||
isEqual,
|
isEqual,
|
||||||
isUndefined,
|
isUndefined,
|
||||||
last,
|
last,
|
||||||
|
orderBy,
|
||||||
startCase,
|
startCase,
|
||||||
unionBy,
|
unionBy,
|
||||||
} from 'lodash';
|
} from 'lodash';
|
||||||
@ -163,6 +165,7 @@ export const TaskTabNew = ({
|
|||||||
fetchUpdatedThread,
|
fetchUpdatedThread,
|
||||||
updateTestCaseIncidentStatus,
|
updateTestCaseIncidentStatus,
|
||||||
testCaseResolutionStatus,
|
testCaseResolutionStatus,
|
||||||
|
isPostsLoading,
|
||||||
} = useActivityFeedProvider();
|
} = useActivityFeedProvider();
|
||||||
|
|
||||||
const isTaskDescription = isDescriptionTask(taskDetails?.type as TaskType);
|
const isTaskDescription = isDescriptionTask(taskDetails?.type as TaskType);
|
||||||
@ -1047,6 +1050,34 @@ export const TaskTabNew = ({
|
|||||||
setShowFeedEditor(false);
|
setShowFeedEditor(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const posts = useMemo(() => {
|
||||||
|
if (isPostsLoading) {
|
||||||
|
return (
|
||||||
|
<Space className="m-y-md" direction="vertical" size={16}>
|
||||||
|
<Skeleton active />
|
||||||
|
<Skeleton active />
|
||||||
|
<Skeleton active />
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const posts = orderBy(taskThread.posts, ['postTs'], ['desc']);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Col className="p-l-0 p-r-0" data-testid="feed-replies">
|
||||||
|
{posts.map((reply, index, arr) => (
|
||||||
|
<CommentCard
|
||||||
|
closeFeedEditor={closeFeedEditor}
|
||||||
|
feed={taskThread}
|
||||||
|
isLastReply={index === arr.length - 1}
|
||||||
|
key={reply.id}
|
||||||
|
post={reply}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}, [taskThread, closeFeedEditor, isPostsLoading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
closeFeedEditor();
|
closeFeedEditor();
|
||||||
}, [taskThread.id]);
|
}, [taskThread.id]);
|
||||||
@ -1149,22 +1180,7 @@ export const TaskTabNew = ({
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{taskThread?.posts && taskThread?.posts?.length > 0 && (
|
{posts}
|
||||||
<Col className="p-l-0 p-r-0" data-testid="feed-replies">
|
|
||||||
{taskThread?.posts
|
|
||||||
?.slice()
|
|
||||||
.sort((a, b) => (b.postTs as number) - (a.postTs as number))
|
|
||||||
.map((reply, index, arr) => (
|
|
||||||
<CommentCard
|
|
||||||
closeFeedEditor={closeFeedEditor}
|
|
||||||
feed={taskThread}
|
|
||||||
isLastReply={index === arr.length - 1}
|
|
||||||
key={reply.id}
|
|
||||||
post={reply}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Col>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { Col, Row, Steps, Typography } from 'antd';
|
import { Col, Row, Skeleton, Steps, Typography } from 'antd';
|
||||||
import { last, toLower } from 'lodash';
|
import { last, toLower } from 'lodash';
|
||||||
import React, { ReactNode, useMemo } from 'react';
|
import React, { ReactNode, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -36,7 +36,8 @@ import './task-tab-incident-manager-header.style.less';
|
|||||||
|
|
||||||
const TaskTabIncidentManagerHeaderNew = ({ thread }: { thread: Thread }) => {
|
const TaskTabIncidentManagerHeaderNew = ({ thread }: { thread: Thread }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { testCaseResolutionStatus } = useActivityFeedProvider();
|
const { testCaseResolutionStatus, isTestCaseResolutionLoading } =
|
||||||
|
useActivityFeedProvider();
|
||||||
const testCaseResolutionStepper = useMemo(() => {
|
const testCaseResolutionStepper = useMemo(() => {
|
||||||
const updatedData = [...testCaseResolutionStatus];
|
const updatedData = [...testCaseResolutionStatus];
|
||||||
const lastStatusType = last(
|
const lastStatusType = last(
|
||||||
@ -215,14 +216,18 @@ const TaskTabIncidentManagerHeaderNew = ({ thread }: { thread: Thread }) => {
|
|||||||
)}
|
)}
|
||||||
<Col className="p-l-0" span={24}>
|
<Col className="p-l-0" span={24}>
|
||||||
<div className="task-resolution-steps-container-new">
|
<div className="task-resolution-steps-container-new">
|
||||||
<Steps
|
{isTestCaseResolutionLoading ? (
|
||||||
className="task-resolution-steps w-full"
|
<Skeleton active />
|
||||||
current={testCaseResolutionStatus.length}
|
) : (
|
||||||
data-testid="task-resolution-steps"
|
<Steps
|
||||||
items={testCaseResolutionStepper}
|
className="task-resolution-steps w-full"
|
||||||
labelPlacement="vertical"
|
current={testCaseResolutionStatus.length}
|
||||||
size="small"
|
data-testid="task-resolution-steps"
|
||||||
/>
|
items={testCaseResolutionStepper}
|
||||||
|
labelPlacement="vertical"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -24,6 +24,9 @@ export const teamsLinkRegEx = /\((.+?\/\/.+?)\/(.+?\/.+?\/.+?)\/(.+?)\)/;
|
|||||||
export const entityLinkRegEx = /<#E::([^<>]+?)::([^<>]+?)>/g;
|
export const entityLinkRegEx = /<#E::([^<>]+?)::([^<>]+?)>/g;
|
||||||
export const entityRegex = /<#E::([^<>]+?)::([^<>]+?)\|(\[(.+?)?\]\((.+?)?\))>/;
|
export const entityRegex = /<#E::([^<>]+?)::([^<>]+?)\|(\[(.+?)?\]\((.+?)?\))>/;
|
||||||
|
|
||||||
|
// 3 is the default page count for the post feed in list API
|
||||||
|
export const POST_FEED_PAGE_COUNT = 3;
|
||||||
|
|
||||||
export const ENTITY_URL_MAP = {
|
export const ENTITY_URL_MAP = {
|
||||||
team: 'settings/members/teams',
|
team: 'settings/members/teams',
|
||||||
user: 'users',
|
user: 'users',
|
||||||
|
@ -126,6 +126,12 @@ export const postFeedById = async (id: string, data: Post) => {
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPostsFeedById = async (id: string) => {
|
||||||
|
const response = await APIClient.get<{ data: Post[] }>(`/feed/${id}/posts`);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
export const deletePostById = (threadId: string, postId: string) => {
|
export const deletePostById = (threadId: string, postId: string) => {
|
||||||
return APIClient.delete<Post>(`/feed/${threadId}/posts/${postId}`);
|
return APIClient.delete<Post>(`/feed/${threadId}/posts/${postId}`);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user