+
Reference
+
{cve.reference.split(' ').map((url: string, i: number) => (
{url}
@@ -142,11 +137,11 @@ const CveCard = ({ cve }: { cve: CVE }) => (
)}
- {/* 描述信息 */}
+ {/* Description */}
{cve.description && (
-
-
Description
-
{cve.description}
+
+
Description
+
{cve.description}
)}
@@ -170,9 +165,8 @@ const CratePage = () => {
}
const data = await response.json();
setResults(data);
- console.log('data in overviewwwwwwwww:', data);
} catch (error) {
- console.error('Error fetching data:', error);
+ console.error('Error fetching crate data:', error);
setError('An error occurred');
} finally {
setLoading(false);
@@ -181,11 +175,10 @@ const CratePage = () => {
fetchCrateData();
}, [params.name, params.version, params.nsfront, params.nsbehind]);
- console.log('results in overviewwwwwwwww:', results);
+
if (loading) return
Loading...
;
if (error) return
Error: {error}
;
- // 计算当前页的 CVE 数据
const getCurrentPageItems = (items: CVE[], currentPage: number) => {
const start = (currentPage - 1) * itemsPerPage;
const end = start + itemsPerPage;
@@ -193,293 +186,535 @@ const CratePage = () => {
};
return (
-
-
-
-
- {/* Security Advisories 主框 */}
-
- {/* Security Advisories 标题 */}
-
-
-
Security Advisories
-
0
- ? 'rgb(179, 20, 18)'
- : 'rgb(34, 197, 94)'
- }}
- >
- {results ? (results.cves?.length || 0) + (results.dep_cves?.length || 0) : 0}
-
+
+
+
+
+ {/* 左侧内容区域 - 占据2列 */}
+
+ {/* Security Advisories 标题 */}
+
+
+
+ Security Advisories
+
-
- {/* 两个子框的容器 */}
-
- {/* In this package 框 */}
-
-
-
In this package
-
0) ? 'rgb(179, 20, 18)' : 'rgb(34, 197, 94)' }}>
- {results?.cves?.length || 0}
-
+ {/* Security Advisories 内容 */}
+
+ {/* In this package */}
+
0 ? 'h-[502px]' : 'h-[300px]'}`}>
+
+
In this package
+ 0 ? 'bg-[#FD5656]' : 'bg-[#4B68FF]'}`}>
+ {results?.cves?.length || 0}
+
+
+
+ {results?.cves && results.cves.length > 0 ? (
+
0 ? "overflow-auto h-full w-full" : ""}>
+ {getCurrentPageItems(results.cves, packageCurrentPage).map((cve, index) => (
+
+ ))}
+ {results.cves.length > itemsPerPage && (
+
+ setPackageCurrentPage(1)}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={packageCurrentPage === 1}
+ >
+ <<
+
+ setPackageCurrentPage(prev => Math.max(1, prev - 1))}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={packageCurrentPage === 1}
+ >
+ <
+
+ {Array.from({ length: Math.min(5, Math.ceil(results.cves.length / itemsPerPage)) }).map((_, i) => {
+ const pageNum = packageCurrentPage - Math.floor(Math.min(5, Math.ceil(results.cves.length / itemsPerPage)) / 2) + i;
+ if (pageNum > 0 && pageNum <= Math.ceil(results.cves.length / itemsPerPage)) {
+ return (
+ setPackageCurrentPage(pageNum)}
+ className={`mx-1 w-6 h-6 rounded-full flex items-center justify-center text-sm ${packageCurrentPage === pageNum
+ ? 'bg-blue-500 text-white'
+ : 'border'
+ }`}
+ >
+ {pageNum}
+
+ );
+ }
+ return null;
+ })}
+ setPackageCurrentPage(prev => Math.min(Math.ceil(results.cves.length / itemsPerPage), prev + 1))}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={packageCurrentPage >= Math.ceil(results.cves.length / itemsPerPage)}
+ >
+ >
+
+ setPackageCurrentPage(Math.ceil(results.cves.length / itemsPerPage))}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={packageCurrentPage >= Math.ceil(results.cves.length / itemsPerPage)}
+ >
+ >>
+
+
+ )}
+
+ ) : (
+
+
+
No vulnerabilities found
+
+ )}
+
-
- {results?.cves && results.cves.length > 0 ? (
- <>
- {getCurrentPageItems(results.cves, packageCurrentPage).map((cve, index) => (
-
- ))}
- {results.cves.length > itemsPerPage && (
-
- )}
- >
- ) : (
-
No vulnerabilities found
- )}
+
+ {/* In the dependencies */}
+
0 ? 'h-[502px]' : 'h-[300px]'}`}>
+
+
In the dependencies
+ 0 ? 'bg-[#FD5656]' : 'bg-[#4B68FF]'}`}>
+ {results?.dep_cves?.length || 0}
+
+
+
+ {results?.dep_cves && results.dep_cves.length > 0 ? (
+
0 ? "overflow-auto h-full w-full" : ""}>
+ {getCurrentPageItems(results.dep_cves, depCurrentPage).map((cve, index) => (
+
+ ))}
+ {results.dep_cves.length > itemsPerPage && (
+
+ setDepCurrentPage(1)}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={depCurrentPage === 1}
+ >
+ <<
+
+ setDepCurrentPage(prev => Math.max(1, prev - 1))}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={depCurrentPage === 1}
+ >
+ <
+
+ {Array.from({ length: Math.min(5, results.dep_cves.length) }).map((_, i) => {
+ const pageNum = depCurrentPage - 2 + i;
+ if (pageNum > 0 && pageNum <= results.dep_cves.length) {
+ return (
+ setDepCurrentPage(pageNum)}
+ className={`mx-1 w-6 h-6 rounded-full flex items-center justify-center text-sm ${depCurrentPage === pageNum
+ ? 'bg-blue-500 text-white'
+ : 'border'
+ }`}
+ >
+ {pageNum}
+
+ );
+ }
+ return null;
+ })}
+ setDepCurrentPage(prev => Math.min(results.dep_cves.length, prev + 1))}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={depCurrentPage >= results.dep_cves.length}
+ >
+ >
+
+ setDepCurrentPage(results.dep_cves.length)}
+ className="mx-1 w-6 h-6 rounded-full flex items-center justify-center border text-sm"
+ disabled={depCurrentPage >= results.dep_cves.length}
+ >
+ >>
+
+
+ )}
+
+ ) : (
+
+
+
No vulnerabilities found
+
+ )}
+
- {/* In the dependencies 框 */}
-
-
-
In the dependencies
-
0 ? 'rgb(179, 20, 18)' : 'rgb(34, 197, 94)' }}>
- {results?.dep_cves?.length || 0}
-
+ {/* Licenses */}
+
+ {/* Licenses 标题 */}
+
-
- {results?.dep_cves && results.dep_cves.length > 0 ? (
- <>
- {getCurrentPageItems(results.dep_cves, depCurrentPage).map((cve, index) => (
-
- ))}
- {results.dep_cves.length > itemsPerPage && (
-
- )}
- >
- ) : (
-
No vulnerabilities found
- )}
+ {/* Licenses 内容 */}
+
+
+ {results ? results.license : 'No results available'}
+
-
-
- {/* Licenses */}
-
+ {/* Dependencies */}
+
+ {/* Dependencies 标题 */}
+
+ {/* Dependencies 内容 */}
+ {results && (results.dependencies.direct + results.dependencies.indirect) > 0 ? (
+
+
+ {/* Direct */}
+
+
Direct
+
{results.dependencies.direct}
+
+
+
+ {/* Indirect */}
+
+
Indirect
+
{results.dependencies.indirect}
+
+
+
+
+
+
+
+ View all dependencies ({results.dependencies.direct + results.dependencies.indirect})
+
+
+
+
+ ) : (
+
+ This Package Has No Known Dependencies.
+
+ )}
+
- {/* Dependencies */}
-
-
-
Dependencies
-
- {results ? results.dependencies.direct + results.dependencies.indirect : 0}
-
-
- {/* Direct */}
-
-
Direct
-
- {results ? JSON.stringify(results.dependencies.direct) : 'No cves detected.'}
-
-
-
0
- ? (results.dependencies.direct / (results.dependencies.direct + results.dependencies.indirect)) * 100
- : 0 // 当分母为0时,条状图宽度直接设为0%
- }%`,
- backgroundColor: 'rgb(50,165,224)',
- }}
- className="h-full rounded"
- >
+ {/* Dependents */}
+
+ {/* Dependents 标题 */}
+
+ {/* Dependents 内容 */}
+ {results && (results.dependents.direct + results.dependents.indirect) > 0 ? (
+
+
+ {/* Direct */}
+
+
Direct
+
{results.dependents.direct}
+
+
+
+ {/* Indirect */}
+
+
Indirect
+
{results.dependents.indirect}
+
+
+
+
+
+
+
+ View all dependents ({results.dependents.direct + results.dependents.indirect})
+
+
+
+
+ ) : (
+
+ This Package Has No Known Dependents.
+
+ )}
- {/* Indirect */}
-
-
Indirect
-
- {results ? JSON.stringify(results.dependencies.indirect) : 'No results available'}
-
-
-
0
- ? (results.dependencies.indirect / (results.dependencies.direct + results.dependencies.indirect)) * 100
- : 0
- }%`,
- backgroundColor: 'rgb(50,165,224)',
- }}
- className="h-full rounded"
- >
+
+ {/* 右侧内容区域 - 占据1列 */}
+
-
-
-
- View all dependencies
+ {/* 第二个摘要 */}
+
-
+
+
- {/* Dependents */}
-
-
-
Dependents
-
- {results ? results.dependents.direct + results.dependents.indirect : 0}
-
-
- {/* Direct */}
-
-
Direct
-
- {results ? JSON.stringify(results.dependents.direct) : 'No results available'}
-
-
-
-
0
- ? (results.dependents.direct / (results.dependents.direct + results.dependents.indirect)) * 100
- : 0 // 当分母为0时,条状图宽度直接设为0%
- }%`,
- backgroundColor: 'rgb(50,165,224)',
- }}
- className="h-full rounded"
- >
+ {/* Documentation */}
+
+
+
+
+ Documentation
+
+
+
-
- {/* Indirect */}
-
-
Indirect
-
- {results ? JSON.stringify(results.dependents.indirect) : 'No results available'}
-
-
-
0
- ? (results.dependents.indirect / (results.dependents.direct + results.dependents.indirect)) * 100
- : 0 // 当分母为0时,将宽度设为0%
- }%`,
- backgroundColor: 'rgb(50,165,224)',
- }}
- className="h-full rounded"
- >
+
+ {/* GitHub Links */}
+
+
+
+
+ GitHub Links
+
+
+
-
-
-
-
- View all dependents
+ {/* OpenSSF Scorecard */}
+
+
+
+
+ OpenSSF Scorecard
+
+
+
+ The Open Source Security Foundation is a cross-industry collaboration to improve the security of
+ open source software (OSS). The Scorecard provides security health metrics for open source projects.
+
+
+ View information about checks and how to fix failures.
+
+
+
+
8.3/10
+
Scorecard as of November 11, 2024
+
+
+
+ {[
+ { name: 'Code-Review', score: '10/10' },
+ { name: 'Maintained', score: '10/10' },
+ { name: 'CI/Best-Practices', score: '10/10' },
+ { name: 'License', score: '10/10' },
+ { name: 'Dangerous-Workflow', score: '10/10' },
+ { name: 'Security-Policy', score: '10/10' },
+ { name: 'Token-Permissions', score: '10/10' },
+ { name: 'Binary-Artifacts', score: '10/10' },
+ { name: 'Pinned-Dependencies', score: '10/10' }
+ ].map((item, index) => (
+
+ {item.name}
+ {item.score}
+
+ ))}
-
+
-
-
- {/* 新增的块: doc_url 和 github_url */}
-
-
-
Documentation & GitHub Links
-
+
+
+
+
+
-
- {/* OpenSSF scorecard */}
-
-
OpenSSF scorecard
-
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
-
View information about checks and how to fix failures.
-
-
8.3/10
-
Scorecard as of November 11, 2024.
+
+
API
+
+ API
+ BigQuery Dataset
+ GitHub
+
-
-
Code-Review 10/10
-
Maintained 10/10
-
CI/Best-Practices 0/10
-
License 10/10
-
Dangerous-Workflow 10/10
-
Security-Policy 10/10
-
Token-Permissions 10/10
-
Binary-Artifacts 10/10
-
Pinned-Dependencies 0/10
+
+
+
Legal
+
+ Legal
+ Privacy
+ Terms
+
+
+
+
Copyright © 2023 jp21.com.cn All Rights Reserved(@ICPBH180237号)
+
-
+
);
};
diff --git a/components/CrateNav.tsx b/components/CrateNav.tsx
index 8d5b39b..eae2d72 100644
--- a/components/CrateNav.tsx
+++ b/components/CrateNav.tsx
@@ -1,7 +1,9 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import NewHeader from '@/components/NewHeader';
+import { useHeaderContext } from '../app/context/CrateContext';
+import Image from 'next/image';
interface CrateNavProps {
nsfront: string;
@@ -13,6 +15,10 @@ interface CrateNavProps {
const CrateNav: React.FC
= ({ nsfront, nsbehind, name, version }) => {
const pathname = usePathname();
const basePath = `/${nsfront}/${nsbehind}/${name}/${version}`;
+ const [isOpen, setIsOpen] = useState(false);
+ const [currentVersion, setCurrentVersion] = useState(version);
+ const [searchTerm, setSearchTerm] = useState('');
+ const { crateData, setCrateData } = useHeaderContext();
const navItems = [
{ name: 'Overview', path: '' },
@@ -21,6 +27,22 @@ const CrateNav: React.FC = ({ nsfront, nsbehind, name, version })
{ name: 'Versions', path: '/versions' },
];
+ useEffect(() => {
+ const fetchData = async () => {
+ if (!crateData.results) {
+ const response = await fetch(`/api/crates/${nsfront}/${nsbehind}/${name}/${version}`);
+ const data = await response.json();
+ setCrateData({
+ crateName: data.crate_name,
+ crateVersion: version,
+ results: data,
+ });
+ }
+ };
+
+ fetchData();
+ }, [nsfront, nsbehind, name, version, setCrateData, crateData.results]);
+
const isActive = (path: string) => {
if (path === '') {
return pathname === basePath;
@@ -28,25 +50,91 @@ const CrateNav: React.FC = ({ nsfront, nsbehind, name, version })
return pathname === `${basePath}${path}`;
};
+ const toggleDropdown = () => {
+ setIsOpen((prev) => !prev);
+ };
+
+ const closeDropdown = () => {
+ setIsOpen(false);
+ };
+
return (
-
-
- {navItems.map((item) => (
-
- {item.name}
-
- ))}
+
+
+
+
+
{name}
+
+
+ {currentVersion || 'Select Version'}
+
+
+ {isOpen && (
+
+
+
+
+ setSearchTerm(e.target.value)}
+ className="w-[125px] h-[30px] flex-shrink-0 rounded-[9.5px] bg-white focus:bg-[#E2E9FF] border border-[#E5E5E5] focus:outline-none px-2"
+ />
+
+
+ {crateData.results?.versions
+ .filter(version => version.toLowerCase().includes(searchTerm.toLowerCase()))
+ .map((version, index) => (
+ {
+ setCurrentVersion(version);
+ setSearchTerm('');
+ closeDropdown();
+ }}
+ href={`/${nsfront}/${nsbehind}/${crateData.results?.crate_name}/${version}`}
+ >
+
+ {version}
+
+
+ ))}
+
+
+
+ )}
+
+
+
+
+ {navItems.map((item) => (
+
+ {item.name}
+ {isActive(item.path) && (
+
+ )}
+
+ ))}
+
-
+
);
};
diff --git a/components/HeaderWithSearch.tsx b/components/HeaderWithSearch.tsx
index 75c08d3..9e24d94 100644
--- a/components/HeaderWithSearch.tsx
+++ b/components/HeaderWithSearch.tsx
@@ -1,83 +1,34 @@
// components/Header.js
'use client';
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
import Link from 'next/link';
-import { useHeaderContext } from '../app/context/CrateContext';
-import { useParams } from 'next/navigation';
import { message } from 'antd';
-import { useRouter } from 'next/navigation';
-// import { cratesInfo } from '@/app/lib/all_interface';
const Header = () => {
- const router = useRouter();
- console.log('paramsssssssssssss:', router.refresh);
- const params = useParams();
- const [messageApi, contextHolder] = message.useMessage();//antd-message的hooks调用
+ const [messageApi, contextHolder] = message.useMessage();
const [searchQuery, setSearchQuery] = useState('');
- const { crateData, setCrateData } = useHeaderContext();
- const [isOpen, setIsOpen] = useState(false);
-
-
- const [currentVersion, setCurrentVersion] = useState(params.version); // 存储当前选中的版本
const handleKeyPress = (e: { key: string; }) => {
- // 检查是否按下了回车键
if (e.key === 'Enter') {
- // 如果是回车键,执行搜索
performSearch();
}
};
const performSearch = () => {
if (!searchQuery || searchQuery.trim() === '') {
-
messageApi.warning('请输入搜索内容');
- //alert("请输入搜索内容"); // 可选:提示用户输入内容
}
if (searchQuery.trim()) {
- // 使用 Link 跳转到搜索页面
window.location.href = `/search?crate_name=${searchQuery}`;
}
};
- useEffect(() => {
- const path = params.path || ''; // 确保有值
- console.log('path:', path);
- }, [params.path]); // 依赖于 params.path
- // 使用 useEffect 从 API 获取数据
- useEffect(() => {
- const fetchData = async () => {
- // 如果 crateData.results 为空,说明数据还未加载
- if (!crateData.results) {
- const response = await fetch(`/api/crates/${params.nsfront}/${params.nsbehind}/${params.name}/${params.version}`);
- const data = await response.json();
- console.log('dataaaaaaaaaaaaaa:', data);
- setCrateData({
- crateName: data.crate_name,
- crateVersion: params.version,
- results: data,
- });
-
- }
- };
-
- fetchData();
- }, [params.nsfront, params.nsbehind, params.name, params.version, setCrateData, crateData.crateVersion, crateData.results]); // 添加 crateData 作为依赖项
-
- const toggleDropdown = () => {
- setIsOpen((prev) => !prev);
- };
-
- const closeDropdown = () => {
- setIsOpen(false);
-
- };
return (
<>
{contextHolder}
-
+
open
@@ -87,55 +38,8 @@ const Header = () => {
insights
-
-
{params.name}
-
-
- {/* {crateData.crateVersion || 'Select Version'} */}
- {currentVersion || 'Select Version'}
-
-
-
-
- {isOpen && (
-
-
-
-
- {crateData.results?.versions.map((version, index) => (
- {
- setCurrentVersion(version);
- }}
- href={`/${params.nsfront}/${params.nsbehind}/${crateData.results?.crate_name}/${version}`}
- >
-
-
- {version}
-
-
-
- ))}
-
-
-
- )}
-
-
-
+
{
>
-
);
};
diff --git a/package.json b/package.json
index 6d69e83..b9ef0c6 100644
--- a/package.json
+++ b/package.json
@@ -32,10 +32,10 @@
"@types/node": "22.13.10",
"@types/react": "18.3.12",
"@types/react-dom": "18.3.1",
- "eslint": "9.22.0",
+ "eslint": "9.21.0",
"eslint-config-next": "^15.1.0"
},
"engines": {
"node": ">=20.12.0"
}
-}
+}
\ No newline at end of file
diff --git a/public/images/homepage/1.png b/public/images/homepage/1.png
new file mode 100644
index 0000000..dbdf38c
Binary files /dev/null and b/public/images/homepage/1.png differ
diff --git a/public/images/homepage/2.png b/public/images/homepage/2.png
new file mode 100644
index 0000000..dc95d5a
Binary files /dev/null and b/public/images/homepage/2.png differ
diff --git a/public/images/homepage/3.png b/public/images/homepage/3.png
new file mode 100644
index 0000000..80cb138
Binary files /dev/null and b/public/images/homepage/3.png differ
diff --git a/public/images/homepage/4.png b/public/images/homepage/4.png
new file mode 100644
index 0000000..df42690
Binary files /dev/null and b/public/images/homepage/4.png differ
diff --git a/public/images/homepage/5.png b/public/images/homepage/5.png
new file mode 100644
index 0000000..29342f1
Binary files /dev/null and b/public/images/homepage/5.png differ
diff --git a/public/images/homepage/Vector.png b/public/images/homepage/Vector.png
new file mode 100644
index 0000000..674181e
Binary files /dev/null and b/public/images/homepage/Vector.png differ
diff --git a/public/images/homepage/miss.png b/public/images/homepage/miss.png
new file mode 100644
index 0000000..8e28a1e
Binary files /dev/null and b/public/images/homepage/miss.png differ
diff --git a/public/images/homepage/verison-up.png b/public/images/homepage/verison-up.png
new file mode 100644
index 0000000..04701a6
Binary files /dev/null and b/public/images/homepage/verison-up.png differ
diff --git a/public/images/homepage/version-down.png b/public/images/homepage/version-down.png
new file mode 100644
index 0000000..e648b56
Binary files /dev/null and b/public/images/homepage/version-down.png differ