From dcf74d5cf52c7a6ab3bfc408168807b0850e728f Mon Sep 17 00:00:00 2001 From: sailong Date: Tue, 1 Jul 2025 16:24:25 +0800 Subject: [PATCH 1/2] refactor(UI):The timeline and tab components of the MR Page --- .../apps/web/components/DiffView/FileDiff.tsx | 2 +- moon/apps/web/components/MrView/MRComment.tsx | 2 +- .../web/components/MrView/TimelineItems.tsx | 94 +++++++ moon/apps/web/package.json | 11 +- moon/apps/web/pages/[org]/mr/[id].tsx | 230 +++++++++--------- moon/apps/web/tsconfig.json | 4 +- moon/pnpm-lock.yaml | 39 ++- moon/pnpm-workspace.yaml | 6 + 8 files changed, 252 insertions(+), 136 deletions(-) create mode 100644 moon/apps/web/components/MrView/TimelineItems.tsx diff --git a/moon/apps/web/components/DiffView/FileDiff.tsx b/moon/apps/web/components/DiffView/FileDiff.tsx index 8fe9fb8a3..8550cbd64 100644 --- a/moon/apps/web/components/DiffView/FileDiff.tsx +++ b/moon/apps/web/components/DiffView/FileDiff.tsx @@ -98,7 +98,7 @@ export default function FileDiff({ diffs }: { diffs: string }) { } return ( -
+
diff --git a/moon/apps/web/components/MrView/MRComment.tsx b/moon/apps/web/components/MrView/MRComment.tsx index 439cc558a..392d18360 100644 --- a/moon/apps/web/components/MrView/MRComment.tsx +++ b/moon/apps/web/components/MrView/MRComment.tsx @@ -76,7 +76,7 @@ const Comment = ({ conv, id, whoamI }: CommentProps) => { } > -
+
diff --git a/moon/apps/web/components/MrView/TimelineItems.tsx b/moon/apps/web/components/MrView/TimelineItems.tsx new file mode 100644 index 000000000..d45341bf4 --- /dev/null +++ b/moon/apps/web/components/MrView/TimelineItems.tsx @@ -0,0 +1,94 @@ +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 MRComment from '@/components/MrView/MRComment'; +import { formatDistance, fromUnixTime } from 'date-fns'; +import { MRDetail } from '@/pages/[org]/mr/[id]'; + +interface TimelineItemProps { + badge?: React.ReactNode + children?: React.ReactNode + isOver?: boolean +} + +interface ConvItem { + id: number + badge?: React.ReactNode + children?: React.ReactNode + isOver: boolean; +} + +interface TimelineWrapperProps { + convItems?: ConvItem[]; +} + + +const TimelineItem = ({ badge, children, isOver }: TimelineItemProps) => { + return ( + <> + + {badge} + {children} + + {isOver && } + + ) +} + +const TimelineWrapper: React.FC = ({ convItems = [] }) => { + return ( + + + + {convItems?.map((item) => ( + + {item.children} + + ))} + + + + ); +}; + +const TimelineItems: React.FC<{ mrDetail?: MRDetail, id: string }> = ({ mrDetail, id }) => { + if (!mrDetail) { + return null; + } + + const convItems: ConvItem[] = mrDetail?.conversations.map((conv) => { + let icon; + let children; + let isOver = false; + + switch (conv.conv_type) { + case 'Comment': + icon = ; + children = ; + break; + case 'Merged': + icon = ; + children = + 'Merged via the queue into main ' + + formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }); + isOver = true; + break; + case 'Closed': + icon = ; + children = conv.comment; + isOver = true; + break; + case 'Reopen': + icon = ; + children = conv.comment; + break; + } + + return { badge: icon, children, isOver, id: conv.id }; + }); + + return ; +}; + +export default TimelineItems; \ No newline at end of file diff --git a/moon/apps/web/package.json b/moon/apps/web/package.json index 436572fb4..5e653586d 100644 --- a/moon/apps/web/package.json +++ b/moon/apps/web/package.json @@ -21,7 +21,7 @@ "@ant-design/icons": "catalog:", "@emoji-mart/data": "catalog:", "@emotion/styled": "catalog:", - "@git-diff-view/react": "0.0.26", + "@git-diff-view/react": "catalog:", "@gitmono/config": "workspace:*", "@gitmono/editor": "workspace:*", "@gitmono/regex": "workspace:*", @@ -35,8 +35,9 @@ "@next/bundle-analyzer": "catalog:", "@octokit/auth-app": "catalog:", "@octokit/core": "catalog:", - "@primer/primitives": "^10.7.0", - "@primer/react": "^37.27.0", + "@primer/octicons-react": "catalog:", + "@primer/primitives": "catalog:", + "@primer/react": "catalog:", "@radix-ui/react-accordion": "catalog:", "@radix-ui/react-dialog": "catalog:", "@radix-ui/react-hover-card": "catalog:", @@ -68,7 +69,7 @@ "deepmerge": "catalog:", "fast-deep-equal": "catalog:", "framer-motion": "catalog:", - "fuse.js": "^7.1.0", + "fuse.js": "catalog:", "github-markdown-css": "catalog:", "gray-matter": "catalog:", "jotai": "catalog:", @@ -125,7 +126,7 @@ "react-wrap-balancer": "catalog:", "remeda": "catalog:", "slugify": "catalog:", - "styled-components": "^6.1.19", + "styled-components": "catalog:", "tippy.js": "catalog:", "use-debounce": "catalog:", "use-sound": "catalog:", diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx index cea6ec9e4..a0175fb92 100644 --- a/moon/apps/web/pages/[org]/mr/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -1,15 +1,10 @@ 'use client' import React, { useRef, useState } from 'react'; -import { Card, Tabs, TabsProps,Timeline,} from 'antd'; -// import { CommentOutlined, MergeOutlined, CloseCircleOutlined, PullRequestOutlined } from '@ant-design/icons'; -import { ChevronRightCircleIcon, ChevronSelectIcon,AlarmIcon,ClockIcon, PicturePlusIcon} from '@gitmono/ui/Icons' -import { formatDistance, fromUnixTime } from 'date-fns'; -import MRComment from '@/components/MrView/MRComment'; +import { PicturePlusIcon} from '@gitmono/ui/Icons' import { useRouter } from 'next/router'; import FileDiff from '@/components/DiffView/FileDiff'; -import { Button } from '@gitmono/ui'; -// import { ReloadIcon } from '@radix-ui/react-icons'; +import { Button, LoadingSpinner, UIText } from '@gitmono/ui'; import { cn } from '@gitmono/ui/utils'; import AuthAppProviders from '@/components/Providers/AuthAppProviders'; import { AppLayout } from '@/components/Layout/AppLayout'; @@ -28,8 +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 { UnderlinePanels } from '@primer/react/experimental' +import { CommentDiscussionIcon, FileDiffIcon } from '@primer/octicons-react' +import TimelineItems from '@/components/MrView/TimelineItems'; -interface MRDetail { +export interface MRDetail { status: string, conversations: Conversation[], title: string, @@ -49,7 +47,7 @@ const MRDetailPage:PageWithLayout = () =>{ const [login, _setLogin] = useState(true); const [isReactionPickerOpen, setIsReactionPickerOpen] = useState(false) const id = typeof tempId === 'string' ? tempId : ''; - const { data: MrDetailData } = useGetMrDetail(id) + const { data: MrDetailData, isLoading: detailIsLoading } = useGetMrDetail(id) const mrDetail = MrDetailData?.data as MRDetail | undefined @@ -57,7 +55,7 @@ const MRDetailPage:PageWithLayout = () =>{ mrDetail.status = mrDetail.status.toLowerCase(); } - const { data: MrFilesChangedData} = useGetMrFilesChanged(id) + const { data: MrFilesChangedData, isLoading: fileChgIsLoading} = useGetMrFilesChanged(id) const { mutate: approveMr, isPending : mrMergeIsPending } = usePostMrMerge(id) const handleMrApprove = () => { @@ -92,7 +90,7 @@ const MRDetailPage:PageWithLayout = () =>{ const currentContentHTML = editorRef.current?.editor?.getHTML() ?? '

'; if (trimHtml(currentContentHTML) === '') { - toast.error('Please enter the content.', { position: 'top-center' }) + toast.error('Please enter the content.') }else { postMrComment( { content: currentContentHTML }, @@ -105,26 +103,6 @@ const MRDetailPage:PageWithLayout = () =>{ } } - let conv_items = mrDetail?.conversations.map(conv => { - let icon; - let children; - - switch (conv.conv_type) { - case "Comment": icon = ; children = ; break - case "Merged": icon = ; children = "Merged via the queue into main " + formatDistance(fromUnixTime(conv.created_at), new Date(), { addSuffix: true }); break; - case "Closed": icon = ; children = conv.comment; break; - case "Reopen": icon = ; children = conv.comment; break; - }; - - const element = { - dot: icon, - // color: 'red', - children: children - } - - return element - }); - const buttonClasses= 'cursor-pointer'; const editorRef = useRef(null); const onKeyDownScrollHandler = useHandleBottomScrollOffset({ @@ -134,101 +112,115 @@ const MRDetailPage:PageWithLayout = () =>{ upload: editorRef.current?.uploadAndAppendAttachments }) - const tab_items: TabsProps['items'] = [ - { - key: '1', - label: 'Conversation', - children: -
- -
-
- {mrDetail && mrDetail.status === "open" && - - } -
-

Add a comment

- -
- -
-
- {mrDetail && mrDetail.status === "open" && + return ( +
+
+ + {`${mrDetail?.title || ''}#${id}`} + +
+
+ + Conversation + Files Changed + +
+ {detailIsLoading ? ( +
+ +
+ ) : ( + + )} +
+
+ {mrDetail && mrDetail.status === "open" && + + } +
+

Add a comment

+ +
+ - } - {mrDetail && mrDetail.status === "closed" && + variant='plain' + iconOnly={} + accessibilityLabel='Add files' + onClick={dropzone.open} + tooltip='Add files' + /> + +
+
+ {mrDetail && mrDetail.status === "open" && + + } + {mrDetail && mrDetail.status === "closed" && + + } - } - +
-
- }, - { - key: '2', - label: 'Files Changed', - children: MrFilesChangedData?.data?.content ? - : -
No files changed
- } - ]; - - return ( - - - - ) + + + {fileChgIsLoading ? ( +
+ +
+ ) : MrFilesChangedData?.data?.content ? ( + + ) : ( +
No files changed
+ )} +
+ +
+
+ ) } diff --git a/moon/apps/web/tsconfig.json b/moon/apps/web/tsconfig.json index f046db93b..15a38ffa3 100644 --- a/moon/apps/web/tsconfig.json +++ b/moon/apps/web/tsconfig.json @@ -24,7 +24,9 @@ "name": "next" } ], - "strictNullChecks": true + "strictNullChecks": true, + "module": "nodenext", + "moduleResolution": "nodenext" }, "extends": "@gitmono/tsconfig/nextjs.json", "include": [ diff --git a/moon/pnpm-lock.yaml b/moon/pnpm-lock.yaml index 2f0766871..95769ca72 100644 --- a/moon/pnpm-lock.yaml +++ b/moon/pnpm-lock.yaml @@ -27,6 +27,9 @@ catalogs: '@flydotio/dockerfile': specifier: ^0.4.11 version: 0.4.11 + '@git-diff-view/react': + specifier: 0.0.26 + version: 0.0.26 '@heroicons/react': specifier: ^2.2.0 version: 2.2.0 @@ -72,6 +75,15 @@ catalogs: '@playwright/test': specifier: ^1.43.1 version: 1.43.1 + '@primer/octicons-react': + specifier: ^19.15.3 + version: 19.15.3 + '@primer/primitives': + specifier: ^10.7.0 + version: 10.7.0 + '@primer/react': + specifier: ^37.27.0 + version: 37.27.0 '@radix-ui/react-accordion': specifier: ^1.2.0 version: 1.2.0 @@ -402,6 +414,9 @@ catalogs: framer-motion: specifier: ^11.11.11 version: 11.11.11 + fuse.js: + specifier: ^7.1.0 + version: 7.1.0 github-markdown-css: specifier: ^5.8.1 version: 5.8.1 @@ -609,6 +624,9 @@ catalogs: storybook: specifier: ^8.0.0-beta.3 version: 8.0.5 + styled-components: + specifier: ^6.1.19 + version: 6.1.19 swagger-typescript-api: specifier: ^12.0.4 version: 12.0.4 @@ -774,7 +792,7 @@ importers: specifier: 'catalog:' version: 11.14.0(@emotion/react@11.14.0(@types/react@18.2.74)(react@18.2.0))(@types/react@18.2.74)(react@18.2.0) '@git-diff-view/react': - specifier: 0.0.26 + specifier: 'catalog:' version: 0.0.26(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@gitmono/config': specifier: workspace:* @@ -815,11 +833,14 @@ importers: '@octokit/core': specifier: 'catalog:' version: 6.1.2 + '@primer/octicons-react': + specifier: 'catalog:' + version: 19.15.3(react@18.2.0) '@primer/primitives': - specifier: ^10.7.0 + specifier: 'catalog:' version: 10.7.0 '@primer/react': - specifier: ^37.27.0 + specifier: 'catalog:' version: 37.27.0(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(styled-components@6.1.19(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) '@radix-ui/react-accordion': specifier: 'catalog:' @@ -915,7 +936,7 @@ importers: specifier: 'catalog:' version: 11.11.11(@emotion/is-prop-valid@1.3.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) fuse.js: - specifier: ^7.1.0 + specifier: 'catalog:' version: 7.1.0 github-markdown-css: specifier: 'catalog:' @@ -1086,7 +1107,7 @@ importers: specifier: 'catalog:' version: 1.6.6 styled-components: - specifier: ^6.1.19 + specifier: 'catalog:' version: 6.1.19(react-dom@18.2.0(react@18.2.0))(react@18.2.0) tippy.js: specifier: 'catalog:' @@ -23844,9 +23865,9 @@ snapshots: postcss@8.4.31: dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 postcss@8.4.38: dependencies: @@ -26641,7 +26662,7 @@ snapshots: html-escaper: 2.0.2 is-plain-object: 5.0.0 opener: 1.5.2 - picocolors: 1.0.0 + picocolors: 1.1.1 sirv: 2.0.4 ws: 7.5.9 transitivePeerDependencies: diff --git a/moon/pnpm-workspace.yaml b/moon/pnpm-workspace.yaml index 49d164b86..0ea928b00 100644 --- a/moon/pnpm-workspace.yaml +++ b/moon/pnpm-workspace.yaml @@ -13,6 +13,7 @@ catalog: '@emoji-mart/data': ^1.1.2 '@figma/plugin-typings': 1.74.0 '@flydotio/dockerfile': ^0.4.11 + '@git-diff-view/react': 0.0.26 '@hocuspocus/extension-database': ^2.13.5 '@hocuspocus/extension-logger': ^2.13.5 '@hocuspocus/provider': ^2.13.5 @@ -27,6 +28,9 @@ catalog: '@octokit/auth-app': ^7.1.0 '@octokit/core': ^6.1.2 '@playwright/test': ^1.43.1 + '@primer/octicons-react': ^19.15.3 + '@primer/primitives': ^10.7.0 + '@primer/react': ^37.27.0 '@radix-ui/react-accordion': ^1.2.0 '@radix-ui/react-context-menu': ^2.2.1 '@radix-ui/react-dialog': ^1.1.1 @@ -153,6 +157,7 @@ catalog: fast-deep-equal: ^3.1.3 feed: ^4.2.2 framer-motion: ^11.11.11 + fuse.js: ^7.1.0 gray-matter: ^4.0.3 jotai: ^2.0.3 jotai-scope: ^0.4.1 @@ -233,6 +238,7 @@ catalog: slugify: ^1.6.6 sonner: ^1.5.0 storybook: ^8.0.0-beta.3 + styled-components: ^6.1.19 supertest: ^6.3.3 swagger-typescript-api: ^12.0.4 tailwind-merge: ^2.3.0 From 793a5fd6378da61af62eb05481ec6ddbeeac9d0e Mon Sep 17 00:00:00 2001 From: sailong Date: Tue, 1 Jul 2025 16:55:19 +0800 Subject: [PATCH 2/2] fix(UI):Module import configuration --- moon/apps/web/pages/[org]/mr/[id].tsx | 3 +-- moon/apps/web/tsconfig.json | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx index a0175fb92..ad1f11d8f 100644 --- a/moon/apps/web/pages/[org]/mr/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -23,7 +23,6 @@ import { trimHtml } from '@/utils/trimHtml' import { toast } from 'react-hot-toast' import { ComposerReactionPicker } from '@/components/Reactions/ComposerReactionPicker'; import { useUploadHelpers } from '@/hooks/useUploadHelpers'; -import { UnderlinePanels } from '@primer/react/experimental' import { CommentDiscussionIcon, FileDiffIcon } from '@primer/octicons-react' import TimelineItems from '@/components/MrView/TimelineItems'; @@ -49,7 +48,7 @@ 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(); diff --git a/moon/apps/web/tsconfig.json b/moon/apps/web/tsconfig.json index 15a38ffa3..f046db93b 100644 --- a/moon/apps/web/tsconfig.json +++ b/moon/apps/web/tsconfig.json @@ -24,9 +24,7 @@ "name": "next" } ], - "strictNullChecks": true, - "module": "nodenext", - "moduleResolution": "nodenext" + "strictNullChecks": true }, "extends": "@gitmono/tsconfig/nextjs.json", "include": [