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
183 changes: 89 additions & 94 deletions moon/apps/web/components/CodeView/CodeTable.tsx
Original file line number Diff line number Diff line change
@@ -1,115 +1,110 @@
'use client'

import 'github-markdown-css/github-markdown-light.css'

import { useMemo } from 'react'
import { DocumentIcon, FolderIcon } from '@heroicons/react/20/solid'
import { formatDistance, fromUnixTime } from 'date-fns'
import { usePathname, useRouter } from 'next/navigation'
import Markdown from 'react-markdown'
import { formatDistance, fromUnixTime } from 'date-fns'

import styles from './CodeTable.module.css'
import { Space, Table, TableProps } from 'antd/lib'
import {
FolderIcon,
DocumentIcon,
} from '@heroicons/react/20/solid'
import { useMemo } from 'react';
import RTable from './Table'
import { columnsType, DirectoryType } from './Table/type'

export interface DataType {
oid: string;
name: string;
content_type: string;
message: string;
date: number;
oid: string
name: string
content_type: string
message: string
date: number
}

const CodeTable = ({ directory, readmeContent}:any) => {
const router = useRouter();
const pathname = usePathname();
let real_path = pathname?.replace("/tree", "");

const columns = useMemo<TableProps<DataType>['columns']>(() => [
{
title: 'Name',
dataIndex: ['name', 'content_type'],
key: 'name',
render: (_, record) => (
<Space>
{record.content_type === "directory" && <FolderIcon className="size-6" />}
{record.content_type === "file" && <DocumentIcon className="size-6" />}
<a>{record.name}</a>
</Space>
)
},
{
title: 'Message',
dataIndex: 'message',
key: 'message',
render: (text) => <a>{text}</a>,
},
{
title: 'Date',
dataIndex: 'date',
key: 'date',
render: (_, { date }) => (
<>
{date && formatDistance(fromUnixTime(date), new Date(), { addSuffix: true })}
</>
)
}
], []);

const handleRowClick = (record: DataType) => {
const normalizedPath = real_path?.replace(/^\/|\/$/g, '');
const pathParts = normalizedPath?.split('/') || [];

if (record.content_type === "file") {
let newPath: string;

const hasBlob = pathParts?.includes('blob');
const CodeTable = ({ directory, readmeContent }: any) => {
const router = useRouter()
const pathname = usePathname()
let real_path = pathname?.replace('/tree', '')

const columns = useMemo<columnsType<DirectoryType>[]>(
() => [
{
title: 'Name',
dataIndex: ['name', 'content_type'],
key: 'name',
render: (_, record) => (
<>
<div className='flex'>
{record.content_type === 'directory' && <FolderIcon className='size-6' />}
{record.content_type === 'file' && <DocumentIcon className='size-6' />}
<a className='cursor-pointer transition-colors duration-300 hover:text-[#69b1ff]'>{record.name}</a>
</div>
</>
)
},
{
title: 'Message',
dataIndex: ['message'],
key: 'message',
render: (_, { message }) => (
<a className='cursor-pointer transition-colors duration-300 hover:text-[#69b1ff]'>{message}</a>
)
},
{
title: 'Date',
dataIndex: ['date'],
key: 'date',
render: (_, { date }) => (
<>{date && formatDistance(fromUnixTime(Number(date)), new Date(), { addSuffix: true })}</>
)
}
],
[]
)

const handleRowClick = (record: DirectoryType) => {
const normalizedPath = real_path?.replace(/^\/|\/$/g, '')
const pathParts = normalizedPath?.split('/') || []

if (record.content_type === 'file') {
let newPath: string

const hasBlob = pathParts?.includes('blob')

if (!hasBlob && pathParts.length >= 2) {
pathParts?.splice(2, 0, 'blob');
pathParts?.splice(2, 0, 'blob')
}
pathParts?.push(encodeURIComponent(record.name));
pathParts?.push(encodeURIComponent(record.name))

newPath = `/${pathParts?.join('/')}`;
router.push(newPath);
newPath = `/${pathParts?.join('/')}`
router.push(newPath)
} else {
let newPath: string;
const hasTree = pathParts?.includes('tree');
let newPath: string

const hasTree = pathParts?.includes('tree')

if (!hasTree && pathParts.length >= 2) {
pathParts?.splice(2, 0, 'tree');
pathParts?.splice(2, 0, 'tree')
}
pathParts?.push(encodeURIComponent(record.name));

newPath = `/${pathParts?.join('/')}`;
router.push(newPath);
}
}
pathParts?.push(encodeURIComponent(record.name))

return (
<div>
<Table style={{ clear: "none" }} rowClassName={styles.dirShowTr}
pagination={false} columns={columns}
dataSource={directory}
rowKey="name"
onRow={(record) => {
return {
onClick: () => { handleRowClick(record) }
};
}}
/>
{readmeContent && (
<div className={styles.markdownContent}>
<div className="markdown-body">
<Markdown>{readmeContent}</Markdown>
</div>
</div>
)}
</div>
);
};
newPath = `/${pathParts?.join('/')}`
router.push(newPath)
}
}

return (
<div>
<RTable columns={columns ?? []} datasource={directory} size='3' align='center' onClick={handleRowClick} />

{readmeContent && (
<div className={styles.markdownContent}>
<div className='markdown-body'>
<Markdown>{readmeContent}</Markdown>
</div>
</div>
)}
</div>
)
}

export default CodeTable;
export default CodeTable
62 changes: 62 additions & 0 deletions moon/apps/web/components/CodeView/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Table } from '@radix-ui/themes'

import { columnsType, DirectoryType } from './type'

const table = <T extends DirectoryType>({
columns,
datasource,
size,
align,
justify,
onClick
}: {
columns: columnsType<T>[]
datasource: T[]
size?: '1' | '2' | '3' | undefined
align?: 'center' | 'start' | 'end' | undefined
justify?: 'center' | 'start' | 'end' | undefined
onClick?: (record: T) => void
}) => {
return (
<>
<Table.Root size={size}>
<Table.Header>
<Table.Row align={align}>
{columns.map((c) => (
<>
<Table.ColumnHeaderCell>{c.title}</Table.ColumnHeaderCell>
</>
Comment on lines +26 to +28

Copilot AI May 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each header cell rendered in columns.map is missing a unique key prop; add key={c.key} (or similar) on <Table.ColumnHeaderCell> and remove the unnecessary fragment.

Suggested change
<>
<Table.ColumnHeaderCell>{c.title}</Table.ColumnHeaderCell>
</>
<Table.ColumnHeaderCell key={c.key}>{c.title}</Table.ColumnHeaderCell>

Copilot uses AI. Check for mistakes.
))}
</Table.Row>
</Table.Header>

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

export default table
15 changes: 15 additions & 0 deletions moon/apps/web/components/CodeView/Table/type.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type RenderFn<T> = (value: any, record: T, index?: number) => React.ReactNode
export interface columnsType<T> {
title: string
dataIndex: string[]
key: string
render: RenderFn<T>
}

export interface DirectoryType {
content_type: string
date: string
message: string
name: string
oid: string
}
48 changes: 25 additions & 23 deletions moon/apps/web/components/CodeView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
'use client'

import CodeTable from './CodeTable';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useGetTreeCommitInfo } from '@/hooks/useGetTreeCommitInfo';
import { CommonResultVecTreeCommitItem } from '@gitmono/types/generated';
import { useCallback, useEffect, useMemo, useState } from 'react'
import { CommonResultVecTreeCommitItem } from '@gitmono/types/generated'

import { useGetTreeCommitInfo } from '@/hooks/useGetTreeCommitInfo'

import CodeTable from './CodeTable'

export default function CodeView() {
const { data:TreeCommitInfo } = useGetTreeCommitInfo('/')
const { data: TreeCommitInfo } = useGetTreeCommitInfo('/')

type DirectoryType = NonNullable<CommonResultVecTreeCommitItem['data']>;
const directory:DirectoryType = useMemo(() => TreeCommitInfo?.data ?? [], [TreeCommitInfo]);
type DirectoryType = NonNullable<CommonResultVecTreeCommitItem['data']>
const directory: DirectoryType = useMemo(() => TreeCommitInfo?.data ?? [], [TreeCommitInfo])

const [readmeContent, setReadmeContent] = useState("");
const [readmeContent, setReadmeContent] = useState('')

const fetchData = useCallback(async () => {
if (directory.length === 0) return;
if (directory.length === 0) return

try {
const content = await getReadmeContent("/", directory);
const content = await getReadmeContent('/', directory)

setReadmeContent(content);
setReadmeContent(content)
} catch (error) {
// console.error('Error fetching data:', error);
}
}, [directory]);
}, [directory])

useEffect(() => {
fetchData();
}, [fetchData]);
fetchData()
}, [fetchData])

return (
<div className='p-3.5 mt-3'>
<div className='mt-3 p-3.5'>
<CodeTable directory={directory} readmeContent={readmeContent} />
</div>
);
)
}

async function getReadmeContent(pathname:string, directory: any) {
let readmeContent = '';
async function getReadmeContent(pathname: string, directory: any) {
let readmeContent = ''

for (const project of directory || []) {
if (project.name === 'README.md' && project.content_type === 'file') {
const res = await fetch(`/api/blob?path=${pathname}/README.md`);
const response = await res.json();
const res = await fetch(`/api/blob?path=${pathname}/README.md`)
const response = await res.json()

readmeContent = response.data.data;
break;
readmeContent = response.data.data
break
}
}
return readmeContent
Expand Down
1 change: 1 addition & 0 deletions moon/apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@radix-ui/react-slider": "catalog:",
"@radix-ui/react-slot": "catalog:",
"@radix-ui/react-tabs": "catalog:",
"@radix-ui/themes": "^3.2.1",
"@sentry/nextjs": "catalog:",
"@shopify/react-shortcuts": "catalog:",
"@tanstack/react-query": "catalog:",
Expand Down
8 changes: 5 additions & 3 deletions moon/apps/web/pages/[org]/code/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Theme } from '@radix-ui/themes'
import Head from 'next/head'

import CodeView from '@/components/CodeView'
import { AppLayout } from '@/components/Layout/AppLayout'
import { AuthAppProviders } from '@/components/Providers/AuthAppProviders'
import { PageWithLayout } from '@/utils/types'
import CodeView from '@/components/CodeView'

const OrganizationTestPage: PageWithLayout<any> = () => {

return (
<>
<Head>
Expand All @@ -21,7 +21,9 @@ const OrganizationTestPage: PageWithLayout<any> = () => {
OrganizationTestPage.getProviders = (page, pageProps) => {
return (
<AuthAppProviders {...pageProps}>
<AppLayout {...pageProps}>{page}</AppLayout>
<Theme>
<AppLayout {...pageProps}>{page}</AppLayout>
</Theme>
</AuthAppProviders>
)
}
Expand Down
Loading