Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 25 additions & 35 deletions moon/apps/web/components/Issues/IssueIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,30 @@

import { useState } from 'react'
import { useAtom } from 'jotai'
import { useRouter } from 'next/router'
import { useDebounce } from 'use-debounce'

import { Button, LayeredHotkeys, UIText } from '@gitmono/ui'
// import { useDebounce } from 'use-debounce'

import { Button, LayeredHotkeys, Link, UIText } from '@gitmono/ui'
import { cn } from '@gitmono/ui/src/utils'

import { FloatingNewDocButton } from '@/components/FloatingButtons/NewDoc'
import {
IndexPageContainer,
IndexPageContent,
IndexPageEmptyState,
IndexSearchInput
} from '@/components/IndexPages/components'
import { IndexPageContainer, IndexPageContent, IndexPageEmptyState } from '@/components/IndexPages/components'
import { SplitViewContainer, SplitViewDetail } from '@/components/SplitView'
import { IssueBreadcrumbIcon } from '@/components/Titlebar/BreadcrumbPageIcons'
import { BreadcrumbLabel, BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar'
import { BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar'
import { useScope } from '@/contexts/scope'

import { IssuesContent } from './IssuesContent'
import IssueSearch from './IssueSearch'
import { filterAtom } from './utils/store'

export const IssueIndex = () => {
const [query, setQuery] = useState('')
const [queryDebounced] = useDebounce(query, 150)
const [query, _setQuery] = useState('')
Comment thread
liuyangjuncong20202570 marked this conversation as resolved.
// const [queryDebounced] = useDebounce(query, 150)

const isSearching = query.length > 0
// const isSearchLoading = queryDebounced.length > 0 && getNotes.isFetching
const isSearchLoading = queryDebounced.length > 0
// const isSearchLoading = queryDebounced.length > 0

return (
<>
Expand All @@ -38,15 +34,9 @@ export const IssueIndex = () => {
<IndexPageContainer>
<BreadcrumbTitlebar className='justify-between'>
<IssueBreadcrumbIcon />
<BreadcrumbLabel>Issue</BreadcrumbLabel>
<IndexSearchInput query={query} setQuery={setQuery} isSearchLoading={isSearchLoading} />

<Button variant='primary' size={'base'}>
Labels
</Button>
<NewIssueButton />
</BreadcrumbTitlebar>
<IndexPageContent id='/[org]/issue' className={cn('@container', '3xl:max-w-7xl max-w-7xl')}>
<IssueSearch />
<IssuesContent searching={isSearching} />
</IndexPageContent>
</IndexPageContainer>
Expand All @@ -57,17 +47,23 @@ export const IssueIndex = () => {
}

export function IssueIndexTabFilter({
part,
fullWidth = false,
openNum,
closeNum
closeNum,
openTooltip,
closeTooltip
}: {
part: string
fullWidth?: boolean
openNum?: number
closeNum?: number
openTooltip?: string
closeTooltip?: string
}) {
const { scope } = useScope()

const [filter, setFilter] = useAtom(filterAtom(scope))
const [filter, setFilter] = useAtom(filterAtom({ scope, part: `${part}` }))

return (
<>
Expand All @@ -79,7 +75,7 @@ export function IssueIndexTabFilter({
fullWidth={fullWidth}
onClick={() => setFilter('open')}
variant={filter === 'open' ? 'flat' : 'plain'}
tooltip='Issues that are still open and need attention'
tooltip={openTooltip}
>
Open {openNum}
</Button>
Expand All @@ -88,7 +84,7 @@ export function IssueIndexTabFilter({
fullWidth={fullWidth}
onClick={() => setFilter('closed')}
variant={filter === 'closed' ? 'flat' : 'plain'}
tooltip='Closed'
tooltip={closeTooltip}
>
Closed {closeNum}
</Button>
Expand All @@ -97,20 +93,14 @@ export function IssueIndexTabFilter({
}

export const NewIssueButton = () => {
const router = useRouter()
const { scope } = useScope()

return (
<Button
variant='primary'
className='bg-[#1f883d]'
size={'base'}
onClick={() => {
router.push(`/${scope}/issue/new`)
}}
>
New Issue
</Button>
<Link href={`/${scope}/issue/new`}>
<Button variant='primary' className='bg-[#1f883d]' size={'base'}>
New Issue
</Button>
</Link>
)
}

Expand Down
41 changes: 26 additions & 15 deletions moon/apps/web/components/Issues/IssueList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Command,
ConditionalWrap,
LazyLoadingSpinner,
LoadingSpinner,
SearchIcon,
useCommand
} from '@gitmono/ui'
Expand All @@ -21,36 +22,44 @@ import { SubjectCommand } from '@/components/Subject/SubjectCommand'
import { BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar'

import { MemberAvatar } from '../MemberAvatar'
import { IssueIndexTabFilter } from './IssueIndex'

export function IssueList<T>({
Issuelists,
header,
children
children,
isLoading = false
}: {
Issuelists: T[]
hideProject?: boolean
header?: React.ReactNode
children?: (issue: T[]) => React.ReactNode
isLoading?: boolean
}) {
const needsCommandWrap = !useCommand()
const isDark = useAtomValue(darkModeAtom)

return (
<>
{!isDark ? (
<div className='issuecontainer overflow-hidden rounded-md border border-[#d0d7de]'>
<div className='max-h-[600px] overflow-auto rounded-md border border-[#d0d7de]'>
{header}
<ConditionalWrap
condition={needsCommandWrap}
wrap={(children) => (
<SubjectCommand>
<Command.List className='flex flex-1 flex-col'>{children}</Command.List>
</SubjectCommand>
)}
>
{children?.(Issuelists)}
</ConditionalWrap>

{isLoading ? (
<div className='flex h-[400px] items-center justify-center'>
<LoadingSpinner />
</div>
) : (
<ConditionalWrap
condition={needsCommandWrap}
wrap={(children) => (
<SubjectCommand>
<Command.List className='flex flex-1 flex-col'>{children}</Command.List>
</SubjectCommand>
)}
>
{children?.(Issuelists)}
</ConditionalWrap>
)}
</div>
) : (
<div>darkMode</div>
Expand All @@ -62,16 +71,18 @@ export function IssueList<T>({
interface ListBannerProps {
pickerTypes: string[]
children?: (p: string) => React.ReactNode
tabfilter?: React.ReactNode
}

export const ListBanner = forwardRef<HTMLDivElement, ListBannerProps>(
({ pickerTypes, children }: ListBannerProps, ref) => {
({ pickerTypes, children, tabfilter }: ListBannerProps, ref) => {
return (
<>
<div ref={ref}>
<BreadcrumbTitlebar className='justify-between'>
<ConditionalWrap condition={true} wrap={(c) => <div>{c}</div>}>
<IssueIndexTabFilter />
{tabfilter}
{/* <IssueIndexTabFilter /> */}
</ConditionalWrap>
<ConditionalWrap condition={true} wrap={(c) => <div>{c}</div>}>
{pickerTypes.map((p) => {
Expand Down
1 change: 0 additions & 1 deletion moon/apps/web/components/Issues/IssuePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ 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
Expand Down
60 changes: 60 additions & 0 deletions moon/apps/web/components/Issues/IssueSearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useState } from 'react'
import { useDebounce } from 'use-debounce'

import { Button, Link } from '@gitmono/ui'

import { BreadcrumbTitlebar } from '@/components/Titlebar/BreadcrumbTitlebar'
import { useScope } from '@/contexts/scope'

import Search from './Search'
import { fuseOptions, searchList } from './utils/consts'

export default function IssueSearch() {
const [query, setQuery] = useState('')
const [queryDebounced] = useDebounce(query, 150)
const [open, setOpen] = useState(false)
const handleQuery = (val: string) => {
setOpen(true)
setQuery(val)
}

// const isSearching = query.length > 0
// const isSearchLoading = queryDebounced.length > 0 && getNotes.isFetching
const isSearchLoading = queryDebounced.length > 0

return (
<>
<BreadcrumbTitlebar className='z-20 justify-between border-b-0 px-0'>
<Search
SearchQuery={{ query, setQuery: handleQuery, isSearchLoading }}
SearchListTable={{
open,
setOpen,
items: searchList
}}
SearchOptions={{
fuseOptions,
searchList
}}
/>
{/* <IndexSearchInput query={query} setQuery={setQuery} isSearchLoading={isSearchLoading} /> */}
<Button variant='primary' size={'base'}>
Labels
</Button>
<NewIssueButton />
</BreadcrumbTitlebar>
</>
)
}

export const NewIssueButton = () => {
const { scope } = useScope()

return (
<Link href={`/${scope}/issue/new`}>
<Button variant='primary' className='bg-[#1f883d]' size={'base'}>
New Issue
</Button>
</Link>
)
}
32 changes: 25 additions & 7 deletions moon/apps/web/components/Issues/IssuesContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import { useSyncedMembers } from '@/hooks/useSyncedMembers'
import { apiErrorToast } from '@/utils/apiErrorToast'
import { atomWithWebStorage } from '@/utils/atomWithWebStorage'

import { IndexPageInstantLoading } from '../IndexPages/components'
import { MemberAvatar } from '../MemberAvatar'
import { IssueIndexTabFilter } from './IssueIndex'
import { MemberHovercard } from './MemberHoverCardNE'
import { Pagination } from './Pagenation'
import { orderTags, tags } from './utils/consts'
import { generateAllMenuItems, MenuConfig } from './utils/generateAllMenuItems'
Expand Down Expand Up @@ -62,7 +64,7 @@ export function IssuesContent({ searching }: Props) {

const [pageSize, _setPageSize] = useState(10)

const [status, _setStatus] = useAtom(filterAtom(scope))
const [status, _setStatus] = useAtom(filterAtom({ scope, part: 'issue' }))

const [issueList, setIssueList] = useState<Item[]>([])

Expand Down Expand Up @@ -161,7 +163,6 @@ export function IssuesContent({ searching }: Props) {

onSelectFactory: (_item: string) => (e: Event) => {
e.preventDefault()

},
className: 'overflow-hidden',
labelFactory: (item: string) => <div>{item}</div>
Expand Down Expand Up @@ -273,9 +274,9 @@ export function IssuesContent({ searching }: Props) {
fetchData(1, pageSize)
}, [pageSize, fetchData])

if (loading) {
return <IndexPageInstantLoading />
}
// if (loading) {
// return <IndexPageInstantLoading />
// }

// if (!issueList.length) {
// return searching ? <EmptySearchResults /> : <IssueIndexEmptyState />
Expand All @@ -295,10 +296,14 @@ export function IssuesContent({ searching }: Props) {
) : (
<>
<IssueList
isLoading={loading}
Issuelists={issueList}
header={
<ListBanner
pickerTypes={['Author', 'Labels', 'Projects', 'Milestones', 'Assignees', 'Types', `${order}`]}
tabfilter={
<IssueIndexTabFilter openTooltip='Issues that are still open and need attention' part='issue' />
}
>
{(p) => ListHeaderItem(p)}
</ListBanner>
Expand All @@ -311,7 +316,7 @@ export function IssuesContent({ searching }: Props) {
key={i.link}
title={i.title}
leftIcon={<CheckCircleFilledFlushIcon color='#378f50' size={16} />}
rightIcon={<ChatBubbleIcon />}
rightIcon={<RightAvatar member={members[0]} />}
>
<div className='text-xs text-[#59636e]'>
{i.link} · {i.user_id} {i.status}{' '}
Expand All @@ -337,3 +342,16 @@ function IssueSearchList(_props: { searchIssueList?: Item[]; hideProject?: boole
</>
)
}

export const RightAvatar = ({ member }: { member: Member }) => {
return (
<>
<div className='mr-10 flex items-center justify-between gap-10'>
<ChatBubbleIcon />
<MemberHovercard username={member.user.display_name} side='top' align='end' member={member}>
<MemberAvatar size='sm' member={member} />
</MemberHovercard>
</div>
</>
)
}
Loading