From 161e5b598567c53d7caec9fcbccd65df867ac17c Mon Sep 17 00:00:00 2001 From: "benjamin.747" Date: Thu, 26 Jun 2025 20:28:21 +0800 Subject: [PATCH] fix(UI): refactor tree api to return all parent tree --- ceres/src/api_service/mod.rs | 25 ++++++------ ceres/src/model/git.rs | 14 +++++++ mono/src/api/api_router.rs | 67 ++++++++++++++++++++++++-------- mono/src/api/mod.rs | 4 +- moon/packages/types/generated.ts | 22 ++++++++--- 5 files changed, 96 insertions(+), 36 deletions(-) diff --git a/ceres/src/api_service/mod.rs b/ceres/src/api_service/mod.rs index 54c234211..c2a8d7283 100644 --- a/ceres/src/api_service/mod.rs +++ b/ceres/src/api_service/mod.rs @@ -104,21 +104,22 @@ pub trait ApiHandler: Send + Sync { Ok(commit.into()) } - async fn get_tree_info(&self, path: PathBuf) -> Result, GitError> { - match self.search_tree_by_path(&path).await? { + async fn get_tree_info(&self, path: &Path) -> Result, GitError> { + match self.search_tree_by_path(path).await? { Some(tree) => { - let mut items = Vec::new(); - for item in tree.tree_items { - let mut info: TreeBriefItem = item.clone().into(); - path.join(item.name) - .to_str() - .unwrap() - .clone_into(&mut info.path); - items.push(info); - } + let items = tree + .tree_items + .into_iter() + .map(|item| { + let full_path = path.join(&item.name); + let mut info: TreeBriefItem = item.into(); + info.path = full_path.to_str().unwrap().to_owned(); + info + }) + .collect(); Ok(items) } - None => Ok(Vec::new()), + None => Ok(vec![]), } } diff --git a/ceres/src/model/git.rs b/ceres/src/model/git.rs index b8680ffc7..643280938 100644 --- a/ceres/src/model/git.rs +++ b/ceres/src/model/git.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use serde::{Deserialize, Serialize}; use utoipa::{IntoParams, ToSchema}; @@ -164,3 +166,15 @@ impl From for TreeBriefItem { fn default_path() -> String { "/".to_string() } + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct TreeResponse { + pub file_tree: HashMap, + pub tree_items: Vec, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct FileTreeItem { + pub tree_items: Vec, + pub total_count: usize, +} diff --git a/mono/src/api/api_router.rs b/mono/src/api/api_router.rs index 7ae2d292e..bdb80a94b 100644 --- a/mono/src/api/api_router.rs +++ b/mono/src/api/api_router.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use axum::{ body::Body, @@ -12,8 +12,8 @@ use http::StatusCode; use ceres::{ api_service::ApiHandler, model::git::{ - BlobContentQuery, CodePreviewQuery, CreateFileInfo, LatestCommitInfo, TreeBriefItem, - TreeCommitItem, TreeHashItem, TreeQuery, + BlobContentQuery, CodePreviewQuery, CreateFileInfo, FileTreeItem, LatestCommitInfo, + TreeCommitItem, TreeHashItem, TreeQuery, TreeResponse, }, }; use common::model::CommonResult; @@ -60,7 +60,7 @@ async fn get_blob_string( state: State, ) -> Result>, ApiError> { let data = state - .api_handler(query.path.clone().into()) + .api_handler(query.path.as_ref()) .await? .get_blob_as_string(query.path.into()) .await?; @@ -95,7 +95,7 @@ async fn create_file( Json(json): Json, ) -> Result>, ApiError> { state - .api_handler(json.path.clone().into()) + .api_handler(json.path.as_ref()) .await? .create_monorepo_file(json.clone()) .await?; @@ -119,7 +119,7 @@ async fn get_latest_commit( state: State, ) -> Result, ApiError> { let res = state - .api_handler(query.path.clone().into()) + .api_handler(query.path.as_ref()) .await? .get_latest_commit(query.path.into()) .await?; @@ -134,20 +134,55 @@ async fn get_latest_commit( CodePreviewQuery ), responses( - (status = 200, body = CommonResult>, content_type = "application/json") + (status = 200, body = CommonResult, content_type = "application/json") ), tag = GIT_TAG )] async fn get_tree_info( Query(query): Query, state: State, -) -> Result>>, ApiError> { - let data = state - .api_handler(query.path.clone().into()) +) -> Result>, ApiError> { + let mut parts = Vec::new(); + let mut current = String::new(); + let mut segments = query.path.split('/').peekable(); + + while let Some(segment) = segments.next() { + if segment.is_empty() { + current = "/".to_string(); + parts.push(current.clone()); + } else if segments.peek().is_some() { + if current != "/" { + current.push('/'); + } + current.push_str(segment); + parts.push(current.clone()); + } + } + + let mut file_tree = HashMap::new(); + + for part in parts { + let path = part.as_ref(); + let handler = state.api_handler(path).await?; + let tree_items = handler.get_tree_info(path).await?; + file_tree.insert( + part, + FileTreeItem { + total_count: tree_items.len(), + tree_items, + }, + ); + } + + let tree_items = state + .api_handler(query.path.as_ref()) .await? - .get_tree_info(query.path.into()) + .get_tree_info(query.path.as_ref()) .await?; - Ok(Json(CommonResult::success(Some(data)))) + Ok(Json(CommonResult::success(Some(TreeResponse { + file_tree, + tree_items, + })))) } /// List matching trees with commit msg by query @@ -167,7 +202,7 @@ async fn get_tree_commit_info( state: State, ) -> Result>>, ApiError> { let data = state - .api_handler(query.path.clone().into()) + .api_handler(query.path.as_ref()) .await? .get_tree_commit_info(query.path.into()) .await?; @@ -191,7 +226,7 @@ async fn get_tree_content_hash( state: State, ) -> Result>>, ApiError> { let data = state - .api_handler(query.path.clone().into()) + .api_handler(query.path.as_ref()) .await? .get_tree_content_hash(query.path.into()) .await?; @@ -223,7 +258,7 @@ async fn get_tree_dir_hash( let target_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); let data = state - .api_handler(parent_path.clone().into()) + .api_handler(parent_path.as_ref()) .await? .get_tree_dir_hash(parent_path.into(), target_name) .await?; @@ -259,7 +294,7 @@ pub async fn get_tree_file( Query(query): Query, ) -> Result { let data = state - .api_handler(query.path.clone().into()) + .api_handler(query.path.as_ref()) .await? .get_binary_tree_by_path(std::path::Path::new(&query.path), query.oid) .await?; diff --git a/mono/src/api/mod.rs b/mono/src/api/mod.rs index 67e329fed..9ecbd6149 100644 --- a/mono/src/api/mod.rs +++ b/mono/src/api/mod.rs @@ -7,7 +7,7 @@ use oauth2::{ }, Client, EndpointNotSet, EndpointSet, StandardRevocableToken, }; -use std::path::PathBuf; +use std::path::Path; use ceres::{ api_service::{ @@ -102,7 +102,7 @@ impl MonoApiServiceState { self.storage.user_storage() } - async fn api_handler(&self, path: PathBuf) -> Result, ProtocolError> { + async fn api_handler(&self, path: &Path) -> Result, ProtocolError> { let import_dir = self.storage.config().monorepo.import_dir.clone(); if path.starts_with(&import_dir) && path != import_dir { if let Some(model) = self diff --git a/moon/packages/types/generated.ts b/moon/packages/types/generated.ts index 31214be42..0f16fdfc7 100644 --- a/moon/packages/types/generated.ts +++ b/moon/packages/types/generated.ts @@ -3133,12 +3133,11 @@ export type CommonResultString = { req_result: boolean } -export type CommonResultVecTreeBriefItem = { +export type CommonResultTreeResponse = { data?: { - content_type: string - name: string - path: string - }[] + file_tree: Record + tree_items: TreeBriefItem[] + } err_message: string req_result: boolean } @@ -3195,6 +3194,12 @@ export type CreateFileInfo = { path: string } +export type FileTreeItem = { + /** @min 0 */ + total_count: number + tree_items: TreeBriefItem[] +} + export type FilesChangedList = { content: string mui_trees: MuiTreeNode[] @@ -3363,6 +3368,11 @@ export type TreeHashItem = { oid: string } +export type TreeResponse = { + file_tree: Record + tree_items: TreeBriefItem[] +} + export type UserInfo = { avatar_url: string display_name: string @@ -4561,7 +4571,7 @@ export type GetApiTreeParams = { path?: string } -export type GetApiTreeData = CommonResultVecTreeBriefItem +export type GetApiTreeData = CommonResultTreeResponse export type GetApiTreeCommitInfoParams = { refs?: string