From 0e694e296bbeac64b7c026d9819af3bb3fadfca1 Mon Sep 17 00:00:00 2001 From: "benjamin.747" Date: Thu, 15 Aug 2024 16:12:01 +0800 Subject: [PATCH] add repo publish api and tree, blob page --- gateway/src/api/ztm_router.rs | 6 +- gemini/src/http/handler.rs | 2 +- jupiter/src/storage/git_db_storage.rs | 6 - lunar/package.json | 8 +- lunar/src/app/api/fetcher.ts | 52 +++++- lunar/src/app/api/relay/repo_fork/route.ts | 2 +- lunar/src/app/application-layout.tsx | 1 - lunar/src/app/blob/page.tsx | 22 +++ lunar/src/app/page.tsx | 65 +++++--- lunar/src/app/tree/page.tsx | 54 ++++++ lunar/src/components/BreadCrumb.module.css | 5 + lunar/src/components/BreadCrumb.tsx | 32 ++++ lunar/src/components/CodeContent.module.css | 41 +++++ lunar/src/components/CodeContent.tsx | 72 ++++++++ lunar/src/components/CodeTable.module.css | 18 ++ lunar/src/components/CodeTable.tsx | 175 ++++++++++++++++++++ lunar/src/components/MergeList.tsx | 67 ++++++++ lunar/src/components/RepoTree.module.css | 4 + lunar/src/components/RepoTree.tsx | 126 ++++++++++++++ moon/package.json | 4 +- moon/src/app/application-layout.tsx | 2 +- 21 files changed, 719 insertions(+), 45 deletions(-) create mode 100644 lunar/src/app/blob/page.tsx create mode 100644 lunar/src/app/tree/page.tsx create mode 100644 lunar/src/components/BreadCrumb.module.css create mode 100644 lunar/src/components/BreadCrumb.tsx create mode 100644 lunar/src/components/CodeContent.module.css create mode 100644 lunar/src/components/CodeContent.tsx create mode 100644 lunar/src/components/CodeTable.module.css create mode 100644 lunar/src/components/CodeTable.tsx create mode 100644 lunar/src/components/MergeList.tsx create mode 100644 lunar/src/components/RepoTree.module.css create mode 100644 lunar/src/components/RepoTree.tsx diff --git a/gateway/src/api/ztm_router.rs b/gateway/src/api/ztm_router.rs index 3b4b9822..50a09b9b 100644 --- a/gateway/src/api/ztm_router.rs +++ b/gateway/src/api/ztm_router.rs @@ -14,7 +14,7 @@ use crate::api::MegaApiServiceState; pub fn routers() -> Router { Router::new() .route("/ztm/repo_provide", get(repo_provide)) - .route("/ztm/repo_folk", get(repo_folk)) + .route("/ztm/repo_fork", get(repo_fork)) } async fn repo_provide( @@ -50,7 +50,7 @@ async fn repo_provide( Ok(Json(res)) } -async fn repo_folk( +async fn repo_fork( Query(query): Query>, state: State, ) -> Result>, (StatusCode, String)> { @@ -76,7 +76,7 @@ async fn repo_folk( } }; - let res = gemini::http::handler::repo_folk( + let res = gemini::http::handler::repo_fork( state.ztm.ztm_agent_port, identifier.to_string(), local_port, diff --git a/gemini/src/http/handler.rs b/gemini/src/http/handler.rs index cd60bceb..f71b3be8 100644 --- a/gemini/src/http/handler.rs +++ b/gemini/src/http/handler.rs @@ -55,7 +55,7 @@ pub async fn repo_provide( Ok("success".to_string()) } -pub async fn repo_folk( +pub async fn repo_fork( ztm_agent_port: u16, identifier: String, local_port: u16, diff --git a/jupiter/src/storage/git_db_storage.rs b/jupiter/src/storage/git_db_storage.rs index 2a81c6ca..ef79a2bd 100644 --- a/jupiter/src/storage/git_db_storage.rs +++ b/jupiter/src/storage/git_db_storage.rs @@ -122,12 +122,6 @@ impl GitDbStorage { .one(self.get_connection()) .await?; Ok(result) - // if let Some(model) = result { - // let refs: Refs = model.into(); - // Ok(Some(refs)) - // } else { - // Ok(None) - // } } pub async fn default_branch_exist(&self, repo_id: i64) -> Result { diff --git a/lunar/package.json b/lunar/package.json index 478b5ef9..c23b1ebb 100644 --- a/lunar/package.json +++ b/lunar/package.json @@ -23,7 +23,11 @@ "next": "14.2.3", "react": "^18", "react-dom": "^18", - "swr": "^2.2.5" + "swr": "^2.2.5", + "github-markdown-css": "^5.6.1", + "react-markdown": "^9.0.1", + "prism-react-renderer": "^2.3.1" + }, "devDependencies": { "@tauri-apps/cli": "^1.6.0", @@ -35,4 +39,4 @@ "postcss": "^8.4.40", "typescript": "^5.5.4" } -} +} \ No newline at end of file diff --git a/lunar/src/app/api/fetcher.ts b/lunar/src/app/api/fetcher.ts index 6f79b469..843a884e 100644 --- a/lunar/src/app/api/fetcher.ts +++ b/lunar/src/app/api/fetcher.ts @@ -1,4 +1,5 @@ -import useSWR from "swr"; +import useSWR, { Fetcher } from "swr"; +import { invoke } from '@tauri-apps/api/tauri'; const endpoint = process.env.NEXT_PUBLIC_API_URL; const relay = process.env.NEXT_PUBLIC_RELAY_API_URL; @@ -26,8 +27,8 @@ const fetcher = async url => { export function useTreeCommitInfo(path) { - const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/tree/commit-info?path=${path}`, fetcher, { - dedupingInterval: 60000, + const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/tree/commit-info?path=${path}`, fetcher, { + dedupingInterval: 1000, }) return { tree: data, @@ -37,7 +38,7 @@ export function useTreeCommitInfo(path) { } export function useBlobContent(path) { - const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/blob?path=${path}`, fetcher, { + const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/blob?path=${path}`, fetcher, { dedupingInterval: 60000, }) return { @@ -57,3 +58,46 @@ export function useRepoList() { isError: error, } } + +// export function usePublishRepo(path: string) { +// const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mega/ztm/repo_provide?path=${path}`, fetcher) +// return { +// data: data, +// isLoading, +// isError: error, +// } +// } + +export const tauriFetcher: Fetcher = ([key, args]) => { + return invoke(key, args); +}; + +export function useMegaStatus() { + const { data, error, isLoading } = useSWR( + ['mega_service_status', {}], + tauriFetcher + ); + + return { + status: data, + isLoading, + isError: error, + }; +} + +// normal fetch +export async function requestPublishRepo(path) { + const response = await fetch(`${endpoint}/api/v1/mega/ztm/repo_provide?path=${path}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error('Failed to publish repo'); + } + + // 返回响应数据 + return response.json(); +} \ No newline at end of file diff --git a/lunar/src/app/api/relay/repo_fork/route.ts b/lunar/src/app/api/relay/repo_fork/route.ts index 4c23058b..81929983 100644 --- a/lunar/src/app/api/relay/repo_fork/route.ts +++ b/lunar/src/app/api/relay/repo_fork/route.ts @@ -8,7 +8,7 @@ export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams const identifier = searchParams.get('identifier') const port = searchParams.get('port') - const res = await fetch(`${endpoint}/api/v1/ztm/repo_folk?identifier=${identifier}&port=${port}`, { + const res = await fetch(`${endpoint}/api/v1/mega/ztm/repo_fork?identifier=${identifier}&port=${port}`, { }) const data = await res.json() diff --git a/lunar/src/app/application-layout.tsx b/lunar/src/app/application-layout.tsx index c86265c1..525719f9 100644 --- a/lunar/src/app/application-layout.tsx +++ b/lunar/src/app/application-layout.tsx @@ -37,7 +37,6 @@ import { HomeIcon, QuestionMarkCircleIcon, SparklesIcon, - Square2StackIcon, TicketIcon, ChatBubbleLeftRightIcon, CodeBracketSquareIcon, diff --git a/lunar/src/app/blob/page.tsx b/lunar/src/app/blob/page.tsx new file mode 100644 index 00000000..d84432f5 --- /dev/null +++ b/lunar/src/app/blob/page.tsx @@ -0,0 +1,22 @@ +'use client' +import CodeContent from '@/components/CodeContent'; +import Bread from '@/components/BreadCrumb'; +import { useSearchParams } from 'next/navigation'; +import { useBlobContent } from '../api/fetcher'; +import { Skeleton } from "antd/lib"; + + +export default function BlobPage() { + const searchParams = useSearchParams(); + const path = searchParams.get('path'); + + const { blob, isBlobLoading, isBlobError } = useBlobContent(`${path}`); + if (isBlobLoading) return ; + + return ( +
+ + +
+ ) +} diff --git a/lunar/src/app/page.tsx b/lunar/src/app/page.tsx index d3e4f674..0a1dc10b 100644 --- a/lunar/src/app/page.tsx +++ b/lunar/src/app/page.tsx @@ -1,10 +1,10 @@ 'use client' import { Flex, Layout } from 'antd'; -import { Skeleton } from "antd"; -import CodeTable from '../../../moon/src/components/CodeTable'; -import MergeList from '../../../moon/src/components/MergeList'; -import { useTreeCommitInfo, useBlobContent } from '@/app/api/fetcher'; +import { Skeleton, Button, Result } from "antd/lib"; +import CodeTable from '@/components/CodeTable'; +import MergeList from '@/components/MergeList'; +import { useTreeCommitInfo, useBlobContent, useMegaStatus } from '@/app/api/fetcher'; const { Content } = Layout; @@ -22,6 +22,7 @@ const layoutStyle = { overflow: 'hidden', width: 'calc(50% - 8px)', maxWidth: 'calc(50% - 8px)', + background: '#fff' }; const mrList = [ @@ -51,27 +52,43 @@ const mrList = [ export default function HomePage() { const { tree, isTreeLoading, isTreeError } = useTreeCommitInfo("/"); const { blob, isBlobLoading, isBlobError } = useBlobContent("/README.md"); + const { status, isLoading, isError } = useMegaStatus(); + + if (isTreeLoading || isBlobLoading || isLoading) return ; return ( - - - {(isTreeLoading || isBlobLoading) && - - } - { - (tree && blob) && - - } - - - {(isTreeLoading || isBlobLoading) && - - } - {(!isTreeLoading && !isBlobLoading) && - - } - {/* */} - - +
+ {!status && + < Result + status="warning" + title="Set relay server address first to start mega server" + extra={ + + } + /> + } + { + status && + + + { + (tree && blob) && + + } + + + {(isTreeLoading || isBlobLoading) && + + } + {(!isTreeLoading && !isBlobLoading) && + + } + {/* */} + + + } +
) } diff --git a/lunar/src/app/tree/page.tsx b/lunar/src/app/tree/page.tsx new file mode 100644 index 00000000..b3d02a9e --- /dev/null +++ b/lunar/src/app/tree/page.tsx @@ -0,0 +1,54 @@ +'use client' + +import CodeTable from '@/components/CodeTable' +import Bread from '@/components/BreadCrumb' +import RepoTree from '@/components/RepoTree' +import { useBlobContent, useTreeCommitInfo } from '@/app/api/fetcher' +import { useSearchParams } from 'next/navigation'; +import { Skeleton, Flex, Layout } from "antd/lib"; + + +export default function Page() { + const searchParams = useSearchParams(); + const path = searchParams.get('path'); + const { tree, isTreeLoading, isTreeError } = useTreeCommitInfo(path); + const { blob, isBlobLoading, isBlobError } = useBlobContent(`${path}/README.md`); + if (isTreeLoading || isBlobLoading) return ; + + const treeStyle = { + borderRadius: 8, + overflow: 'hidden', + width: 'calc(20% - 8px)', + maxWidth: 'calc(20% - 8px)', + background: '#fff', + }; + + const codeStyle = { + borderRadius: 8, + overflow: 'hidden', + width: 'calc(80% - 8px)', + background: '#fff', + }; + + const breadStyle = { + minHeight: 30, + borderRadius: 8, + overflow: 'hidden', + width: 'calc(100% - 8px)', + background: '#fff', + }; + + return ( + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/lunar/src/components/BreadCrumb.module.css b/lunar/src/components/BreadCrumb.module.css new file mode 100644 index 00000000..bf9772c6 --- /dev/null +++ b/lunar/src/components/BreadCrumb.module.css @@ -0,0 +1,5 @@ +.breadCrumb { + width: 80%; + margin-left: 18%; + margin-top: 20px; +} \ No newline at end of file diff --git a/lunar/src/components/BreadCrumb.tsx b/lunar/src/components/BreadCrumb.tsx new file mode 100644 index 00000000..db52e3c4 --- /dev/null +++ b/lunar/src/components/BreadCrumb.tsx @@ -0,0 +1,32 @@ +import 'github-markdown-css/github-markdown-light.css' +import { useRouter } from 'next/navigation' +import { Breadcrumb } from 'antd/lib' +import styles from './BreadCrumb.module.css' + +const Bread = ({ path }) => { + const router = useRouter(); + let path_arr = path.split('/').filter(Boolean); + + const breadCrumbItems = path_arr.map((path, index) => { + if (index == path_arr.length - 1) { + return { + title: path, + }; + } else { + const href = '/tree?path=/' + path_arr.slice(0, index + 1).join('/'); + return { + title: path, + href: href, + }; + } + + }); + + return ( + + ); +}; + +export default Bread; diff --git a/lunar/src/components/CodeContent.module.css b/lunar/src/components/CodeContent.module.css new file mode 100644 index 00000000..7762baab --- /dev/null +++ b/lunar/src/components/CodeContent.module.css @@ -0,0 +1,41 @@ +.codeShowContainer { + border-radius: 1rem; + padding-top: 70px; +} + +.codeLineNumber { + margin-left: 15px; + margin-right: 25px; +} + +.viewChangeTab { + background-color: rgba(53, 53, 53, 0.103); + display: flex; + position: absolute; + width: 80%; + height: 50px; + border-top-left-radius: 1rem; + border-top-right-radius: 1rem; +} + +.viewChangeTabButton { + padding-left: 20px; + padding-right: 20px; + height: 100%; + border-radius: 1rem; + border: none; + background-color: transparent; +} + +.viewChangeTabButton:hover, +.viewChangeTabButton:checked { + background-color: rgba(0, 0, 0, 0.121); +} + +.fileCodeContainer { + width: 80%; + margin-left: 18%; + border-radius: 0.5rem; + margin-top: 10px; + +} \ No newline at end of file diff --git a/lunar/src/components/CodeContent.tsx b/lunar/src/components/CodeContent.tsx new file mode 100644 index 00000000..48d2a6e1 --- /dev/null +++ b/lunar/src/components/CodeContent.tsx @@ -0,0 +1,72 @@ +// import Editor from './editor/Editor' +import 'github-markdown-css/github-markdown-light.css' +import { Highlight, themes } from "prism-react-renderer" +import { useState } from 'react' +import { createRoot } from 'react-dom/client' +import styles from './CodeContent.module.css' + +const CodeContent = ({ fileContent }) => { + + const [showEditor, setShowEditor] = useState(false); + + const handleLineNumberClick = (lineIndex) => { + setShowEditor(!showEditor); + const lineNumberButton = document.getElementsByClassName('codeLineNumber')[lineIndex]; + const codeLineNumber = lineNumberButton.closest('.token-line'); + if (showEditor) { + const editorContainer = document.createElement('div'); + editorContainer.className = 'editor-container'; + + // render the Editor into the container + const root = createRoot(editorContainer); + // root.render() + if (codeLineNumber && codeLineNumber.parentNode) { + codeLineNumber.parentNode.insertBefore(editorContainer, codeLineNumber.nextSibling); + + } + } else { + const editorContainer = document.querySelector('.editor-container'); + if (editorContainer && editorContainer.parentNode) { + editorContainer.parentNode.removeChild(editorContainer); + } + } + + }; + + + return ( +
+
+ + +
+ + + {({ className, style, tokens, getLineProps, getTokenProps }) => ( +
+                        {tokens.map((line, i) => (
+                            
+ + {i + 1} + {line.map((token, key) => ( + + ))} +
+ ))} +
+ )} +
+
+ ) + +} + +export default CodeContent; diff --git a/lunar/src/components/CodeTable.module.css b/lunar/src/components/CodeTable.module.css new file mode 100644 index 00000000..b8813f91 --- /dev/null +++ b/lunar/src/components/CodeTable.module.css @@ -0,0 +1,18 @@ +.readmeContainer { + margin-top: 2rem; + margin-left: 1rem; +} + +.markdownContent { + margin: 0 auto; + margin-top: 5%; + border: 1px solid rgba(0, 0, 0, 0.112); + padding: 2%; + border-radius: 0.5rem; + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + +} diff --git a/lunar/src/components/CodeTable.tsx b/lunar/src/components/CodeTable.tsx new file mode 100644 index 00000000..3b162edb --- /dev/null +++ b/lunar/src/components/CodeTable.tsx @@ -0,0 +1,175 @@ +'use client' + +import 'github-markdown-css/github-markdown-light.css' +import { useRouter, useSearchParams } from 'next/navigation' +import Markdown from 'react-markdown' +import { formatDistance, fromUnixTime } from 'date-fns' +import styles from './CodeTable.module.css' +import { Input, Modal, Space, Table, TableProps } from 'antd/lib' +import { useState } from 'react' +import { + FolderIcon, + DocumentIcon, +} from '@heroicons/react/20/solid' +import { requestPublishRepo } from '@/app/api/fetcher' + + +export interface DataType { + oid: string; + name: string; + content_type: string; + message: string; + date: number; +} + +const CodeTable = ({ directory, readmeContent }) => { + const router = useRouter(); + const fileCodeContainerStyle = { + width: '100%', + margin: '0 auto', + borderRadius: '0.5rem', + marginTop: '10px' + }; + const [open, setOpen] = useState(false); + const [confirmLoading, setConfirmLoading] = useState(false); + const [modalText, setModalText] = useState(''); + const searchParams = useSearchParams(); + const path = searchParams.get('path'); + + var columns: TableProps['columns'] = [ + { + title: 'Name', + dataIndex: ['name', 'content_type'], + key: 'name', + render: (_, record) => { + return <> + {record.content_type === "file" && + + + handleFileClick(record)}>{record.name} + + } + {record.content_type === "directory" && + + + handleDirectoryClick(record)}>{record.name} + } + + } + }, + { + title: 'Message', + dataIndex: 'message', + key: 'message', + render: (text) => {text}, + }, + { + title: 'Date', + dataIndex: 'date', + key: 'date', + render: (_, { date }) => ( + <> + {date && formatDistance(fromUnixTime(date), new Date(), { addSuffix: true })} + + ) + }, + { + title: 'Action', + key: 'action', + render: (_, record) => ( + + showModal(record.name)}>Publish + Revoke + + ), + }, + ]; + + const handleFileClick = (file) => { + router.push(`/blob?path=${path}/${file.name}`); + }; + + const handleDirectoryClick = async (directory) => { + var newPath = ''; + if (!path) { + newPath = `/tree?path=/${directory.name}`; + } else { + newPath = `/tree?path=${path}/${directory.name}`; + } + router.push( + newPath + ); + }; + + // const handleGoBack = () => { + // const safePath = real_path.split('/'); + // if (safePath.length == 1) { + // router.push('/') + // } else { + // router.push(`/tree/${safePath.slice(0, -1).join('/')}`); + // } + // }; + + // sort by file type, render folder type first + const sortedDir = directory.sort((a, b) => { + if (a.content_type === 'directory' && b.content_type === 'file') { + return -1; + } else if (a.content_type === 'file' && b.content_type === 'directory') { + return 1; + } else { + return 0; + } + }); + + const showModal = (name) => { + setModalText(name); + setOpen(true); + }; + + const handleOk = async (filename) => { + + var newPath = ''; + if (!path) { + newPath = `/${filename}`; + } else { + newPath = `${path}/${filename}`; + } + setConfirmLoading(true); + // await requestPublishRepo(path) + setTimeout(() => { + console.log("publish path", newPath); + setOpen(false); + setConfirmLoading(false); + }, 2000); + }; + + const handleCancel = () => { + setOpen(false); + }; + + return ( +
+ + handleOk(modalText)} + confirmLoading={confirmLoading} + onCancel={handleCancel} + > + + + {readmeContent && ( +
+
+ {readmeContent} +
+
+ )} + + ); +}; + + + +export default CodeTable; diff --git a/lunar/src/components/MergeList.tsx b/lunar/src/components/MergeList.tsx new file mode 100644 index 00000000..4c16d1ba --- /dev/null +++ b/lunar/src/components/MergeList.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { Avatar, List, Tag } from 'antd/lib'; +import { format, formatDistance, fromUnixTime } from 'date-fns' +import { MergeOutlined } from '@ant-design/icons'; +import Link from 'next/link'; + +interface MrInfoItem { + id: number, + title: string, + status: string, + open_timestamp: number, + merge_timestamp: number | null, +} + +interface MergeListProps { + mrList: MrInfoItem[]; +} + +const MergeList: React.FC = ({ mrList }) => { + + const getStatusTag = (status: string) => { + switch (status) { + case 'open': + return open; + case 'merged': + return merged; + case 'closed': + return closed; + } + }; + + const getDescription = (item: MrInfoItem) => { + switch (item.status) { + case 'open': + return `MergeRequest opened on ${format(fromUnixTime(Number(item.open_timestamp)), 'MMM d')} by Admin`; + case 'merged': + if (item.merge_timestamp !== null) { + return `MergeRequest by Admin was merged ${formatDistance(fromUnixTime(item.merge_timestamp), new Date(), { addSuffix: true })}`; + } else { + return ""; + } + case 'closed': + return closed; + } + } + + return ( + ( + + + } + title={{`MR ${item.id} open by Mega automacticlly${item.title}`}{getStatusTag(item.status)}} + description={getDescription(item)} + /> + + )} + /> + ); +}; + +export default MergeList; \ No newline at end of file diff --git a/lunar/src/components/RepoTree.module.css b/lunar/src/components/RepoTree.module.css new file mode 100644 index 00000000..04808d88 --- /dev/null +++ b/lunar/src/components/RepoTree.module.css @@ -0,0 +1,4 @@ +.dirTreeContainer { + margin-top: 20px; + float: left; +} \ No newline at end of file diff --git a/lunar/src/components/RepoTree.tsx b/lunar/src/components/RepoTree.tsx new file mode 100644 index 00000000..d95d5d70 --- /dev/null +++ b/lunar/src/components/RepoTree.tsx @@ -0,0 +1,126 @@ +import 'github-markdown-css/github-markdown-light.css' +import { DownOutlined } from '@ant-design/icons/lib' +import { useState, useEffect } from 'react' +import { useRouter } from 'next/navigation' +import { Tree } from 'antd/lib' +import styles from './RepoTree.module.css' + +const RepoTree = ({ directory }) => { + const router = useRouter(); + const [treeData, setTreeData] = useState(); + const [updateTree, setUpdateTree] = useState(false); + const [expandedKeys, setExpandedKeys] = useState([]); + + useEffect(() => { + setTreeData(convertToTreeData(directory)); + }, [directory]); + + + useEffect(() => { + if (updateTree) { + setUpdateTree(false); + } + }, [updateTree]); + + + + // convert the dir to tree data + const convertToTreeData = (responseData) => { + return sortProjectsByType(responseData).map(item => { + const treeItem = { + title: item.name, + key: item.id, + isLeaf: item.content_type !== 'directory', + path: item.path, + expanded: false, // initialize expanded state to false + children: [] // eneure every node having the children element + }; + return treeItem; + }); + }; + + // sortProjectsByType function to sort projects by file type + const sortProjectsByType = (projects) => { + return projects.sort((a, b) => { + if (a.content_type === 'directory' && b.content_type === 'file') { + return -1; // directory comes before file + } else if (a.content_type === 'file' && b.content_type === 'directory') { + return 1; // file comes after directory + } else { + return 0; // maintain original order + } + }); + }; + + // append the clicked dir to the treeData + const appendTreeData = (treeData, subItems, clickedNodeKey) => { + return treeData.map(item => { + if (item.key === clickedNodeKey) { + return { + ...item, + children: subItems + }; + } else if (Array.isArray(item.children)) { + return { + ...item, + children: appendTreeData(item.children, subItems, clickedNodeKey) + }; + } + }); + }; + + const onExpand = async (keys, { expanded, node }) => { + // push new url and query to router + console.log("OnExpanded!"); + console.log("keys", keys); + console.log("node", node.path); + // router.push({ query: { repo_path: "/projects/freighter", object_id: node.key } }); + var responseData; + try { + const response = await fetch(`/api/tree?path=${node.path}`); + + if (!response.ok) { + throw new Error('Failed to fetch tree data'); + } + + console.log('Response status:', response.status); + + responseData = await response.json(); + console.log('Response data:', responseData); + + } catch (error) { + console.error('Error fetching tree data:', error); + } + // onRenderTree(node.key); + if (expanded) { + const subTreeData = convertToTreeData(responseData.items); + const newTreeData = appendTreeData(treeData, subTreeData, node.key); + // setExpandedKeys([...expandedKeys, node.key]); + setTreeData(newTreeData); + // setCurrentPath([...currentPath, node.title]); // for breadcrumb + } else { + setExpandedKeys(expandedKeys.filter(key => key !== node.key)); + } + }; + + const onSelect = (keys, info) => { + router.push(`/?object_id=${keys}`); + console.log('Trigger Select', keys, info); + }; + + return ( +
+ } + expandedKeys={expandedKeys} + /> +
+ ); +}; + +export default RepoTree; diff --git a/moon/package.json b/moon/package.json index 4cfc819a..1b72f102 100644 --- a/moon/package.json +++ b/moon/package.json @@ -14,14 +14,14 @@ "@headlessui/react": "^2.1.2", "@headlessui/tailwindcss": "^0.2.1", "@heroicons/react": "^2.1.5", - "@lexical/react": "^0.16.1", + "@lexical/react": "^0.17.0", "@tailwindcss/forms": "^0.5.7", "clsx": "^2.1.1", "date-fns": "^3.6.0", "framer-motion": "^11.3.19", "github-markdown-css": "^5.6.1", "highlight.js": "^11.10.0", - "lexical": "^0.16.1", + "lexical": "^0.17.0", "next": "^14.2.5", "prism-react-renderer": "^2.3.1", "react": "^18.3.1", diff --git a/moon/src/app/application-layout.tsx b/moon/src/app/application-layout.tsx index 5d209d16..1d06c6bb 100644 --- a/moon/src/app/application-layout.tsx +++ b/moon/src/app/application-layout.tsx @@ -113,7 +113,7 @@ export function ApplicationLayout({ { - !user && + !token && } {