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
13 changes: 7 additions & 6 deletions moon/apps/web/components/CodeView/CodeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import 'github-markdown-css/github-markdown-light.css'

import { useMemo } from 'react'
import { DocumentIcon, FolderIcon } from '@heroicons/react/20/solid'
import { FolderIcon } from '@heroicons/react/20/solid'
import { formatDistance, fromUnixTime } from 'date-fns'
import { usePathname, useRouter } from 'next/navigation'
import RTable from './Table'
import { columnsType, DirectoryType } from './Table/type'
import Markdown from 'react-markdown'
import FileIcon from './FileIcon/FileIcon'

export interface DataType {
oid: string
Expand All @@ -18,7 +19,7 @@ export interface DataType {
date: number
}

const CodeTable = ({ directory, loading, readmeContent}: any) => {
const CodeTable = ({ directory, loading, readmeContent, onCommitInfoChange}: any) => {
const router = useRouter()
const pathname = usePathname()
let real_path = pathname?.replace('/tree', '')
Expand All @@ -41,8 +42,9 @@ const CodeTable = ({ directory, loading, readmeContent}: any) => {
<>
<div className='flex items-center'>
{record.content_type === 'directory' && <FolderIcon className='size-4 text-gray-600' />}
{record.content_type === 'file' && <DocumentIcon className='size-4 text-gray-600' />}
{record.content_type === 'file' && <FileIcon filename={record.name} style={{width:'16px', height:'16px'}}/>}
<a className='cursor-pointer transition-colors duration-300 hover:text-[#69b1ff] pl-2'>{record.name}</a>

</div>
</>
)
Expand All @@ -52,9 +54,6 @@ const CodeTable = ({ directory, loading, readmeContent}: any) => {
dataIndex: ['commit_message'],
key: 'commit_message',
render: (_, {commit_message}) => (

// console.log(message, 'message')

<a className='cursor-pointer transition-colors duration-300 text-gray-600 hover:text-[#69b1ff]'>{commit_message}</a>
)
},
Expand Down Expand Up @@ -97,6 +96,8 @@ const CodeTable = ({ directory, loading, readmeContent}: any) => {
pathParts?.push(encodeURIComponent(record.name))

newPath = `/${pathParts?.join('/')}`

onCommitInfoChange?.(newPath);
router.push(newPath)
}
}
Expand Down
11 changes: 11 additions & 0 deletions moon/apps/web/components/CodeView/FileIcon/FileIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { getIcon } from 'material-file-icons';

function FileIcon({ filename, style, className }:any) {
return <div
style={style}
className={className}
dangerouslySetInnerHTML={{ __html: getIcon(filename).svg }}
/>;
}

export default FileIcon;
100 changes: 56 additions & 44 deletions moon/apps/web/components/CodeView/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Spinner, Table } from '@radix-ui/themes'

import { Table } from '@radix-ui/themes'
import { columnsType, DirectoryType } from './type'
import { Skeleton } from '@mui/material';
import { useMemo } from 'react';

const table = <T extends DirectoryType>({
const TableComponent = <T extends DirectoryType>({
columns,
datasource,
size,
Expand All @@ -19,48 +20,59 @@ const table = <T extends DirectoryType>({
onClick?: (record: T) => void
loading?: boolean
}) => {
// 使用useMemo缓存列配置,只有当columns数组变化时才重新计算
const memoizedColumns = useMemo(() => columns,[columns]);

return (
<>
<Spinner loading={loading}>
<Table.Root size={size}>
<Table.Header>
<Table.Row align={align}>
{columns.map((c) => (
<Table.ColumnHeaderCell key={c.title}>{c.title}</Table.ColumnHeaderCell>
<Table.Root size={size}>
<Table.Header>
<Table.Row align={align}>
{memoizedColumns.map((c) => (
<Table.ColumnHeaderCell key={c.title}>{c.title}</Table.ColumnHeaderCell>
))}
</Table.Row>
</Table.Header>

<Table.Body>
{loading ? (
// 骨架屏行
Array.from({ length: 5 }).map((_, rowIndex) => {
const uniqueKey = `skeleton-row-${rowIndex}`; // 生成唯一 key

return (
<Table.Row key={uniqueKey}>
{memoizedColumns.map((column) => (
<Table.Cell key={column.key}>
<Skeleton variant="rounded" height={16} width="100%" />
</Table.Cell>
))}
</Table.Row>
);
})
) : datasource.length > 0 && (
// 实际数据行
datasource.map((d, index) => {
const uniqueKey = `row-${index}`;

return <Table.Row className='hover:bg-gray-100' key={uniqueKey}>
{memoizedColumns.map((c) => (
<Table.Cell
onClick={(e) => {
e.stopPropagation();
onClick?.(d);
}}
justify={justify}
key={c.key || c.title}
>
{c.render ? c.render(c.dataIndex[0], d, index) : null}
</Table.Cell>
))}
</Table.Row>
</Table.Header>

<Table.Body>
{datasource.map((d, index) => {
if (d) {
return (
// eslint-disable-next-line react/no-array-index-key
<Table.Row className='hover:bg-gray-100' key={index}>
{columns.map((c, index) => (
<Table.Cell
onClick={(e) => {
e.stopPropagation()
onClick?.(d)
}}
justify={justify}
// eslint-disable-next-line react/no-array-index-key
key={c.key + index}
>
{c.render ? c.render(c.dataIndex[0], d, index) : null}
</Table.Cell>
))}
</Table.Row>
)
} else {
return null
}
})}
</Table.Body>
</Table.Root>
</Spinner>
</>
)
}
})
)}
</Table.Body>
</Table.Root>
);
};

export default table
export default TableComponent;
98 changes: 69 additions & 29 deletions moon/apps/web/components/CodeView/TreeView/CloneTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import React, { useEffect, useState } from 'react'
import { Button, Input, Popover, Space, Tabs, TabsProps } from 'antd'
import { Button, cn, Popover, PopoverContent, PopoverPortal, PopoverTrigger } from '@gitmono/ui'
import copy from 'copy-to-clipboard'
import { usePathname } from 'next/navigation'
import { CheckIcon, CopyIcon, DownloadIcon } from '@gitmono/ui/Icons'
import {LEGACY_API_URL} from '@gitmono/config'
import { Box, Flex, Tabs } from '@radix-ui/themes'

const CloneTabs = ({ endpoint }: any) => {
const pathname = usePathname()
const [text, setText] = useState<string>(pathname || '')
const [copied, setCopied] = useState<boolean>(false)
const [active_tab, setActiveTab] = useState<string>('1')

const onChange = (key: string) => {
setActiveTab(key)
}
const [active_tab, setActiveTab] = useState<string>('HTTP')
const [open, setOpen] = useState(false)
const url = new URL(LEGACY_API_URL)

useEffect(() => {
if (LEGACY_API_URL) {
Expand All @@ -33,37 +32,78 @@ const CloneTabs = ({ endpoint }: any) => {
setTimeout(() => setCopied(false), 2000) // Reset after 2 seconds
}

const tab_items: TabsProps['items'] = [
const tabContent = [
{
key: '1',
label: 'HTTP',
children: (
<Space style={{ width: '100%' }}>
<Input value={text} />
<Button onClick={handleCopy} icon={copied ? <CheckIcon /> : <CopyIcon />} size={'small'} />
</Space>
)
value:'HTTP',
inputValue:`${url.href}${pathname?.replace('/myorganization/code/tree/', '')}.git`,
info:'Clone using the web URL.'
},
{
key: '2',
label: 'SSH',
children: (
<Space style={{ width: '100%' }}>
<Input value={text} />
<Button onClick={handleCopy} icon={copied ? <CheckIcon /> : <CopyIcon />} size={'small'} />
</Space>
)
value:'SSH',
inputValue:`ssh://git@${url.host}${pathname?.replace('/myorganization/code/tree', '')}.git`,
info:'Use a password-protected SSH key.'
}
]

return (
<Popover
placement='bottomRight'
content={<Tabs defaultActiveKey='1' items={tab_items} onChange={onChange} />}
trigger='click'
>
<Button icon={<DownloadIcon />}>Code</Button>
<>
<Popover open={open} onOpenChange={setOpen} modal>
<PopoverTrigger asChild>
<Button
variant="base"
>
<Flex gap="3">
<DownloadIcon />
Code
</Flex>
</Button>
</PopoverTrigger>
<PopoverPortal>
{open && (
<PopoverContent
className={cn(
'animate-scale-fade shadow-popover dark:border-primary-opaque bg-primary relative flex h-[130px] w-[400px] flex-1 origin-[--radix-hover-card-content-transform-origin] flex-col overflow-hidden rounded-lg border border-transparent dark:shadow-[0px_2px_16px_rgba(0,0,0,1)]'
)}
sideOffset={4}
align='start'
onOpenAutoFocus={(e) => e.preventDefault()}
asChild
addDismissibleLayer
>
<Tabs.Root defaultValue="HTTP" onValueChange={setActiveTab}>
<Tabs.List size="1" className='p-2'>
<Tabs.Trigger value="HTTP">
<Button variant={active_tab === 'HTTP' ? 'flat' : 'plain'}>HTTP</Button>
</Tabs.Trigger>
<Tabs.Trigger value="SSH" style={{marginLeft:'10px'}}>
<Button variant={active_tab === 'SSH' ? 'flat' : 'plain'}>SSH</Button>
</Tabs.Trigger>
</Tabs.List>
<Box pt="3">
{
tabContent?.map((_item)=>{
return (
<Tabs.Content value={_item.value} key={_item.value}>
<Flex direction='column'>
<Flex align='center'>
<input value={_item.inputValue} className='w-[350px] p-1 m-2 bg-gray-150 border-b border-r' style={{ borderRadius: '5px' }}/>
<Button onClick={handleCopy} size='sm' variant="text" className='text-gray-600'>{copied ? <CheckIcon /> : <CopyIcon />}</Button>
</Flex>
<div className='text-gray-500 ml-2'>{_item.info}</div>
</Flex>
</Tabs.Content>
)
})
}
</Box>

</Tabs.Root>
</PopoverContent>
)}
</PopoverPortal>
</Popover>

</>
)
}

Expand Down
Loading