From 5ab26a7bef04f29bcb4f7b68149781e18a936ebe Mon Sep 17 00:00:00 2001 From: sailong Date: Mon, 7 Jul 2025 15:05:57 +0800 Subject: [PATCH] refactor(UI):Comment Display Card --- .../web/components/Issues/IssueDetailPage.tsx | 5 +- moon/apps/web/components/MrView/CloseItem.tsx | 42 ++++++ moon/apps/web/components/MrView/MRComment.tsx | 120 ++++++++---------- .../apps/web/components/MrView/MergedItem.tsx | 21 +++ .../apps/web/components/MrView/ReopenItem.tsx | 42 ++++++ .../web/components/MrView/TimelineItems.tsx | 19 +-- .../MrView/components/HandleTime.tsx | 25 ++++ .../MrView/components/UserLinkByName.tsx | 18 +++ .../web/hooks/issues/useGetIssueDetail.ts | 4 +- moon/apps/web/pages/[org]/mr/[id].tsx | 12 +- 10 files changed, 225 insertions(+), 83 deletions(-) create mode 100644 moon/apps/web/components/MrView/CloseItem.tsx create mode 100644 moon/apps/web/components/MrView/MergedItem.tsx create mode 100644 moon/apps/web/components/MrView/ReopenItem.tsx create mode 100644 moon/apps/web/components/MrView/components/HandleTime.tsx create mode 100644 moon/apps/web/components/MrView/components/UserLinkByName.tsx diff --git a/moon/apps/web/components/Issues/IssueDetailPage.tsx b/moon/apps/web/components/Issues/IssueDetailPage.tsx index f23fa9ee4..3c1e7fe4d 100644 --- a/moon/apps/web/components/Issues/IssueDetailPage.tsx +++ b/moon/apps/web/components/Issues/IssueDetailPage.tsx @@ -27,10 +27,11 @@ interface IssueDetail { } interface Conversation { id: number - user_id: number conv_type: string comment: string - created_at: number + created_at: number, + updated_at: number, + username: string, } interface detailRes { diff --git a/moon/apps/web/components/MrView/CloseItem.tsx b/moon/apps/web/components/MrView/CloseItem.tsx new file mode 100644 index 000000000..8fa6f075f --- /dev/null +++ b/moon/apps/web/components/MrView/CloseItem.tsx @@ -0,0 +1,42 @@ +import { ConditionalWrap } from '@gitmono/ui' +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' +import { Conversation } from '@/pages/[org]/mr/[id]' +import { MemberHovercard } from '../InlinePost/MemberHovercard' +import { MemberAvatar } from '../MemberAvatar' +import { UserLinkByName } from './components/UserLinkByName' +import HandleTime from './components/HandleTime' + + +interface CloseItemProps { + conv: Conversation +} +const CloseItem = ({ conv }: CloseItemProps) => { + const { data: member } = useGetOrganizationMember({ username: conv.username }) + + return ( + <> +
+
+ ( + + + {c} + + + )} + > + {member ? : 'Avatar not found'} + +
+
{conv.comment}
+
+ +
+
+ + ) +} + +export default CloseItem diff --git a/moon/apps/web/components/MrView/MRComment.tsx b/moon/apps/web/components/MrView/MRComment.tsx index 392d18360..24d2b8dac 100644 --- a/moon/apps/web/components/MrView/MRComment.tsx +++ b/moon/apps/web/components/MrView/MRComment.tsx @@ -1,85 +1,71 @@ -// import { MoreOutlined } from '@ant-design/icons'; -import { NotePlusIcon } from '@gitmono/ui/Icons' -import type { MenuProps } from 'antd' -import { Card, Dropdown } from 'antd/lib' -import { formatDistance, fromUnixTime } from 'date-fns' import { getMarkdownExtensions } from '@gitmono/editor' -import { useDeleteIssueComment } from '@/hooks/issues/useDeleteIssueComment' -import { useDeleteMrCommentDelete } from '@/hooks/useDeleteMrCommentDelete' import { Conversation } from '@/pages/[org]/mr/[id]' import { RichTextRenderer } from '@/components/RichTextRenderer' import { useMemo } from 'react' +import { ConditionalWrap, UIText } from '@gitmono/ui' +import { MemberHovercard } from '../InlinePost/MemberHovercard' +import { MemberAvatar } from '../MemberAvatar' +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' +import { KebabHorizontalIcon } from '@primer/octicons-react' +import { UserLinkByName } from './components/UserLinkByName' +import HandleTime from './components/HandleTime' + interface CommentProps { conv: Conversation id: string whoamI: string } -const Comment = ({ conv, id, whoamI }: CommentProps) => { - const { mutate: deleteComment } = useDeleteMrCommentDelete(id) - const { mutate: deleteIssueComment } = useDeleteIssueComment(id) - const handleDelete = () => { - switch (whoamI) { - case 'issue': - deleteIssueComment(conv.id) - break - case 'mr': - deleteComment(conv.id) - break - default: - return - } - } - - const handleMenuClick: MenuProps['onClick'] = ({ key }) => { - if (key === '3') { - handleDelete() - } - } - - const items: MenuProps['items'] = [ - { - label: 'Edit', - key: '1', - disabled: true - }, - { - label: 'Hide', - key: '2', - disabled: true - }, - { - type: 'divider' - }, - { - label: 'Delete', - key: '3', - danger: true - } - ] - const menuProps = { - items, - onClick: handleMenuClick - } - - const time = formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }) +const Comment = ({ conv }: CommentProps) => { + const { data: member } = useGetOrganizationMember({ username: conv.username }) + const extensions = useMemo(() => getMarkdownExtensions({ linkUnfurl: {} }), []) return ( - - - - } - > -
+
+
+
+
+ ( + + + {c} + + + )} + > + { member ? : "Avatar not found"} + +
+
+ ( + + {children} + + )} + > + + {conv?.username || 'username not found'} + + +
+
+ +
+
+ +
+ +
- +
) } diff --git a/moon/apps/web/components/MrView/MergedItem.tsx b/moon/apps/web/components/MrView/MergedItem.tsx new file mode 100644 index 000000000..83d5ac79c --- /dev/null +++ b/moon/apps/web/components/MrView/MergedItem.tsx @@ -0,0 +1,21 @@ +import { Conversation } from '@/pages/[org]/mr/[id]' +import HandleTime from './components/HandleTime' + +interface MergedItemProps { + conv: Conversation +} +const MergedItem = ({ conv }: MergedItemProps) => { + + return ( + <> +
+
Merged via the queue into main
+
+ +
+
+ + ) +} + +export default MergedItem diff --git a/moon/apps/web/components/MrView/ReopenItem.tsx b/moon/apps/web/components/MrView/ReopenItem.tsx new file mode 100644 index 000000000..804c4c7a2 --- /dev/null +++ b/moon/apps/web/components/MrView/ReopenItem.tsx @@ -0,0 +1,42 @@ +import { ConditionalWrap } from '@gitmono/ui' +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' +import { Conversation } from '@/pages/[org]/mr/[id]' +import { MemberHovercard } from '../InlinePost/MemberHovercard' +import { MemberAvatar } from '../MemberAvatar' +import { UserLinkByName } from './components/UserLinkByName' +import HandleTime from './components/HandleTime' + + +interface ReopenItemProps { + conv: Conversation +} +const ReopenItem = ({ conv }: ReopenItemProps) => { + const { data: member } = useGetOrganizationMember({ username: conv.username }) + + return ( + <> +
+
+ ( + + + {c} + + + )} + > + {member ? : 'Avatar not found'} + +
+
{conv.comment}
+
+ +
+
+ + ) +} + +export default ReopenItem diff --git a/moon/apps/web/components/MrView/TimelineItems.tsx b/moon/apps/web/components/MrView/TimelineItems.tsx index d45341bf4..93bc6e43f 100644 --- a/moon/apps/web/components/MrView/TimelineItems.tsx +++ b/moon/apps/web/components/MrView/TimelineItems.tsx @@ -1,10 +1,12 @@ import React from 'react' import '@primer/primitives/dist/css/functional/themes/light.css' import { BaseStyles, ThemeProvider, Timeline } from '@primer/react' -import { FeedPullRequestClosedIcon, CommentIcon, FeedMergedIcon, IssueReopenedIcon } from '@primer/octicons-react' +import { FeedPullRequestClosedIcon, CommentIcon, FeedMergedIcon, FeedPullRequestOpenIcon } from '@primer/octicons-react' import MRComment from '@/components/MrView/MRComment'; -import { formatDistance, fromUnixTime } from 'date-fns'; import { MRDetail } from '@/pages/[org]/mr/[id]'; +import CloseItem from './CloseItem'; +import ReopenItem from './ReopenItem'; +import MergedItem from './MergedItem'; interface TimelineItemProps { badge?: React.ReactNode @@ -69,19 +71,18 @@ const TimelineItems: React.FC<{ mrDetail?: MRDetail, id: string }> = ({ mrDetail break; case 'Merged': icon = ; - children = - 'Merged via the queue into main ' + - formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }); + children = ; isOver = true; break; case 'Closed': - icon = ; - children = conv.comment; + icon = ; + children = ; isOver = true; break; case 'Reopen': - icon = ; - children = conv.comment; + icon = + children = ; break; } diff --git a/moon/apps/web/components/MrView/components/HandleTime.tsx b/moon/apps/web/components/MrView/components/HandleTime.tsx new file mode 100644 index 000000000..de3529f31 --- /dev/null +++ b/moon/apps/web/components/MrView/components/HandleTime.tsx @@ -0,0 +1,25 @@ +import { format, formatDistance, fromUnixTime } from 'date-fns' +import { Tooltip } from '@gitmono/ui' + +interface HandleTimeProps { + created_at: number +} + +const HandleTime = ({ created_at }: HandleTimeProps) => { + const time = formatDistance(fromUnixTime(created_at), new Date(), { addSuffix: true }) + const formatTimestamp = (timestamp: number) => { + const date = timestamp > 1e12 ? fromUnixTime(Math.floor(timestamp / 1000)) : fromUnixTime(timestamp) + + return format(date, 'yyyy-MM-dd HH:mm:ss') + } + + return ( + <> + +
{time}
+
+ + ) +} + +export default HandleTime diff --git a/moon/apps/web/components/MrView/components/UserLinkByName.tsx b/moon/apps/web/components/MrView/components/UserLinkByName.tsx new file mode 100644 index 000000000..a0c758237 --- /dev/null +++ b/moon/apps/web/components/MrView/components/UserLinkByName.tsx @@ -0,0 +1,18 @@ +import { Link, LinkProps } from '@gitmono/ui/Link' +import { useScope } from '@/contexts/scope' + +export function UserLinkByName({ + username, + children, + ...linkProps +}: Omit & { username: string; children: React.ReactNode }) { + const { scope } = useScope() + + if(!username) return <>{children} + + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/moon/apps/web/hooks/issues/useGetIssueDetail.ts b/moon/apps/web/hooks/issues/useGetIssueDetail.ts index 4b06108e0..815cfec72 100644 --- a/moon/apps/web/hooks/issues/useGetIssueDetail.ts +++ b/moon/apps/web/hooks/issues/useGetIssueDetail.ts @@ -4,11 +4,11 @@ import { legacyApiClient } from '@/utils/queryClient' interface conversations { id: number - user_id: number conv_type: string comment: string created_at: number updated_at: number + username: string } interface raw { @@ -22,7 +22,7 @@ interface raw { interface issueDetail { status: string - conversations: { id: number; user_id: number; conv_type: string; comment: string; created_at: number }[] + conversations: conversations[] title: string } diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx index 938c4f392..a9ca0dc19 100644 --- a/moon/apps/web/pages/[org]/mr/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -23,9 +23,11 @@ import { trimHtml } from '@/utils/trimHtml' import { toast } from 'react-hot-toast' import { ComposerReactionPicker } from '@/components/Reactions/ComposerReactionPicker'; import { useUploadHelpers } from '@/hooks/useUploadHelpers'; -import { CommentDiscussionIcon, FileDiffIcon } from '@primer/octicons-react' +import { CommentDiscussionIcon, FileDiffIcon, ChecklistIcon } from '@primer/octicons-react' import TimelineItems from '@/components/MrView/TimelineItems'; +const { UnderlinePanels } = require('@primer/react/experimental') + export interface MRDetail { status: string, conversations: Conversation[], @@ -33,10 +35,11 @@ export interface MRDetail { } export interface Conversation { id: number, - user_id: number, conv_type: string, comment: string, created_at: number, + updated_at: number, + username: string, } const MRDetailPage:PageWithLayout = () =>{ @@ -48,7 +51,6 @@ const MRDetailPage:PageWithLayout = () =>{ const id = typeof tempId === 'string' ? tempId : ''; const { data: MrDetailData, isLoading: detailIsLoading } = useGetMrDetail(id) const mrDetail = MrDetailData?.data as MRDetail | undefined - const { UnderlinePanels } = require('@primer/react/experimental') if (mrDetail && typeof mrDetail.status === 'string') { mrDetail.status = mrDetail.status.toLowerCase(); @@ -121,6 +123,7 @@ const MRDetailPage:PageWithLayout = () =>{
Conversation + Checks Files Changed
@@ -205,6 +208,9 @@ const MRDetailPage:PageWithLayout = () =>{
+ +
Checks
+
{fileChgIsLoading ? (