From 7867be4f88b6437100116a850a6757f5f2933984 Mon Sep 17 00:00:00 2001 From: liuyangjuncong20202570 Date: Sat, 2 Aug 2025 16:34:28 +0800 Subject: [PATCH] feat:fix the router problem & add assignees style --- .../web/components/Issues/IssueDetailPage.tsx | 106 ++++++++---------- .../web/components/Issues/IssuesContent.tsx | 52 +++++---- .../web/components/Issues/utils/store.tsx | 5 +- .../web/components/MrView/AssigneeItem.tsx | 66 +++++++++++ .../apps/web/components/MrView/ReopenItem.tsx | 2 +- .../web/components/MrView/TimelineItems.tsx | 10 +- moon/apps/web/components/MrView/index.tsx | 10 +- .../[org]/issue/[link]/{[id] => }/index.tsx | 7 +- .../[org]/mr/[link]/{[id].tsx => index.tsx} | 12 +- 9 files changed, 176 insertions(+), 94 deletions(-) create mode 100644 moon/apps/web/components/MrView/AssigneeItem.tsx rename moon/apps/web/pages/[org]/issue/[link]/{[id] => }/index.tsx (90%) rename moon/apps/web/pages/[org]/mr/[link]/{[id].tsx => index.tsx} (98%) diff --git a/moon/apps/web/components/Issues/IssueDetailPage.tsx b/moon/apps/web/components/Issues/IssueDetailPage.tsx index 7e5a55491..766c9f06a 100644 --- a/moon/apps/web/components/Issues/IssueDetailPage.tsx +++ b/moon/apps/web/components/Issues/IssueDetailPage.tsx @@ -1,39 +1,46 @@ -'use client'; - -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { IssueClosedIcon, IssueOpenedIcon, IssueReopenedIcon } from '@primer/octicons-react'; -import { Stack } from '@primer/react'; -import { useRouter } from 'next/router'; -import toast from 'react-hot-toast'; - - -import { CommonResultIssueDetailRes } from '@gitmono/types'; -import { Button, LoadingSpinner, PicturePlusIcon } from '@gitmono/ui'; - -import { EMPTY_HTML } from '@/atoms/markdown'; -import { useHandleBottomScrollOffset } from '@/components/NoteEditor/useHandleBottomScrollOffset'; -import { ComposerReactionPicker } from '@/components/Reactions/ComposerReactionPicker'; -import { SimpleNoteContent, SimpleNoteContentRef } from '@/components/SimpleNoteEditor/SimpleNoteContent'; -import { useGetIssueDetail } from '@/hooks/issues/useGetIssueDetail'; -import { usePostIssueAssignees } from '@/hooks/issues/usePostIssueAssignees'; -import { usePostIssueClose } from '@/hooks/issues/usePostIssueClose'; -import { usePostIssueComment } from '@/hooks/issues/usePostIssueComment'; -import { usePostIssueReopen } from '@/hooks/issues/usePostIssueReopen'; -import { useGetCurrentUser } from '@/hooks/useGetCurrentUser'; -import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember'; -import { usePostIssueLabels } from '@/hooks/usePostIssueLabels'; -import { useUploadHelpers } from '@/hooks/useUploadHelpers'; -import { apiErrorToast } from '@/utils/apiErrorToast'; -import { trimHtml } from '@/utils/trimHtml'; - - - -import { MemberAvatar } from '../MemberAvatar'; -import TimelineItems from '../MrView/TimelineItems'; -import { BadgeItem } from './IssueNewPage'; -import { pickWithReflect } from './utils/pickWithReflectDeep'; -import { splitFun, useAssigneesSelector, useAvatars, useChange, useLabelMap, useLabels, useLabelsSelector, useMemberMap } from './utils/sideEffect'; - +'use client' + +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { IssueClosedIcon, IssueOpenedIcon, IssueReopenedIcon } from '@primer/octicons-react' +import { Stack } from '@primer/react' +import { useAtom } from 'jotai' +import { useRouter } from 'next/router' +import toast from 'react-hot-toast' + +import { CommonResultIssueDetailRes } from '@gitmono/types' +import { Button, LoadingSpinner, PicturePlusIcon } from '@gitmono/ui' + +import { EMPTY_HTML } from '@/atoms/markdown' +import { useHandleBottomScrollOffset } from '@/components/NoteEditor/useHandleBottomScrollOffset' +import { ComposerReactionPicker } from '@/components/Reactions/ComposerReactionPicker' +import { SimpleNoteContent, SimpleNoteContentRef } from '@/components/SimpleNoteEditor/SimpleNoteContent' +import { useGetIssueDetail } from '@/hooks/issues/useGetIssueDetail' +import { usePostIssueAssignees } from '@/hooks/issues/usePostIssueAssignees' +import { usePostIssueClose } from '@/hooks/issues/usePostIssueClose' +import { usePostIssueComment } from '@/hooks/issues/usePostIssueComment' +import { usePostIssueReopen } from '@/hooks/issues/usePostIssueReopen' +import { useGetCurrentUser } from '@/hooks/useGetCurrentUser' +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' +import { usePostIssueLabels } from '@/hooks/usePostIssueLabels' +import { useUploadHelpers } from '@/hooks/useUploadHelpers' +import { apiErrorToast } from '@/utils/apiErrorToast' +import { trimHtml } from '@/utils/trimHtml' + +import { MemberAvatar } from '../MemberAvatar' +import TimelineItems from '../MrView/TimelineItems' +import { BadgeItem } from './IssueNewPage' +import { pickWithReflect } from './utils/pickWithReflectDeep' +import { + splitFun, + useAssigneesSelector, + useAvatars, + useChange, + useLabelMap, + useLabels, + useLabelsSelector, + useMemberMap +} from './utils/sideEffect' +import { idAtom } from './utils/store' // interface IssueDetail { // status: string @@ -44,7 +51,8 @@ import { splitFun, useAssigneesSelector, useAvatars, useChange, useLabelMap, use // let needComment = false -export default function IssueDetailPage({ link, id }: { link: string; id: number }) { +export default function IssueDetailPage({ link }: { link: string }) { + const [id] = useAtom(idAtom) const [login, setLogin] = useState(false) const [info, setInfo] = useState>({ status: '', @@ -223,22 +231,6 @@ export default function IssueDetailPage({ link, id }: { link: string; id: number const labelMap = useLabelMap() - // const handleChange = (html: string) => { - // if (html && html === '

') { - // setCloseHint('Close issue') - // } else { - // setCloseHint('Close with comment') - // } - // } - - // const handleCloseChange = (html: string) => { - // if (html && html === '

') { - // needComment = false - // } else { - // needComment = true - // } - // } - const { open, handleAssignees, handleOpenChange, fetchSelected } = useAssigneesSelector({ assignees: info?.assignees ?? [], assignRequest: (selected) => @@ -450,7 +442,7 @@ export default function IssueDetailPage({ link, id }: { link: string; id: number )} {/* */} -
+
- handleLabels(selected)} open={label_open} diff --git a/moon/apps/web/components/Issues/IssuesContent.tsx b/moon/apps/web/components/Issues/IssuesContent.tsx index 81e03e105..52b105474 100644 --- a/moon/apps/web/components/Issues/IssuesContent.tsx +++ b/moon/apps/web/components/Issues/IssuesContent.tsx @@ -25,20 +25,26 @@ import { ListBanner, ListItem } from '@/components/Issues/IssueList' -import { filterAtom, issueCloseCurrentPage, issueOpenCurrentPage, sortAtom } from '@/components/Issues/utils/store' +import { + filterAtom, + idAtom, + issueCloseCurrentPage, + issueOpenCurrentPage, + sortAtom +} from '@/components/Issues/utils/store' import { useScope } from '@/contexts/scope' import { useGetIssueLists } from '@/hooks/issues/useGetIssueLists' +import { useGetLabelList } from '@/hooks/useGetLabelList' import { useSyncedMembers } from '@/hooks/useSyncedMembers' import { apiErrorToast } from '@/utils/apiErrorToast' import { atomWithWebStorage } from '@/utils/atomWithWebStorage' +import { getFontColor } from '@/utils/getFontColor' import { IssueIndexTabFilter } from './IssueIndex' import { MemberHoverAvatarList } from './MemberHoverAvatarList' import { Pagination } from './Pagenation' import { orderTags } from './utils/consts' import { generateAllMenuItems, MenuConfig } from './utils/generateAllMenuItems' -import { useGetLabelList } from '@/hooks/useGetLabelList' -import { getFontColor } from '@/utils/getFontColor' interface Props { getIssues?: ReturnType> @@ -347,6 +353,7 @@ export function IssuesContent({ searching }: Props) { [issueLists, additions] ) + const [_iddAtom, setIdAtom] = useAtom(idAtom) useEffect(() => { if (status === 'open') { @@ -415,7 +422,10 @@ export function IssuesContent({ searching }: Props) { title={i.title} leftIcon={getStatusIcon(i.status)} rightIcon={} - onClick={() => router.push(`/${scope}/issue/${i.link}/${i.id}`)} + onClick={() => { + setIdAtom(i.id) + router.push(`/${scope}/issue/${i.link}`) + }} >
{i.link} ยท {i.author} {i.status}{' '} @@ -471,24 +481,26 @@ export const RightAvatar = ({ item }: { item: ItemsType[number] }) => { }} className='flex items-center gap-2 text-sm' > - {item.labels.map(label => { + {item.labels.map((label) => { const fontColor = getFontColor(label.color) - return - {label.name} - + return ( + + {label.name} + + ) })}
diff --git a/moon/apps/web/components/Issues/utils/store.tsx b/moon/apps/web/components/Issues/utils/store.tsx index a15dee0ad..de3121010 100644 --- a/moon/apps/web/components/Issues/utils/store.tsx +++ b/moon/apps/web/components/Issues/utils/store.tsx @@ -38,4 +38,7 @@ export const mrOpenCurrentPage = atomWithWebStorage('MROpencurrentPage', 1) export const mrCloseCurrentPage = atomWithWebStorage('MRClosecurrentPage', 1) export const labelsOpenCurrentPage = atomWithWebStorage('LabelsOpenCurrentPage', 1) -export const labelsCloseCurrentPage = atomWithWebStorage('LabelsCloseCurrentPage', 1) \ No newline at end of file +export const labelsCloseCurrentPage = atomWithWebStorage('LabelsCloseCurrentPage', 1) + +export const idAtom = atom(0) +export const mridAtom = atom(0) diff --git a/moon/apps/web/components/MrView/AssigneeItem.tsx b/moon/apps/web/components/MrView/AssigneeItem.tsx new file mode 100644 index 000000000..4c8b51d07 --- /dev/null +++ b/moon/apps/web/components/MrView/AssigneeItem.tsx @@ -0,0 +1,66 @@ +import { ConditionalWrap } from '@gitmono/ui/utils' + +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' + +import { MemberHovercard } from '../InlinePost/MemberHovercard' +import { MemberAvatar } from '../MemberAvatar' +import HandleTime from './components/HandleTime' +import { UserLinkByName } from './components/UserLinkByName' +import { ReopenItemProps } from './ReopenItem' + +const AssigneeItem = ({ conv }: ReopenItemProps) => { + const match = conv.comment?.match(/\["(.*?)"\]/) ?? '' + const comment = conv.comment?.split(' ') ?? [] + const { data: member } = useGetOrganizationMember({ username: conv.username }) + + const assignees = match[1].split('", "') + + return ( + <> +
+ ( + + + {c} + + + )} + > + {member ? : 'Avatar not found'} + +
+ {conv.username} + {comment[1]} + {assignees && + assignees.map((i, index) => ( + ( + + + {c} + + + )} + > + <> + + {i} + {index < assignees.length - 1 && ', '} + + + + ))} +
+
+ +
+
+ + ) +} + +export default AssigneeItem diff --git a/moon/apps/web/components/MrView/ReopenItem.tsx b/moon/apps/web/components/MrView/ReopenItem.tsx index 906c1d8c6..8c88e0a82 100644 --- a/moon/apps/web/components/MrView/ReopenItem.tsx +++ b/moon/apps/web/components/MrView/ReopenItem.tsx @@ -7,7 +7,7 @@ import HandleTime from './components/HandleTime' import { ConversationItem } from '@gitmono/types/generated' -interface ReopenItemProps { +export interface ReopenItemProps { conv: ConversationItem } const ReopenItem = ({ conv }: ReopenItemProps) => { diff --git a/moon/apps/web/components/MrView/TimelineItems.tsx b/moon/apps/web/components/MrView/TimelineItems.tsx index 1a6e7af0a..253a318a2 100644 --- a/moon/apps/web/components/MrView/TimelineItems.tsx +++ b/moon/apps/web/components/MrView/TimelineItems.tsx @@ -7,18 +7,20 @@ import { FeedMergedIcon, FeedPullRequestClosedIcon, FeedPullRequestOpenIcon, - FeedTagIcon + FeedTagIcon, + PersonIcon } from '@primer/octicons-react' import { BaseStyles, ThemeProvider, Timeline } from '@primer/react' import { ConversationItem } from '@gitmono/types/generated' +import LabelItem from '@/components/MrView/LabelItem' import MRComment from '@/components/MrView/MRComment' +import AssigneeItem from './AssigneeItem' import CloseItem from './CloseItem' import MergedItem from './MergedItem' import ReopenItem from './ReopenItem' -import LabelItem from '@/components/MrView/LabelItem' interface TimelineItemProps { badge?: React.ReactNode @@ -91,8 +93,8 @@ const TimelineItems: React.FC<{ detail: any; id: string; type: string }> = ({ de children = break case 'Assignee': - icon = - children = + icon = + children = break case 'Label': icon = diff --git a/moon/apps/web/components/MrView/index.tsx b/moon/apps/web/components/MrView/index.tsx index c58042126..ea320a1d3 100644 --- a/moon/apps/web/components/MrView/index.tsx +++ b/moon/apps/web/components/MrView/index.tsx @@ -22,6 +22,7 @@ import { IssueList as MrList } from '@/components/Issues/IssueList' import { useScope } from '@/contexts/scope' +import { useGetLabelList } from '@/hooks/useGetLabelList' import { usePostMrList } from '@/hooks/usePostMrList' import { useSyncedMembers } from '@/hooks/useSyncedMembers' import { apiErrorToast } from '@/utils/apiErrorToast' @@ -32,9 +33,8 @@ import { AdditionType, RightAvatar } from '../Issues/IssuesContent' import { Pagination } from '../Issues/Pagenation' import { orderTags, reviewTags } from '../Issues/utils/consts' import { generateAllMenuItems, MenuConfig } from '../Issues/utils/generateAllMenuItems' -import { filterAtom, mrCloseCurrentPage, mrOpenCurrentPage, sortAtom } from '../Issues/utils/store' +import { filterAtom, mrCloseCurrentPage, mridAtom, mrOpenCurrentPage, sortAtom } from '../Issues/utils/store' import { Heading } from './catalyst/heading' -import { useGetLabelList } from '@/hooks/useGetLabelList' // interface MrInfoItem { // link: string @@ -60,6 +60,7 @@ export default function MrView() { const [sort, setSort] = useAtom(sortAtom({ scope, filter: 'sortPickerMR' })) const { members } = useSyncedMembers() const { labels: labelList } = useGetLabelList() + const [_mrid, setMrid] = useAtom(mridAtom) const orderAtom = useMemo( () => atomWithWebStorage(`${scope}:mr-order`, { sort: 'Created On', time: 'Newest' }), @@ -438,7 +439,10 @@ export default function MrView() { return issueList.map((i) => ( router.push(`/${scope}/mr/${i.link}/${i.id}`)} + onClick={() => { + setMrid(i.id) + router.push(`/${scope}/mr/${i.link}`) + }} title={i.title} leftIcon={getStatusIcon(i.status)} rightIcon={} diff --git a/moon/apps/web/pages/[org]/issue/[link]/[id]/index.tsx b/moon/apps/web/pages/[org]/issue/[link]/index.tsx similarity index 90% rename from moon/apps/web/pages/[org]/issue/[link]/[id]/index.tsx rename to moon/apps/web/pages/[org]/issue/[link]/index.tsx index d7062ac57..d69d4e1aa 100644 --- a/moon/apps/web/pages/[org]/issue/[link]/[id]/index.tsx +++ b/moon/apps/web/pages/[org]/issue/[link]/index.tsx @@ -7,7 +7,7 @@ import { AuthAppProviders } from '@/components/Providers/AuthAppProviders' import { PageWithLayout } from '@/utils/types' export const getServerSideProps: GetServerSideProps = async ({ query }) => { - if (!query.id) { + if (!query.link) { return { redirect: { destination: `/${query.org}/issue`, @@ -17,18 +17,17 @@ export const getServerSideProps: GetServerSideProps = async ({ query }) => { } return { props: { - id: query.id, link: query.link } } } -const OrganizationIssueDetailPage: PageWithLayout = ({ link, id }) => { +const OrganizationIssueDetailPage: PageWithLayout = ({ link }) => { return ( <> - + diff --git a/moon/apps/web/pages/[org]/mr/[link]/[id].tsx b/moon/apps/web/pages/[org]/mr/[link]/index.tsx similarity index 98% rename from moon/apps/web/pages/[org]/mr/[link]/[id].tsx rename to moon/apps/web/pages/[org]/mr/[link]/index.tsx index 675973281..0b9336bf3 100644 --- a/moon/apps/web/pages/[org]/mr/[link]/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[link]/index.tsx @@ -3,6 +3,7 @@ import React, { useRef, useState } from 'react' import { ChecklistIcon, CommentDiscussionIcon, FileDiffIcon } from '@primer/octicons-react' import { BaseStyles, ThemeProvider } from '@primer/react' +import { useAtom } from 'jotai' import { useRouter } from 'next/router' import { toast } from 'react-hot-toast' @@ -20,9 +21,11 @@ import { useAvatars, useChange, useLabelMap, - useLabels, useLabelsSelector, + useLabels, + useLabelsSelector, useMemberMap } from '@/components/Issues/utils/sideEffect' +import { mridAtom } from '@/components/Issues/utils/store' import { AppLayout } from '@/components/Layout/AppLayout' import { MemberAvatar } from '@/components/MemberAvatar' import TimelineItems from '@/components/MrView/TimelineItems' @@ -36,13 +39,13 @@ import { useGetMrDetail } from '@/hooks/useGetMrDetail' import { useGetMrFilesChanged } from '@/hooks/useGetMrFilesChanged' import { usePostMrClose } from '@/hooks/usePostMrClose' import { usePostMrComment } from '@/hooks/usePostMrComment' +import { usePostMRLabels } from '@/hooks/usePostMRLabels' import { usePostMrMerge } from '@/hooks/usePostMrMerge' import { usePostMrReopen } from '@/hooks/usePostMrReopen' import { useUploadHelpers } from '@/hooks/useUploadHelpers' import { apiErrorToast } from '@/utils/apiErrorToast' import { trimHtml } from '@/utils/trimHtml' import { PageWithLayout } from '@/utils/types' -import { usePostMRLabels } from '@/hooks/usePostMRLabels' const { UnderlinePanels } = require('@primer/react/experimental') @@ -54,7 +57,8 @@ export interface MRDetail { const MRDetailPage: PageWithLayout = () => { const router = useRouter() - const { link: tempId, id: item_id } = router.query + const { link: tempId } = router.query + const [item_id] = useAtom(mridAtom) const { scope } = useScope() const [login, _setLogin] = useState(true) const [isReactionPickerOpen, setIsReactionPickerOpen] = useState(false) @@ -216,7 +220,7 @@ const MRDetailPage: PageWithLayout = () => { ) : ( mrDetail && )} -
+
{mrDetail && mrDetail.status === 'open' && (