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
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


# add CRATES_PRO_HOST, CRATES_PRO_INTERNAL_HOST to your enviroment for development
CRATES_PRO_HOST=$CRATES_PRO_HOST
CRATES_PRO_INTERNAL_HOST=$CRATES_PRO_INTERNAL_HOST
CRATES_PRO_HOST=http://210.28.134.203:6888
CRATES_PRO_INTERNAL_HOST=http://210.28.134.203:6888

SECRET_KEY=$YOUR_SECRET_KEY #(not prefixed with NEXT_PUBLIC_ )
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ const CratePage = () => {
if (error) return <div className="text-red-500">Error: {error}</div>;

return (
<div className="container mx-auto p-4">
<div className="w-full h-full p-6">



<DependencyGraph crateName={params.name as string} currentVersion={params.version as string} />
Expand Down
58 changes: 58 additions & 0 deletions app/[nsfront]/[nsbehind]/[name]/[version]/versions/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//Dependents页面
"use client";
import React, { useEffect, useState } from 'react';

import VersionsTable from '@/components/VersionsTable';
import { cratesInfo } from '@/app/lib/all_interface';
import { useParams } from 'next/navigation';



const CratePage = () => {
const [results, setResults] = useState<cratesInfo | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

const params = useParams();



useEffect(() => {
const fetchCrateData = async () => {
try {
const response = await fetch(`/api/crates/${params.nsfront}/${params.nsbehind}/${params.name}/${params.version}`);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();


setResults(data); // 设置获取的数据

} catch (error) {
setError(null);
console.log('Error fetching data:', error);
} finally {
setLoading(false); // 完成加载
}
};
fetchCrateData(); // 调用函数来获取数据
}, [params.name, params.version, params.nsfront, params.nsbehind]); // 依赖项数组,确保在 crateName 或 version 改变时重新获取数据

if (loading) return <div>Loading...</div>;
if (error) return <div className="text-red-500">Error: {error}</div>;



return (
<div>

<VersionsTable data={results?.versions} />

</div>
);
};

export default CratePage;
1 change: 0 additions & 1 deletion app/api/search/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { NextResponse } from 'next/server';

export async function POST(request: Request) {
const endpoint = process.env.CRATES_PRO_INTERNAL_HOST;

const apiUrl = `${endpoint}/api/search`;
const requestBody = await request.json();
console.log("Request Body:", requestBody);
Expand Down
29 changes: 24 additions & 5 deletions components/DependencyGraph.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useEffect, useRef, useState } from 'react';
import * as d3 from 'd3';
// import { useParams } from 'next/navigation';

export interface GraphDependency {
crate_name: string;
Expand All @@ -26,7 +25,6 @@ export interface DependencyGraphProps {
const DependencyGraph: React.FC<DependencyGraphProps> = ({ crateName, currentVersion }) => {
const [graphDependencies, setGraphDependencies] = useState<GraphDependency | null>(null);
const d3Container = useRef<HTMLDivElement | null>(null);
// const params = useParams();

useEffect(() => {
async function fetchDependencyTree(name: string, version: string, visited: Set<string>): Promise<GraphDependency> {
Expand Down Expand Up @@ -112,10 +110,11 @@ const DependencyGraph: React.FC<DependencyGraphProps> = ({ crateName, currentVer

const nodes = Array.from(nodesMap.values());

// Remove the forceCenter to allow free movement of nodes
const simulation = d3.forceSimulation<DependencyNode>(nodes)
.force('link', d3.forceLink<DependencyNode, DependencyLink>(links).id(d => d.id).distance(100))
.force('charge', d3.forceManyBody().strength(-500))
.force('center', d3.forceCenter(width / 2, height / 2))
// Remove center force to prevent auto centering
.force('collide', d3.forceCollide().radius(50));

const link = svg.append('g')
Expand Down Expand Up @@ -191,11 +190,31 @@ const DependencyGraph: React.FC<DependencyGraphProps> = ({ crateName, currentVer
d.fy = null;
}

// Zoom functionality
// const zoom = d3.zoom()
// .scaleExtent([0.1, 10]) // Minimum and maximum zoom scales
// .on('zoom', (event) => {
// svg.selectAll('g')
// .attr('transform', event.transform);
// });

// svg.call(zoom as any);

// }, [graphDependencies]);
const zoom = d3.zoom<SVGSVGElement, unknown>()
.scaleExtent([0.1, 10]) // Minimum and maximum zoom scales
.on('zoom', (event) => {
svg.selectAll('g')
.attr('transform', event.transform);
});

svg.call(zoom); // 不再使用 any

}, [graphDependencies]);

return (
<div className="bg-white p-4 mb-2 shadow-lg rounded-lg">
<div ref={d3Container} style={{ width: '100%', height: '400px' }} />
<div className="bg-white p-4 mb-2 shadow-lg rounded-lg h-screen w-full">
<div ref={d3Container} style={{ width: '100%', height: '100%' }} />
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions components/HeaderWithSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const Header = () => {
{ name: 'Overview', path: '' },
{ name: 'Dependencies', path: '/dependencies' },
{ name: 'Dependents', path: '/dependents' },
{ name: 'Versions', path: '/versions' },
];


Expand Down
108 changes: 108 additions & 0 deletions components/VersionsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use client';
import React, { useEffect, useState, useCallback } from 'react';
import { Table } from 'antd';
import { useParams } from 'next/navigation';

// 假设后端接口返回的类型
interface VersionInfo {
version: string;
publishDay: string;
dependentsNumber: number;
}

interface VersionsTableProps {
data: string[] | undefined; // 传入的版本号数组
}

const VersionsTable: React.FC<VersionsTableProps> = ({ data }) => {
const [versionsData, setVersionsData] = useState<VersionInfo[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const params = useParams();

// 获取版本发布日的函数
const fetchPublishDay = useCallback(async (version: string) => {
try {
const response = await fetch(`/api/publish-day/${version}`);
if (!response.ok) {
throw new Error('Failed to fetch publish day');
}
const data = await response.json();
return data.publishDay || 'N/A'; // 如果没有返回值,则默认返回 'N/A'
} catch (error) {
console.error('Error fetching publish day:', error);
return 'N/A'; // 请求失败时返回默认值
}
}, []);

// 获取版本依赖数的函数
const fetchDependentsNumber = useCallback(async (version: string) => {
try {
const response = await fetch(`/api/crates/${params.nsfront}/${params.nsbehind}/${params.name}/${version}/dependents`);
if (!response.ok) {
throw new Error('Failed to fetch dependents number');
}
const data = await response.json();
return data.direct_count + data.indirect_count || 0; // 如果没有返回值,则默认返回 0
} catch (error) {
console.error('Error fetching dependents number:', error);
return 0; // 请求失败时返回默认值
}
}, [params.nsfront, params.nsbehind, params.name]);

// 请求版本的发布日和依赖数
const fetchVersionDetails = useCallback(async (version: string) => {
const publishDay = await fetchPublishDay(version);
const dependentsNumber = await fetchDependentsNumber(version);
return { version, publishDay, dependentsNumber };
}, [fetchPublishDay, fetchDependentsNumber]);

useEffect(() => {
const fetchData = async () => {
if (data && data.length > 0) {
setLoading(true);
const versionDetails = await Promise.all(
data.map(async (version) => {
return await fetchVersionDetails(version);
})
);
setVersionsData(versionDetails);
setLoading(false);
}
};

fetchData();
}, [data, fetchVersionDetails]);

const columns = [
{
title: 'Version',
dataIndex: 'version',
key: 'version',
render: (text: string) => <span>{text}</span>,
},
{
title: 'Publish Day',
dataIndex: 'publishDay',
key: 'publishDay',
render: (text: string) => <span>{text}</span>,
},
{
title: 'Dependents Number',
dataIndex: 'dependentsNumber',
key: 'dependentsNumber',
render: (text: number) => <span>{text}</span>,
},
];

return (
<Table
columns={columns}
dataSource={versionsData}
pagination={false}
rowKey="version" // 使用版本字符串作为唯一键
loading={loading} // 显示加载状态
/>
);
};

export default VersionsTable;
Loading