diff --git a/ceres/src/api_service/import_api_service.rs b/ceres/src/api_service/import_api_service.rs index 9f9b132dd..2af2b7783 100644 --- a/ceres/src/api_service/import_api_service.rs +++ b/ceres/src/api_service/import_api_service.rs @@ -150,7 +150,7 @@ impl ApiHandler for ImportApiService { &self, path: &Path, start_commit: Commit, - target: TreeItem, + target: &TreeItem, ) -> Commit { let mut target_commit = start_commit.clone(); let mut visited = HashSet::new(); @@ -162,7 +162,7 @@ impl ApiHandler for ImportApiService { while let Some(commit) = p_stack.pop_front() { let root_tree = self.get_tree_by_hash(&commit.tree_id.to_plain_str()).await; let reachable = self - .reachable_in_tree(&root_tree, path, target.clone()) + .reachable_in_tree(&root_tree, path, target) .await .unwrap(); if reachable { diff --git a/ceres/src/api_service/mod.rs b/ceres/src/api_service/mod.rs index 4f8e454eb..206fe7d12 100644 --- a/ceres/src/api_service/mod.rs +++ b/ceres/src/api_service/mod.rs @@ -76,7 +76,7 @@ pub trait ApiHandler: Send + Sync { &self, path: &Path, commit: Commit, - target: TreeItem, + target: &TreeItem, ) -> Commit; async fn get_blob_as_string(&self, file_path: PathBuf) -> Result { @@ -166,9 +166,9 @@ pub trait ApiHandler: Send + Sync { let commit = if let Some(commit) = commit_map.get(commit_id) { commit } else { - tracing::error!("failed fecth commit: {}", commit_id); + tracing::warn!("failed fecth commit: {}", commit_id); &self - .traverse_commit_history(&path, self.get_root_commit().await, item) + .traverse_commit_history(&path, self.get_root_commit().await, &item) .await }; info.oid = commit.id.to_plain_str(); @@ -177,6 +177,12 @@ pub trait ApiHandler: Send + Sync { } items.push(info); } + // sort with type and date + items.sort_by(|a, b| { + a.content_type + .cmp(&b.content_type) + .then(b.date.cmp(&a.date)) + }); Ok(items) } None => Ok(Vec::new()), @@ -385,7 +391,7 @@ pub trait ApiHandler: Send + Sync { &self, root_tree: &Tree, path: &Path, - target: TreeItem, + target: &TreeItem, ) -> Result { let relative_path = self.strip_relative(path).unwrap(); let mut search_tree = root_tree.clone(); @@ -406,7 +412,7 @@ pub trait ApiHandler: Send + Sync { } } // check item exist under search tree - if search_tree.tree_items.into_iter().any(|x| x == target) { + if search_tree.tree_items.iter().any(|x| x == target) { return Ok(true); } Ok(false) diff --git a/ceres/src/api_service/mono_api_service.rs b/ceres/src/api_service/mono_api_service.rs index 237b953d1..889c9db1b 100644 --- a/ceres/src/api_service/mono_api_service.rs +++ b/ceres/src/api_service/mono_api_service.rs @@ -190,7 +190,7 @@ impl ApiHandler for MonoApiService { Ok(commits.into_iter().map(|x| x.into()).collect()) } - async fn traverse_commit_history(&self, _: &Path, _: Commit, _: TreeItem) -> Commit { + async fn traverse_commit_history(&self, _: &Path, _: Commit, _: &TreeItem) -> Commit { unreachable!() } } diff --git a/ceres/src/model/mr.rs b/ceres/src/model/mr.rs index 3fa4e597b..c02228fa8 100644 --- a/ceres/src/model/mr.rs +++ b/ceres/src/model/mr.rs @@ -9,6 +9,7 @@ pub struct MrInfoItem { pub status: String, pub open_timestamp: i64, pub merge_timestamp: Option, + pub updated_at: i64, } impl From for MrInfoItem { @@ -19,6 +20,7 @@ impl From for MrInfoItem { status: value.status.to_string(), open_timestamp: value.created_at.and_utc().timestamp(), merge_timestamp: value.merge_date.map(|dt| dt.and_utc().timestamp()), + updated_at: value.updated_at.and_utc().timestamp(), } } } diff --git a/ceres/src/pack/import_repo.rs b/ceres/src/pack/import_repo.rs index eba8f3bac..38eae2ce0 100644 --- a/ceres/src/pack/import_repo.rs +++ b/ceres/src/pack/import_repo.rs @@ -15,10 +15,7 @@ use tokio_stream::wrappers::ReceiverStream; use callisto::{mega_tree, raw_blob}; use common::errors::MegaError; -use jupiter::{ - context::Context, - storage::batch_save_model, -}; +use jupiter::{context::Context, storage::batch_save_model}; use mercury::{ errors::GitError, internal::{ @@ -30,12 +27,17 @@ use mercury::{hash::SHA1, internal::pack::encode::PackEncoder}; use crate::{ api_service::{mono_api_service::MonoApiService, ApiHandler}, - pack::PackHandler, protocol::{import_refs::{CommandType, RefCommand, Refs}, repo::Repo}, + pack::PackHandler, + protocol::{ + import_refs::{CommandType, RefCommand, Refs}, + repo::Repo, + }, }; pub struct ImportRepo { pub context: Context, pub repo: Repo, + pub command_list: Vec, } #[async_trait] @@ -54,7 +56,6 @@ impl PackHandler for ImportRepo { } async fn handle_receiver(&self, receiver: Receiver) -> Result<(), GitError> { - self.create_monorepo_parent().await.unwrap(); let storage = self.context.services.git_db_storage.clone(); let mut entry_list = vec![]; let mut join_tasks = vec![]; @@ -64,14 +65,21 @@ impl PackHandler for ImportRepo { let stg_clone = storage.clone(); let repo_clone = self.repo.clone(); let handle = tokio::spawn(async move { - stg_clone.save_entry(repo_clone.repo_id, entry_list).await.unwrap(); + stg_clone + .save_entry(repo_clone.repo_id, entry_list) + .await + .unwrap(); }); join_tasks.push(handle); entry_list = vec![]; } } join_all(join_tasks).await; - storage.save_entry(self.repo.repo_id, entry_list).await.unwrap(); + storage + .save_entry(self.repo.repo_id, entry_list) + .await + .unwrap(); + self.attach_to_monorepo_parent().await.unwrap(); Ok(()) } @@ -130,7 +138,8 @@ impl PackHandler for ImportRepo { let sender_clone = entry_tx.clone(); let chunk_clone = chunk.to_vec(); let handler = tokio::spawn(async move { - let mut blob_stream = raw_storage.get_raw_blobs_stream(chunk_clone).await.unwrap(); + let mut blob_stream = + raw_storage.get_raw_blobs_stream(chunk_clone).await.unwrap(); while let Some(model) = blob_stream.next().await { match model { Ok(m) => { @@ -289,9 +298,15 @@ impl PackHandler for ImportRepo { let storage = self.context.services.git_db_storage.clone(); match refs.command_type { CommandType::Create => { - storage.save_ref(self.repo.repo_id, refs.clone().into()).await.unwrap(); + storage + .save_ref(self.repo.repo_id, refs.clone().into()) + .await + .unwrap(); } - CommandType::Delete => storage.remove_ref(self.repo.repo_id, &refs.ref_name).await.unwrap(), + CommandType::Delete => storage + .remove_ref(self.repo.repo_id, &refs.ref_name) + .await + .unwrap(), CommandType::Update => { storage .update_ref(self.repo.repo_id, &refs.ref_name, &refs.new_id) @@ -314,13 +329,16 @@ impl PackHandler for ImportRepo { async fn check_default_branch(&self) -> bool { let storage = self.context.services.git_db_storage.clone(); - storage.default_branch_exist(self.repo.repo_id).await.unwrap() + storage + .default_branch_exist(self.repo.repo_id) + .await + .unwrap() } } impl ImportRepo { - // create monorepo parent for preserve import repo - async fn create_monorepo_parent(&self) -> Result<(), GitError> { + // attach import repo to monorepo parent tree + async fn attach_to_monorepo_parent(&self) -> Result<(), GitError> { let path = PathBuf::from(self.repo.repo_path.clone()); let mono_api_service = MonoApiService { context: self.context.clone(), @@ -329,13 +347,21 @@ impl ImportRepo { let save_trees = mono_api_service.search_and_create_tree(&path).await?; let mut root_ref = storage.get_ref("/").await.unwrap().unwrap(); + let commit_id = &self.command_list.first().unwrap().new_id; + let latest_commit: Commit = self + .context + .services + .git_db_storage + .get_commit_by_hash(self.repo.repo_id, commit_id) + .await + .unwrap() + .unwrap() + .into(); + let commit_msg = latest_commit.format_message(); let new_commit = Commit::from_tree_id( save_trees.back().unwrap().id, vec![SHA1::from_str(&root_ref.ref_commit_hash).unwrap()], - &format!( - "push thrid-part crates {:?} commit", - path.file_name().unwrap() - ), + &commit_msg, ); let save_trees: Vec = save_trees diff --git a/ceres/src/protocol/mod.rs b/ceres/src/protocol/mod.rs index 4200b6d23..9299d6bac 100644 --- a/ceres/src/protocol/mod.rs +++ b/ceres/src/protocol/mod.rs @@ -172,6 +172,7 @@ impl SmartProtocol { Ok(Arc::new(ImportRepo { context: self.context.clone(), repo, + command_list: self.command_list.clone(), })) } else { let mut res = MonoRepo { diff --git a/mono/src/api/oauth/model.rs b/mono/src/api/oauth/model.rs index b0d7384bf..b2011d3d5 100644 --- a/mono/src/api/oauth/model.rs +++ b/mono/src/api/oauth/model.rs @@ -22,7 +22,8 @@ pub struct GitHubUserJson { pub login: String, pub id: u32, pub avatar_url: String, - pub email: String, + // email can be null from github + pub email: Option, } impl From for user::Model { @@ -30,7 +31,7 @@ impl From for user::Model { Self { id: generate_id(), name: value.login, - email: value.email, + email: value.email.unwrap_or_default(), avatar_url: value.avatar_url, is_github: true, created_at: chrono::Utc::now().naive_utc(), diff --git a/moon/src/app/(dashboard)/application-layout.tsx b/moon/src/app/(dashboard)/application-layout.tsx index 8d903a0c7..fc98b0b3e 100644 --- a/moon/src/app/(dashboard)/application-layout.tsx +++ b/moon/src/app/(dashboard)/application-layout.tsx @@ -124,28 +124,7 @@ export function ApplicationLayout({ Mega - - - - - Settings - - - - - Admin - - - - Big Events - - - - - New team… - - @@ -163,19 +142,15 @@ export function ApplicationLayout({ Merge Request - - - Settings - - + Support - + Changelog @@ -187,7 +162,7 @@ export function ApplicationLayout({ - + {user.name} diff --git a/moon/src/app/(dashboard)/changelog/page.tsx b/moon/src/app/(dashboard)/changelog/page.tsx new file mode 100644 index 000000000..0cd3f9982 --- /dev/null +++ b/moon/src/app/(dashboard)/changelog/page.tsx @@ -0,0 +1,8 @@ +export default function ChangeLogPage() { + + return ( +
+ ChangeLog Page +
+ ) +} \ No newline at end of file diff --git a/moon/src/app/(dashboard)/issue/page.tsx b/moon/src/app/(dashboard)/issue/page.tsx new file mode 100644 index 000000000..2a97c2f9f --- /dev/null +++ b/moon/src/app/(dashboard)/issue/page.tsx @@ -0,0 +1,8 @@ +export default function IssuePage() { + + return ( +
+ Issue Page +
+ ) +} \ No newline at end of file diff --git a/moon/src/app/(dashboard)/support/page.tsx b/moon/src/app/(dashboard)/support/page.tsx new file mode 100644 index 000000000..d448014a8 --- /dev/null +++ b/moon/src/app/(dashboard)/support/page.tsx @@ -0,0 +1,8 @@ +export default function SupportPage() { + + return ( +
+ Support Page +
+ ) +} \ No newline at end of file diff --git a/moon/src/app/(dashboard)/user/keys/page.tsx b/moon/src/app/(dashboard)/user/keys/page.tsx index 283267616..de55c4365 100644 --- a/moon/src/app/(dashboard)/user/keys/page.tsx +++ b/moon/src/app/(dashboard)/user/keys/page.tsx @@ -43,8 +43,8 @@ export default function KeysPage() { console.error('Error fetching data:', error); } }; - useEffect(() => { + useEffect(() => { fetchData(); }, []); diff --git a/moon/src/components/CodeTable.tsx b/moon/src/components/CodeTable.tsx index ab871b1f9..266ebeb80 100644 --- a/moon/src/components/CodeTable.tsx +++ b/moon/src/components/CodeTable.tsx @@ -36,17 +36,11 @@ const CodeTable = ({ directory, readmeContent }) => { key: 'name', render: (_, record) => { return <> - {record.content_type === "file" && - - - handleFileClick(record)}>{record.name} - - } - {record.content_type === "directory" && - - - handleDirectoryClick(record)}>{record.name} - } + + {record.content_type === "directory" && } + {record.content_type === "file" && } + {record.name} + } }, @@ -67,23 +61,22 @@ const CodeTable = ({ directory, readmeContent }) => { ) } ]; - - const handleFileClick = (file) => { - const newPath = `/blob/${real_path}/${file.name}`; - router.push(newPath); - }; - - const handleDirectoryClick = async (directory) => { - var newPath = ''; - if (real_path === '/') { - newPath = `/tree/${directory.name}`; + const handleRowClick = (record) => { + if (record.content_type === "file") { + const newPath = `/blob/${real_path}/${record.name}`; + router.push(newPath); } else { - newPath = `/tree/${real_path}/${directory.name}`; + var newPath = ''; + if (real_path === '/') { + newPath = `/tree/${record.name}`; + } else { + newPath = `/tree/${real_path}/${record.name}`; + } + router.push( + newPath, + ); } - router.push( - newPath, - ); - }; + } const handleGoBack = () => { const safePath = real_path.split('/'); @@ -95,21 +88,17 @@ const CodeTable = ({ directory, readmeContent }) => { } }; - // 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; - } - }); - - return (
- +
{ + return { + onClick: (event) => { handleRowClick(record) } + }; + }} + /> {readmeContent && (
diff --git a/moon/src/components/MergeList.tsx b/moon/src/components/MergeList.tsx index 84fec655f..863bc816e 100644 --- a/moon/src/components/MergeList.tsx +++ b/moon/src/components/MergeList.tsx @@ -10,6 +10,7 @@ interface MrInfoItem { status: string, open_timestamp: number, merge_timestamp: number | null, + updated_at: number, } interface MergeListProps { @@ -25,7 +26,7 @@ const MergeList: React.FC = ({ mrList }) => { case 'merged': return merged; case 'closed': - return closed; + return closed; } }; @@ -40,7 +41,7 @@ const MergeList: React.FC = ({ mrList }) => { return ""; } case 'closed': - return closed; + return (`MR ${item.mr_link} by Admin was closed ${formatDistance(fromUnixTime(item.updated_at), new Date(), { addSuffix: true })}` ) } } diff --git a/moon/src/components/catalyst/sidebar-layout.tsx b/moon/src/components/catalyst/sidebar-layout.tsx index 4b7677e64..d326e0506 100644 --- a/moon/src/components/catalyst/sidebar-layout.tsx +++ b/moon/src/components/catalyst/sidebar-layout.tsx @@ -74,7 +74,7 @@ export function SidebarLayout({ {/* Content */}
-
{children}
+
{children}