Skip to content

Conversation

@tenwanft
Copy link
Contributor

No description provided.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tenwanft, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a major overhaul to the application's data loading and display architecture, shifting from a rigid, predefined data structure to a more dynamic and file-path-driven approach. The core changes involve enabling recursive reading of JSONL files, dynamically generating UI components based on the loaded data's schema, and providing file-path-based filtering options. These updates enhance the flexibility and adaptability of the application when handling varied JSONL datasets.

Highlights

  • Recursive JSONL File Handling: Implemented new functionality in the Electron main process and Python backend to recursively discover and read .jsonl files from specified directories, excluding summary.json. Each data item read from these files now includes a _filePath property indicating its origin.
  • Dynamic Data Display in UI: The DetailTable component has been significantly refactored to dynamically generate its columns based on the keys present in the loaded JSONL data, rather than relying on a fixed schema. This allows for greater flexibility in displaying diverse data structures.
  • File-Path Based Filtering: The FilterCascader component has been updated to allow filtering of displayed data by the relative paths of the JSONL files, replacing the previous primary/secondary dimension filtering mechanism. This provides a more direct way to navigate data sources.
  • Updated Pie Chart Component: The PieChart component now includes a Select dropdown to filter the type_ratio data, adapting to changes in the data structure and providing more control over the displayed summary statistics.
  • IPC Communication Updates: New IPC handlers (get-all-jsonl-file-paths and read-all-jsonl-files) have been added and exposed through the Electron preload script, enabling the renderer process to interact with the new file reading capabilities in the main process.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@shijinpjlab shijinpjlab changed the title Dev zeng feat: front page v2.0 Dec 19, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant refactoring to support reading and displaying data from nested .jsonl files. This includes new backend logic in Electron's main process and Python scripts to recursively scan directories, and major updates to frontend components like detail-table, filter-cascader, and pieChart to handle the dynamic data structure. The changes make the application much more flexible in handling different data layouts.

My review focuses on improving code maintainability by reducing duplication, increasing robustness by handling potential runtime errors, and cleaning up leftover development artifacts like console.log statements. I've identified a few critical issues that could lead to application crashes and some medium-severity issues related to code quality.

// 检查是否有二级数据
const hasSecondLevel = firstLevelType => {
return Object.keys(data.name_ratio).some(key =>
return Object.keys(data.type_ratio.content).some(key =>
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

This line directly accesses data.type_ratio.content, but content may not exist on type_ratio, which would cause the application to crash. Please add optional chaining or a fallback to prevent this.

Suggested change
return Object.keys(data.type_ratio.content).some(key =>
return Object.keys(data.type_ratio?.content || {}).some(key =>


//根据筛选获得扇形图的右侧展示的一级目录
const firstLevelData = useMemo(()=>{
return Object.entries(typeRatio[selected]).map(
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The useMemo hook for firstLevelData accesses typeRatio[selected]. If data.type_ratio is empty, the selected state will be initialized to '', causing typeRatio[selected] to be undefined. Calling Object.entries(undefined) will crash the application. Please add a fallback to handle this case.

Suggested change
return Object.entries(typeRatio[selected]).map(
return Object.entries(typeRatio[selected] || {}).map(

console.log(filePaths, 'jsonlFilePaths');

// 使用 id 作为唯一标识
setData(uniqBy(allData, 'id'));
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using uniqBy(allData, 'id') assumes that every data item across all .jsonl files will have a unique id property. If an item lacks an id, or if ids are not unique across different files, this could lead to unintentional data loss or incorrect filtering. A more robust approach would be to use a key that is guaranteed to be unique, or to not perform this de-duplication if the data source already guarantees uniqueness.

Comment on lines +185 to +311
async function getAllJsonlFilePathsRecursive(
dirPath: string
): Promise<string[]> {
const filePaths: string[] = [];

async function traverseDirectory(
currentPath: string,
relativePath: string = ''
): Promise<void> {
try {
const items = await fs.readdir(currentPath, {
withFileTypes: true,
});

for (const item of items) {
const fullPath = path.join(currentPath, item.name);
const newRelativePath = relativePath
? `${relativePath}/${item.name}`
: item.name;

if (item.isDirectory()) {
// 递归遍历子目录
await traverseDirectory(fullPath, newRelativePath);
} else if (
item.isFile() &&
item.name.endsWith('.jsonl') &&
item.name !== 'summary.json'
) {
// 添加 jsonl 文件路径(相对路径)
filePaths.push(newRelativePath);
}
}
} catch (error) {
console.error(`Error reading directory ${currentPath}:`, error);
}
}

await traverseDirectory(dirPath);
return filePaths.sort();
}

ipcMain.handle(
'get-all-jsonl-file-paths',
async (event, dirPath: string) => {
try {
return await getAllJsonlFilePathsRecursive(dirPath);
} catch (error) {
console.error('Error getting all JSONL file paths:', error);
throw error;
}
}
);

// 修改 readAllJsonlFilesRecursive,为每个数据项添加文件路径信息
async function readAllJsonlFilesRecursiveWithPath(
dirPath: string
): Promise<any[]> {
const allData: any[] = [];

async function traverseDirectory(
currentPath: string,
relativePath: string = ''
): Promise<void> {
try {
const items = await fs.readdir(currentPath, {
withFileTypes: true,
});

for (const item of items) {
const fullPath = path.join(currentPath, item.name);
const newRelativePath = relativePath
? `${relativePath}/${item.name}`
: item.name;

if (item.isDirectory()) {
// 递归遍历子目录
await traverseDirectory(fullPath, newRelativePath);
} else if (
item.isFile() &&
item.name.endsWith('.jsonl') &&
item.name !== 'summary.json'
) {
// 读取 jsonl 文件(排除 summary.json)
try {
const fileContent = await fs.readFile(
fullPath,
'utf-8'
);
const lines = fileContent
.trim()
.split('\n')
.filter(line => line.trim());
const parsedData = lines
.map(line => {
try {
const data = JSON.parse(line);
// 为每个数据项添加文件路径信息
return {
...data,
_filePath: newRelativePath,
};
} catch (e) {
console.error(
`Error parsing line in ${fullPath}:`,
e
);
return null;
}
})
.filter(item => item !== null);
allData.push(...parsedData);
} catch (error) {
console.error(
`Error reading file ${fullPath}:`,
error
);
}
}
}
} catch (error) {
console.error(`Error reading directory ${currentPath}:`, error);
}
}

await traverseDirectory(dirPath);
return allData;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There is significant code duplication between the getAllJsonlFilePathsRecursive and readAllJsonlFilesRecursiveWithPath functions. The directory traversal logic is identical in both. To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, I recommend abstracting the traversal logic into a shared helper function. This function could take a callback to process each found file, which would make the code cleaner and easier to manage.

showHighlight?: boolean;
}

//该组件此次迭代该组件暂时不用了
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The comment indicates this component is temporarily unused. To keep the codebase clean and maintainable, it's best to remove unused components. Version control can be used to restore it later if needed. Leaving unused code can lead to confusion and maintenance overhead.

Comment on lines 61 to 62
console.log(allData, 'allData');
console.log(filePaths, 'jsonlFilePaths');
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

These console.log statements should be removed before merging to keep the browser console clean in production.

<div className="space-y-1 max-h-[60vh] overflow-y-auto scrollbar-thin">
{firstLevelData?.map((item, index) => {
const hasChildren = hasSecondLevel(item?.name);
console.log(hasChildren, 'hasChildren')
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This console.log statement should be removed from the code.

const getSecondLevelData = firstLevelType => {
return Object.entries(data.name_ratio)
const getSecondLevelData = (firstLevelType: string) => {
console.log(firstLevelType, 'firstLevelType');
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This console.log statement should be removed from the code.

@tenwanft tenwanft closed this Dec 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants