diff --git a/moon/apps/web/components/CodeView/BlobView/CodeContent.tsx b/moon/apps/web/components/CodeView/BlobView/CodeContent.tsx index b6ad8fd4a..7467270a9 100644 --- a/moon/apps/web/components/CodeView/BlobView/CodeContent.tsx +++ b/moon/apps/web/components/CodeView/BlobView/CodeContent.tsx @@ -1,12 +1,13 @@ -'use client'; +'use client' -import { useEffect, useRef, useState } from 'react'; -import { Button, Dropdown, MenuProps, message } from 'antd'; -import { Highlight, themes } from 'prism-react-renderer'; -import { DotsHorizontal } from '@gitmono/ui'; +import { useEffect, useRef, useState } from 'react' +import { Highlight, themes } from 'prism-react-renderer' -import 'github-markdown-css/github-markdown-light.css'; -import styles from './CodeContent.module.css'; +import 'github-markdown-css/github-markdown-light.css' + +import toast from 'react-hot-toast' + +import styles from './CodeContent.module.css' const suffixToLangMap: Record = { '.js': 'jsx', @@ -21,42 +22,42 @@ const suffixToLangMap: Record = { '.h': 'cpp', '.go': 'go', '.yml': 'yaml', - '.yaml': 'yaml', + '.yaml': 'yaml' } function getLangFromFileName(fileName: string): string { - const lastPart = fileName.toLowerCase().match(/\.[^./\\]+$/); + const lastPart = fileName.toLowerCase().match(/\.[^./\\]+$/) - if(lastPart) { - return suffixToLangMap[lastPart[0].toLowerCase()] ?? "markdown"; + if (lastPart) { + return suffixToLangMap[lastPart[0].toLowerCase()] ?? 'markdown' } - return "markdown"; + return 'markdown' } -const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string[] }) => { +const CodeContent = ({ fileContent, path }: { fileContent: string; path?: string[] }) => { const [lfs, setLfs] = useState(false) const [selectedLine, setSelectedLine] = useState(null) - const menuItems: MenuProps = { - items: [ - { - label: 'Copy line', - key: '1' - }, - { - label: 'Copy permalink', - key: '2' - }, - { - label: 'View file in GitHub.dev', - key: '3' - }, - { - label: 'View file in different branch/tag', - key: '4' - } - ] - } + // const menuItems: MenuProps = { + // items: [ + // { + // label: 'Copy line', + // key: '1' + // }, + // { + // label: 'Copy permalink', + // key: '2' + // }, + // { + // label: 'View file in GitHub.dev', + // key: '3' + // }, + // { + // label: 'View file in different branch/tag', + // key: '4' + // } + // ] + // } useEffect(() => { if (isLfsContent(fileContent)) { @@ -72,20 +73,21 @@ const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string const handleCopyLine = (line: string) => { if (navigator.clipboard) { - navigator.clipboard.writeText(line) - .then(() => message.success('Copied to clipboard')) - .catch(() => message.error('Copied failed')) + navigator.clipboard + .writeText(line) + .then(() => toast.success('Copied to clipboard')) + .catch(() => toast.error('Copied failed')) } else { - const textarea = document.createElement('textarea'); + const textarea = document.createElement('textarea') - textarea.value = line; - document.body.appendChild(textarea); - textarea.select(); + textarea.value = line + document.body.appendChild(textarea) + textarea.select() try { - document.execCommand('copy'); - message.success('Copied to clipboard'); + document.execCommand('copy') + toast.success('Copied to clipboard') } catch { - message.error('Copied failed'); + toast.error('Copied failed') } } } @@ -94,18 +96,17 @@ const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string handleCopyLine(fileContent) } - let filename; + let filename if (!path || path.length === 0) { - message.error('Path information is missing'); - filename = ""; - } - else { + toast.error('Path information is missing') + filename = '' + } else { filename = path[path.length - 1] } const handleRawView = () => { // Create a new window/tab with the raw content - const newWindow = window.open(); + const newWindow = window.open() if (newWindow) { newWindow.document.write(` @@ -123,27 +124,27 @@ const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string ${fileContent.replace(//g, '>')} - `); - newWindow.document.close(); + `) + newWindow.document.close() } else { - message.error('Unable to open new window. Please check your browser settings.'); + toast.error('Unable to open new window. Please check your browser settings.') } } const handleDownload = () => { - const blob = new Blob([fileContent], { type: 'text/plain' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); + const blob = new Blob([fileContent], { type: 'text/plain' }) + const url = URL.createObjectURL(blob) + const a = document.createElement('a') - a.href = url; - a.download = filename; + a.href = url + a.download = filename // Append to the document, click it, and remove it - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); + document.body.appendChild(a) + a.click() + document.body.removeChild(a) // Release the URL object - URL.revokeObjectURL(url); + URL.revokeObjectURL(url) } function isLfsContent(content: string): boolean { @@ -179,9 +180,15 @@ const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string {`${fileContent.split('\n').length} lines . 2.79 KB`}
- - - + + +
@@ -199,6 +206,7 @@ const CodeContent = ({ fileContent, path }: { fileContent: string, path?: string }} className='overflow-x-auto whitespace-pre rounded-lg p-4 text-sm' > + {/* - - - {open && ( - e.preventDefault()} - asChild - addDismissibleLayer - > - - - - - - - - - - - { - tabContent?.map((_item)=>{ + + + + + + {open && ( + e.preventDefault()} + asChild + addDismissibleLayer + > + + + + + + + + + + + {tabContent?.map((_item) => { return ( - + - - + + -
{_item.info}
+
{_item.info}
) - }) - } -
- -
-
- )} -
-
- - + })} +
+
+
+ )} +
+ + ) } diff --git a/moon/apps/web/components/Issues/IssueDetailPage.tsx b/moon/apps/web/components/Issues/IssueDetailPage.tsx index e77a101d8..93ed4dbfa 100644 --- a/moon/apps/web/components/Issues/IssueDetailPage.tsx +++ b/moon/apps/web/components/Issues/IssueDetailPage.tsx @@ -51,6 +51,8 @@ interface detailRes { req_result: boolean } +let needComment = false + export default function IssueDetailPage({ id }: { id: string }) { const [login, setLogin] = useState(false) const [info, setInfo] = useState({ @@ -169,6 +171,10 @@ export default function IssueDetailPage({ id }: { id: string }) { const reopen_issue = useCallback(() => { setLoading('reopen', true) set_to_loading(3) + if (needComment) { + save_comment() + needComment = false + } reopenIssue( { link: id }, { @@ -179,7 +185,7 @@ export default function IssueDetailPage({ id }: { id: string }) { onSettled: () => setLoading('reopen', false) } ) - }, [id, router, reopenIssue]) + }, [id, router, reopenIssue, save_comment]) const editorRef = useRef(null) const onKeyDownScrollHandler = useHandleBottomScrollOffset({ @@ -267,6 +273,14 @@ export default function IssueDetailPage({ id }: { id: string }) { } } + const handleCloseChange = (html: string) => { + if (html && html === '

') { + needComment = false + } else { + needComment = true + } + } + return ( <>
@@ -301,7 +315,7 @@ export default function IssueDetailPage({ id }: { id: string }) {
) : ( - + )} {info && info.status === 'open' && ( @@ -371,6 +385,7 @@ export default function IssueDetailPage({ id }: { id: string }) { content={EMPTY_HTML} autofocus={true} onKeyDown={onKeyDownScrollHandler} + onChange={(html) => handleCloseChange(html)} />
) -} +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/IssueList.tsx b/moon/apps/web/components/Issues/IssueList.tsx index 1876f4ee6..cd6001b8a 100644 --- a/moon/apps/web/components/Issues/IssueList.tsx +++ b/moon/apps/web/components/Issues/IssueList.tsx @@ -414,4 +414,4 @@ export const ListItem = memo( ) } ) -ListItem.displayName = 'ListItem' +ListItem.displayName = 'ListItem' \ No newline at end of file diff --git a/moon/apps/web/components/Issues/IssueNewPage.tsx b/moon/apps/web/components/Issues/IssueNewPage.tsx index fb66475e3..05a04b5f5 100644 --- a/moon/apps/web/components/Issues/IssueNewPage.tsx +++ b/moon/apps/web/components/Issues/IssueNewPage.tsx @@ -385,4 +385,4 @@ export const SideBarItem = ({ emptyState }: { emptyState: string }) => {
) -} +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/IssuePage.tsx b/moon/apps/web/components/Issues/IssuePage.tsx deleted file mode 100644 index 58247d845..000000000 --- a/moon/apps/web/components/Issues/IssuePage.tsx +++ /dev/null @@ -1,152 +0,0 @@ -'use client' - -import React, { useCallback, useEffect, useState } from 'react' -import { Flex, List, PaginationProps, Tabs, TabsProps, Tag } from 'antd' -import { formatDistance, fromUnixTime } from 'date-fns' -import { useRouter } from 'next/router' - -// import { CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons' -import { Button, Link } from '@gitmono/ui' - -import { Heading } from '@/components/Catalyst/Heading' -import { useGetIssueLists } from '@/hooks/issues/useGetIssueLists' -import { apiErrorToast } from '@/utils/apiErrorToast' - -interface Item { - closed_at?: number | null - link: string - author: string - title: string - status: string - open_timestamp: number - updated_at: number -} - -export default function IssuePage() { - const router = useRouter() - const [itemList, setItemList] = useState([]) - const [numTotal, setNumTotal] = useState(0) - const [pageSize, _setPageSize] = useState(10) - const [loading, setLoading] = useState(false) - const [status, setStatus] = useState('open') - const { mutate: issueLists } = useGetIssueLists() - - const fetchData = useCallback( - (page: number, per_page: number) => { - setLoading(true) - - issueLists( - { - data: { pagination: { page, per_page }, additional: { - status, - asc: false - } } - }, - { - onSuccess: (response) => { - const data = response.data - - setItemList(data?.items ?? []) - setNumTotal(data?.total ?? 0) - }, - onError: apiErrorToast, - onSettled: () => setLoading(false) - } - ) - }, - - [status, issueLists] - ) - - useEffect(() => { - fetchData(1, pageSize) - }, [pageSize, fetchData]) - - const getStatusTag = (status: string) => { - switch (status) { - case 'open': - return open - case 'closed': - return closed - } - } - - // const getStatusIcon = (status: string) => { - // switch (status) { - // case 'open': - // // return - // case 'closed': - // // return - // } - // } - - const getDescription = (item: Item) => { - switch (item.status) { - case 'open': - return `Issue opened by Admin ${formatDistance(fromUnixTime(item.open_timestamp), new Date(), { addSuffix: true })} ` - case 'closed': - return `Issue ${item.link} closed by Admin ${formatDistance(fromUnixTime(item.updated_at), new Date(), { addSuffix: true })}` - } - } - - const onChange: PaginationProps['onChange'] = (current, pageSize) => { - fetchData(current, pageSize) - } - - const tabsChange = (activeKey: string) => { - if (activeKey === '1') { - setStatus('open') - } else { - setStatus('closed') - } - } - - const tab_items: TabsProps['items'] = [ - { - key: '1', - label: 'Open' - }, - { - key: '2', - label: 'Closed' - } - ] - - return ( - <> -
- Issues - - - - - - - ( - - - // getStatusIcon(item.status) - // } - title={ - - {item.title} {getStatusTag(item.status)} - - } - description={getDescription(item)} - /> - - )} - /> -
- - ) -} diff --git a/moon/apps/web/components/Issues/IssuesContent.tsx b/moon/apps/web/components/Issues/IssuesContent.tsx index 51ad6d0d7..2c6f5f24a 100644 --- a/moon/apps/web/components/Issues/IssuesContent.tsx +++ b/moon/apps/web/components/Issues/IssuesContent.tsx @@ -3,6 +3,7 @@ import { CheckIcon, IssueClosedIcon, IssueOpenedIcon, SkipIcon } from '@primer/o import { useInfiniteQuery } from '@tanstack/react-query' import { formatDistance, fromUnixTime } from 'date-fns' import { useAtom } from 'jotai' +import { useRouter } from 'next/router' import { LabelItem, @@ -11,7 +12,6 @@ import { PostApiIssueListData } from '@gitmono/types/generated' import { Button, ChatBubbleIcon, ChevronDownIcon, OrderedListIcon } from '@gitmono/ui' -import { Link } from '@gitmono/ui/Link' // import { MenuItem } from '@gitmono/ui/Menu' @@ -25,9 +25,10 @@ import { ListBanner, ListItem } from '@/components/Issues/IssueList' -import { filterAtom, sortAtom } from '@/components/Issues/utils/store' +import { filterAtom, issueCloseCurrentPage, issueOpenCurrentPage, sortAtom } from '@/components/Issues/utils/store' import { useScope } from '@/contexts/scope' import { useGetIssueLists } from '@/hooks/issues/useGetIssueLists' +import { useGetOrganizationMember } from '@/hooks/useGetOrganizationMember' import { useSyncedMembers } from '@/hooks/useSyncedMembers' import { apiErrorToast } from '@/utils/apiErrorToast' import { atomWithWebStorage } from '@/utils/atomWithWebStorage' @@ -74,7 +75,7 @@ export function IssuesContent({ searching }: Props) { const [pageSize, _setPageSize] = useState(10) - const [status, _setStatus] = useAtom(filterAtom({ scope, part: 'issue' })) + const [status, _setStatus] = useAtom(filterAtom({ part: 'issue' })) const [issueList, setIssueList] = useState([]) @@ -96,6 +97,13 @@ export function IssuesContent({ searching }: Props) { const { members } = useSyncedMembers() + const router = useRouter() + + + + const [openCurrent, setopenCurrent] = useAtom(issueOpenCurrentPage) + const [closeCurrent, setcloseCurrent] = useAtom(issueCloseCurrentPage) + const MemberConfig: MenuConfig[] = [ { key: 'Author', @@ -103,6 +111,7 @@ export function IssuesContent({ searching }: Props) { onSelectFactory: (item: Member) => (e: Event) => { e.preventDefault() if (item.user.username === sort['Author']) { + status === 'open' ? setopenCurrent(1) : setcloseCurrent(1) fetchData(1, pageSize) setSort({ ...sort, @@ -124,6 +133,7 @@ export function IssuesContent({ searching }: Props) { onSelectFactory: (item: Member) => (e: Event) => { e.preventDefault() if (item.user.username === sort['Assignees']) { + status === 'open' ? setopenCurrent(1) : setcloseCurrent(1) fetchData(1, pageSize) setSort({ ...sort, @@ -228,6 +238,7 @@ export function IssuesContent({ searching }: Props) { const news = label.map((i) => Number(i)) const addtion = additions(news) + status === 'open' ? setopenCurrent(1) : setcloseCurrent(1) fetchData(1, pageSize, addtion) } } @@ -339,8 +350,12 @@ export function IssuesContent({ searching }: Props) { ) useEffect(() => { - fetchData(1, pageSize) - }, [pageSize, fetchData]) + if (status === 'open') { + fetchData(openCurrent, pageSize) + } else if (status === 'closed') { + fetchData(closeCurrent, pageSize) + } + }, [pageSize, fetchData, openCurrent, closeCurrent, status]) // if (loading) { // return @@ -353,6 +368,10 @@ export function IssuesContent({ searching }: Props) { return } + const handlePageChange = (page: number) => { + status === 'open' ? setopenCurrent(page) : setcloseCurrent(page) + } + const getStatusIcon = (status: string) => { const normalizedStatus = status.toLowerCase() @@ -372,7 +391,7 @@ export function IssuesContent({ searching }: Props) { {searching ? ( <> - + ) : ( <> @@ -392,23 +411,37 @@ export function IssuesContent({ searching }: Props) { > {(issueList) => { return issueList.map((i) => ( - - } - > -
- {i.link} · {i.author} {i.status}{' '} - {formatDistance(fromUnixTime(i.open_timestamp), new Date(), { addSuffix: true })} -
-
- + } + onClick={() => router.push(`/${scope}/issue/${i.link}`)} + > +
+ {i.link} · {i.author} {i.status}{' '} + {formatDistance(fromUnixTime(i.open_timestamp), new Date(), { addSuffix: true })} +
+
)) }} - + {numTotal > 10 && status === 'open' && ( + handlePageChange(page)} + /> + )} + {numTotal > 10 && status === 'closed' && ( + handlePageChange(page)} + /> + )} )} @@ -424,20 +457,27 @@ function IssueSearchList(_props: { searchIssueList?: Item[]; hideProject?: boole ) } -export const RightAvatar = ({ member, commentNum }: { member?: Member; commentNum?: number }) => { +export const RightAvatar = ({ item }: { item: ItemsType[number] }) => { + const shouldFetch = item.assignees.length > 0 + + const { data } = useGetOrganizationMember({ username: item.assignees[0], org: 'mega', enabled: shouldFetch }) + return ( <> -
-
- - {commentNum !== 0 && {commentNum}} -
- {member && ( - - +
+ {item.comment_num !== 0 && ( +
+ + {item.comment_num} +
+ )} + {data && ( + //
展示头像
+ + )}
) -} +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/MemberHoverCardNE.tsx b/moon/apps/web/components/Issues/MemberHoverCardNE.tsx index 07d60a741..8a9661dd0 100644 --- a/moon/apps/web/components/Issues/MemberHoverCardNE.tsx +++ b/moon/apps/web/components/Issues/MemberHoverCardNE.tsx @@ -2,13 +2,49 @@ import React, { useState } from 'react' import * as HoverCard from '@radix-ui/react-hover-card' import { AnimatePresence, m } from 'framer-motion' -import { SyncOrganizationMember as Member } from '@gitmono/types/generated' +import { OrganizationMember as Member } from '@gitmono/types/generated' import { ANIMATION_CONSTANTS, Button, ChatBubbleIcon } from '@gitmono/ui' import { MemberAvatar } from '@/components/MemberAvatar' // import { useScope } from '@/contexts/scope' +export interface OutPut { + id: string + role: string + created_at: Date + deactivated: boolean + is_organization_member: boolean + user: User + status: null +} + +export interface User { + id: string + avatar_url: string + avatar_urls: AvatarUrls + cover_photo_url: null + email: string + username: string + display_name: string + system: boolean + integration: boolean + notifications_paused: boolean + notification_pause_expires_at: null + timezone: null + logged_in: boolean + type_name: string +} + +export interface AvatarUrls { + xs: string + sm: string + base: string + lg: string + xl: string + xxl: string +} + export function MemberHovercard({ member, username, @@ -100,4 +136,4 @@ export function MemberHovercard({ ) -} +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/Pagenation.tsx b/moon/apps/web/components/Issues/Pagenation.tsx index 0ed3fab89..021503a91 100644 --- a/moon/apps/web/components/Issues/Pagenation.tsx +++ b/moon/apps/web/components/Issues/Pagenation.tsx @@ -5,24 +5,27 @@ import { Button, ButtonProps, ChevronLeftIcon, ChevronRightIcon } from '@gitmono import { cn } from '@gitmono/ui/src/utils' import { BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar' +import { atomWithWebStorage } from '@/utils/atomWithWebStorage' import { getPages } from './utils/getPages' -import { currentPage } from './utils/store' -interface PaginationType { +// import { currentPage } from './utils/store' + +interface PaginationType { totalNum: number pageSize: number onChange?: (page: number) => void + currentPage: ReturnType> } -export const Pagination = ({ totalNum, pageSize, onChange }: PaginationType) => { +export const Pagination = ({ totalNum, pageSize, onChange, currentPage }: PaginationType) => { if (totalNum < 0 || pageSize < 0) throw new Error('invalid props') const totalPages = Math.ceil(totalNum / pageSize) const [pages, setPages] = useState<(number | '...')[]>([]) const [current, setCurrent] = useAtom(currentPage) const handleChange = (page: number) => { if (page < 1 || page > totalPages) return - setCurrent(page) + setCurrent(page as T) onChange?.(page) } @@ -106,4 +109,4 @@ const PreviousOrNext = ({ isNext, color, ...rest }: PreviousOrNext) => { )} ) -} +} \ No newline at end of file diff --git a/moon/apps/web/components/Issues/utils/store.tsx b/moon/apps/web/components/Issues/utils/store.tsx index fa6ca7986..f5c3edb8c 100644 --- a/moon/apps/web/components/Issues/utils/store.tsx +++ b/moon/apps/web/components/Issues/utils/store.tsx @@ -1,14 +1,20 @@ import { CookieValueTypes } from 'cookies-next' +import { atom } from 'jotai' import { atomFamily } from 'jotai/utils' import { atomWithWebStorage } from '@/utils/atomWithWebStorage' export type IssueIndexFilterType = 'open' | 'closed' | 'Merged' | 'draft' +// export const filterAtom = atomFamily( +// ({ scope, part }: { scope: CookieValueTypes; part: string }) => +// atomWithWebStorage(`${scope}:${part}-index-filter`, 'open'), +// (a, b) => a.scope === b.scope && a.part === b.part +// ) + export const filterAtom = atomFamily( - ({ scope, part }: { scope: CookieValueTypes; part: string }) => - atomWithWebStorage(`${scope}:${part}-index-filter`, 'open'), - (a, b) => a.scope === b.scope && a.part === b.part + ({ part: _part }: { part: string }) => atom<'open' | 'closed'>('open'), + (a, b) => a.part === b.part ) export interface IssueSortType { @@ -24,3 +30,9 @@ export const sortAtom = atomFamily( export const darkModeAtom = atomWithWebStorage('darkMode', false) export const currentPage = atomWithWebStorage('currentPage', 1) + +export const issueOpenCurrentPage = atomWithWebStorage('IssueOpencurrentPage', 1) +export const issueCloseCurrentPage = atomWithWebStorage('IssueClosecurrentPage', 1) + +export const mrOpenCurrentPage = atomWithWebStorage('MROpencurrentPage', 1) +export const mrCloseCurrentPage = atomWithWebStorage('MRClosecurrentPage', 1) \ No newline at end of file diff --git a/moon/apps/web/components/MrView/index.tsx b/moon/apps/web/components/MrView/index.tsx index e3455dfa7..e6ba036bd 100644 --- a/moon/apps/web/components/MrView/index.tsx +++ b/moon/apps/web/components/MrView/index.tsx @@ -4,10 +4,10 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react' import { GitMergeIcon, GitPullRequestClosedIcon, GitPullRequestIcon } from '@primer/octicons-react' import { formatDistance, fromUnixTime } from 'date-fns' import { useAtom } from 'jotai' +import { useRouter } from 'next/router' import { LabelItem, SyncOrganizationMember as Member, PostApiMrListData } from '@gitmono/types/generated' import { Button, CheckIcon, ChevronDownIcon, OrderedListIcon } from '@gitmono/ui' -import { Link } from '@gitmono/ui/Link' import { cn } from '@gitmono/ui/src/utils' import { IssueIndexTabFilter as MRIndexTabFilter } from '@/components/Issues/IssueIndex' @@ -32,7 +32,7 @@ import { AdditionType, RightAvatar } from '../Issues/IssuesContent' import { Pagination } from '../Issues/Pagenation' import { orderTags, reviewTags, tags } from '../Issues/utils/consts' import { generateAllMenuItems, MenuConfig } from '../Issues/utils/generateAllMenuItems' -import { filterAtom, sortAtom } from '../Issues/utils/store' +import { filterAtom, mrCloseCurrentPage, mrOpenCurrentPage, sortAtom } from '../Issues/utils/store' import { Heading } from './catalyst/heading' // interface MrInfoItem { @@ -51,9 +51,9 @@ export default function MrView() { const [mrList, setMrList] = useState([]) const [numTotal, setNumTotal] = useState(0) const [pageSize] = useState(10) - const [status, _setStatus] = useAtom(filterAtom({ scope, part: 'mr' })) + const [status, _setStatus] = useAtom(filterAtom({ part: 'mr' })) // const [status, _setStatus] = useState('open') - const [page, _setPage] = useState(1) + const [page, setPage] = useState(1) const [isLoading, setIsLoading] = useState(false) const { mutate: fetchMrList } = usePostMrList() const [sort, setSort] = useAtom(sortAtom({ scope, filter: 'sortPickerMR' })) @@ -64,6 +64,9 @@ export default function MrView() { [scope] ) + // const [openCurrent, setopenCurrent] = useAtom(mrOpenCurrentPage) + // const [closeCurrent, setcloseCurrent] = useAtom(mrCloseCurrentPage) + const reviewAtom = useMemo(() => atomWithWebStorage(`${scope}:mr-review`, ''), [scope]) const labelAtom = useMemo(() => atomWithWebStorage(`${scope}:mr-label`, []), [scope]) @@ -395,6 +398,12 @@ export default function MrView() { } } + const handlePageChange = (page: number) => { + setPage(page) + } + + const router = useRouter() + return (
Merge Request @@ -424,23 +433,38 @@ export default function MrView() { > {(issueList) => { return issueList.map((i) => ( - - } - > -
- {i.link} {i.status} {getDescription(i)} -
-
- + router.push(`/${scope}/mr/${i.link}`)} + title={i.title} + leftIcon={getStatusIcon(i.status)} + rightIcon={} + > +
+ {i.link} {i.status} {getDescription(i)} +
+
)) }} - + {numTotal > 10 && status === 'open' && ( + handlePageChange(page)} + /> + )} + {numTotal > 10 && status === 'closed' && ( + handlePageChange(page)} + /> + )}
) -} +} \ No newline at end of file diff --git a/moon/apps/web/package.json b/moon/apps/web/package.json index c6ff39d21..e65e38edd 100644 --- a/moon/apps/web/package.json +++ b/moon/apps/web/package.json @@ -18,7 +18,6 @@ "@100mslive/hms-noise-cancellation": "catalog:", "@100mslive/hms-video-store": "catalog:", "@100mslive/react-sdk": "catalog:", - "@ant-design/icons": "catalog:", "@emoji-mart/data": "catalog:", "@emotion/styled": "catalog:", "@git-diff-view/react": "catalog:", @@ -61,7 +60,6 @@ "@todesktop/client-core": "catalog:", "@vercel/og": "catalog:", "@vercel/speed-insights": "catalog:", - "antd": "catalog:", "clsx": "catalog:", "cookies-next": "catalog:", "copy-to-clipboard": "catalog:", @@ -178,4 +176,4 @@ "peerDependencies": { "y-prosemirror": "^1.2.12" } -} +} \ No newline at end of file diff --git a/moon/apps/web/pages/[org]/code/blob/[...path].tsx b/moon/apps/web/pages/[org]/code/blob/[...path].tsx index 084c9d637..5ab838272 100644 --- a/moon/apps/web/pages/[org]/code/blob/[...path].tsx +++ b/moon/apps/web/pages/[org]/code/blob/[...path].tsx @@ -1,20 +1,21 @@ import React from 'react' -import { Flex, Layout } from 'antd' -import BreadCrumb from '@/components/CodeView/TreeView/BreadCrumb' +import { useRouter } from 'next/router' + import CodeContent from '@/components/CodeView/BlobView/CodeContent' +import CommitHistory, { CommitInfo } from '@/components/CodeView/CommitHistory' +import BreadCrumb from '@/components/CodeView/TreeView/BreadCrumb' +import RepoTree from '@/components/CodeView/TreeView/RepoTree' import { AppLayout } from '@/components/Layout/AppLayout' import AuthAppProviders from '@/components/Providers/AuthAppProviders' import { useGetBlob } from '@/hooks/useGetBlob' -import { useRouter } from 'next/router' -import CommitHistory, { CommitInfo } from '@/components/CodeView/CommitHistory' -import RepoTree from '@/components/CodeView/TreeView/RepoTree' const codeStyle = { borderRadius: 8, background: '#fff', border: '1px solid #d1d9e0', margin: '0 8px', - width: 'calc(80% - 8px)', + // width: 'calc(80% - 8px)' + width: '100%' } const treeStyle = { @@ -27,7 +28,7 @@ const treeStyle = { function BlobPage() { const { path = [] } = useRouter().query as { path?: string[] } const new_path = '/' + path.join('/') - const fileContent = useGetBlob({ path: new_path }).data?.data?? "" + const fileContent = useGetBlob({ path: new_path }).data?.data ?? '' const commitInfo: CommitInfo = { user: { avatar_url: 'https://avatars.githubusercontent.com/u/112836202?v=4&size=40', @@ -39,29 +40,29 @@ function BlobPage() { } return ( -
- - +
+
+
- +
{/* tree */} - - - - +
+
+ +
- - - - - - - - - - - - +
+
+ +
+
+
+ +
+
+
+
+
) } @@ -86,4 +87,4 @@ BlobPage.getProviders = ( ) } -export default BlobPage +export default BlobPage \ No newline at end of file diff --git a/moon/apps/web/pages/[org]/code/tree/[...path]/index.tsx b/moon/apps/web/pages/[org]/code/tree/[...path]/index.tsx index 3cd57c12a..de749500f 100644 --- a/moon/apps/web/pages/[org]/code/tree/[...path]/index.tsx +++ b/moon/apps/web/pages/[org]/code/tree/[...path]/index.tsx @@ -2,19 +2,20 @@ import React, { useMemo, useState } from 'react' import { Theme } from '@radix-ui/themes' -import { Flex, Layout } from 'antd' import { useParams } from 'next/navigation' + import { CommonResultVecTreeCommitItem } from '@gitmono/types/generated' + import CodeTable from '@/components/CodeView/CodeTable' +import CommitHistory from '@/components/CodeView/CommitHistory' import BreadCrumb from '@/components/CodeView/TreeView/BreadCrumb' import CloneTabs from '@/components/CodeView/TreeView/CloneTabs' import RepoTree from '@/components/CodeView/TreeView/RepoTree' import { AppLayout } from '@/components/Layout/AppLayout' import AuthAppProviders from '@/components/Providers/AuthAppProviders' +import { useGetBlob } from '@/hooks/useGetBlob' import { useGetTreeCommitInfo } from '@/hooks/useGetTreeCommitInfo' import { useGetTreePathCanClone } from '@/hooks/useGetTreePathCanClone' -import CommitHistory from '@/components/CodeView/CommitHistory' -import { useGetBlob } from '@/hooks/useGetBlob' function TreeDetailPage() { const params = useParams() @@ -30,8 +31,7 @@ function TreeDetailPage() { const { data: canClone } = useGetTreePathCanClone({ path: newPath }) const reqPath = `${new_path}/README.md` - const {data: readmeContent}=useGetBlob({path:reqPath}) - + const { data: readmeContent } = useGetBlob({ path: reqPath }) const commitInfo = { user: { @@ -55,7 +55,7 @@ function TreeDetailPage() { borderRadius: 8, overflow: 'hidden', width: 'calc(80% - 8px)', - height:'100%', + height: '100%', background: '#fff' } @@ -69,39 +69,34 @@ function TreeDetailPage() { return (
- - - - - {canClone?.data && ( - - - - )} - - {/* tree */} - - setNewPath(path)} /> - - - - { - commitInfo && - - - } - setNewPath(path)} - readmeContent={readmeContent?.data} +
+
+ + {canClone?.data && ( +
+ +
+ )} +
+ {/* tree */} +
+ setNewPath(path)} /> +
+ +
+ {commitInfo && ( +
+ +
+ )} + setNewPath(path)} + readmeContent={readmeContent?.data} /> - - - - +
+
) } @@ -128,4 +123,4 @@ TreeDetailPage.getProviders = ( ) } -export default TreeDetailPage +export default TreeDetailPage \ No newline at end of file diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx index 54132c883..9a0180172 100644 --- a/moon/apps/web/pages/[org]/mr/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -1,84 +1,96 @@ 'use client' -import React, { useRef, useState } from 'react'; -import { PicturePlusIcon} from '@gitmono/ui/Icons' -import { useRouter } from 'next/router'; -import FileDiff from '@/components/DiffView/FileDiff'; -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'; -import { PageWithLayout } from '@/utils/types'; +import React, { useRef, useState } from 'react' +import { ChecklistIcon, CommentDiscussionIcon, FileDiffIcon } from '@primer/octicons-react' +import { useRouter } from 'next/router' +import { toast } from 'react-hot-toast' + +import { ConversationItem } from '@gitmono/types/generated' +import { Button, LoadingSpinner, UIText } from '@gitmono/ui' +import { PicturePlusIcon } from '@gitmono/ui/Icons' +import { cn } from '@gitmono/ui/utils' + +import { EMPTY_HTML } from '@/atoms/markdown' +import FileDiff from '@/components/DiffView/FileDiff' +import { AppLayout } from '@/components/Layout/AppLayout' +import TimelineItems from '@/components/MrView/TimelineItems' +import { useHandleBottomScrollOffset } from '@/components/NoteEditor/useHandleBottomScrollOffset' +import AuthAppProviders from '@/components/Providers/AuthAppProviders' +import { ComposerReactionPicker } from '@/components/Reactions/ComposerReactionPicker' +import { SimpleNoteContent, SimpleNoteContentRef } from '@/components/SimpleNoteEditor/SimpleNoteContent' +import { useScope } from '@/contexts/scope' import { useGetMrDetail } from '@/hooks/useGetMrDetail' -import { useGetMrFilesChanged } from '@/hooks/useGetMrFilesChanged'; +import { useGetMrFilesChanged } from '@/hooks/useGetMrFilesChanged' +import { usePostMrClose } from '@/hooks/usePostMrClose' import { usePostMrComment } from '@/hooks/usePostMrComment' import { usePostMrMerge } from '@/hooks/usePostMrMerge' -import { usePostMrReopen } from '@/hooks/usePostMrReopen'; -import { usePostMrClose } from '@/hooks/usePostMrClose'; -import { useScope } from '@/contexts/scope' -import { SimpleNoteContent, SimpleNoteContentRef } from '@/components/SimpleNoteEditor/SimpleNoteContent'; -import { EMPTY_HTML } from '@/atoms/markdown' -import { useHandleBottomScrollOffset } from '@/components/NoteEditor/useHandleBottomScrollOffset' +import { usePostMrReopen } from '@/hooks/usePostMrReopen' +import { useUploadHelpers } from '@/hooks/useUploadHelpers' 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, ChecklistIcon } from '@primer/octicons-react' -import TimelineItems from '@/components/MrView/TimelineItems'; -import { ConversationItem } from '@gitmono/types/generated'; +import { PageWithLayout } from '@/utils/types' const { UnderlinePanels } = require('@primer/react/experimental') export interface MRDetail { - status: string, - conversations: ConversationItem[], - title: string, + status: string + conversations: ConversationItem[] + title: string } -const MRDetailPage:PageWithLayout = () =>{ - const router = useRouter(); - const { id : tempId } = router.query; - const { scope } = useScope() - const [login, _setLogin] = useState(true); - const [isReactionPickerOpen, setIsReactionPickerOpen] = useState(false) - const id = typeof tempId === 'string' ? tempId : ''; - const { data: MrDetailData, isLoading: detailIsLoading } = useGetMrDetail(id) - const mrDetail = MrDetailData?.data as MRDetail | undefined - - if (mrDetail && typeof mrDetail.status === 'string') { - mrDetail.status = mrDetail.status.toLowerCase(); - } +let needComment = false - const { data: MrFilesChangedData, isLoading: fileChgIsLoading} = useGetMrFilesChanged(id) +const MRDetailPage: PageWithLayout = () => { + const router = useRouter() + const { id: tempId } = router.query + const { scope } = useScope() + const [login, _setLogin] = useState(true) + const [isReactionPickerOpen, setIsReactionPickerOpen] = useState(false) + const id = typeof tempId === 'string' ? tempId : '' + const { data: MrDetailData, isLoading: detailIsLoading } = useGetMrDetail(id) + const mrDetail = MrDetailData?.data as MRDetail | undefined + const [closeHint, setCloseHint] = useState('Close Merge Request') - const { mutate: approveMr, isPending : mrMergeIsPending } = usePostMrMerge(id) - const handleMrApprove = () => { - approveMr(undefined, { - onSuccess: () => { - router.push(`/${scope}/mr`) - }, - }) - } + if (mrDetail && typeof mrDetail.status === 'string') { + mrDetail.status = mrDetail.status.toLowerCase() + } + + const { data: MrFilesChangedData, isLoading: fileChgIsLoading } = useGetMrFilesChanged(id) - const { mutate: closeMr, isPending: mrCloseIsPending } = usePostMrClose(id) - const handleMrClose = () => { - closeMr(undefined, { - onSuccess: () => { - router.push(`/${scope}/mr`) - }, - }) + const { mutate: approveMr, isPending: mrMergeIsPending } = usePostMrMerge(id) + const handleMrApprove = () => { + approveMr(undefined, { + onSuccess: () => { + router.push(`/${scope}/mr`) + } + }) + } + + const { mutate: closeMr, isPending: mrCloseIsPending } = usePostMrClose(id) + const handleMrClose = () => { + if (closeHint === 'Close with comment') { + send_comment() } + closeMr(undefined, { + onSuccess: () => { + router.push(`/${scope}/mr`) + } + }) + } - const { mutate: reopenMr, isPending: mrReopenIsPending } = usePostMrReopen(id) - const handleMrReopen = () => { - reopenMr(undefined,{ - onSuccess: () => { - router.push(`/${scope}/mr`) - }, - }) + const { mutate: reopenMr, isPending: mrReopenIsPending } = usePostMrReopen(id) + const handleMrReopen = () => { + if (needComment) { + send_comment() + needComment = false } + reopenMr(undefined, { + onSuccess: () => { + router.push(`/${scope}/mr`) + } + }) + } - const { mutate: postMrComment, isPending : mrCommentIsPending } = usePostMrComment(id) + const { mutate: postMrComment, isPending: mrCommentIsPending } = usePostMrComment(id) const send_comment = () => { const currentContentHTML = editorRef.current?.editor?.getHTML() ?? '

'; @@ -101,14 +113,24 @@ const MRDetailPage:PageWithLayout = () =>{ } } - const buttonClasses= 'cursor-pointer'; - const editorRef = useRef(null); - const onKeyDownScrollHandler = useHandleBottomScrollOffset({ - editor: editorRef.current?.editor - }) - const { dropzone } = useUploadHelpers({ - upload: editorRef.current?.uploadAndAppendAttachments - }) + const buttonClasses = 'cursor-pointer' + const editorRef = useRef(null) + const onKeyDownScrollHandler = useHandleBottomScrollOffset({ + editor: editorRef.current?.editor + }) + const { dropzone } = useUploadHelpers({ + upload: editorRef.current?.uploadAndAppendAttachments + }) + + const handleChange = (html: string) => { + if (html && html === '

') { + setCloseHint('Close Merge Request') + needComment = false + } else { + setCloseHint('Close with comment') + needComment = true + } + } return (
@@ -123,38 +145,39 @@ const MRDetailPage:PageWithLayout = () =>{ Checks Files Changed -
+
{detailIsLoading ? (
- ) : ( - mrDetail && + ) : ( + mrDetail && )}
-
- {mrDetail && mrDetail.status === "open" && +
+ {mrDetail && mrDetail.status === 'open' && ( - } + )}

Add a comment

-
+
handleChange(html)} />
-
- {mrDetail && mrDetail.status === "open" && +
+ {mrDetail && mrDetail.status === 'open' && ( - } - {mrDetail && mrDetail.status === "closed" && + )} + {mrDetail && mrDetail.status === 'closed' && ( - } + )}