feat: web update vuln list
This commit is contained in:
@@ -9,15 +9,16 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.7.4",
|
||||
"postcss": "^8.4.41",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.26.0",
|
||||
"axios": "^1.7.4",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.4.41",
|
||||
"vite": "^5.4.2",
|
||||
"@vitejs/plugin-react": "^4.3.1"
|
||||
"vite": "^5.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.3.4",
|
||||
|
||||
11
assets/pnpm-lock.yaml
generated
11
assets/pnpm-lock.yaml
generated
@@ -5,6 +5,9 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@tailwindcss/line-clamp':
|
||||
specifier: ^0.4.4
|
||||
version: 0.4.4(tailwindcss@3.4.17)
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^4.3.1
|
||||
version: 4.7.0(vite@5.4.19)
|
||||
@@ -671,6 +674,14 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tailwindcss/line-clamp@0.4.4(tailwindcss@3.4.17):
|
||||
resolution: {integrity: sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==}
|
||||
peerDependencies:
|
||||
tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1'
|
||||
dependencies:
|
||||
tailwindcss: 3.4.17
|
||||
dev: false
|
||||
|
||||
/@types/babel__core@7.20.5:
|
||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||
dependencies:
|
||||
|
||||
@@ -45,9 +45,9 @@ const VulnerabilityListPage = () => {
|
||||
const totalPages = Math.ceil(totalCount / pageSize)
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center mb-8">
|
||||
<h1 className="text-3xl font-extrabold text-gray-900 mb-2">
|
||||
<div className="mx-auto max-w-7xl">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="mb-2 text-3xl font-extrabold text-gray-900">
|
||||
漏洞信息列表
|
||||
</h1>
|
||||
<p className="text-gray-600">
|
||||
@@ -64,13 +64,13 @@ const VulnerabilityListPage = () => {
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
placeholder="搜索漏洞标题或描述..."
|
||||
className="block w-full pl-4 pr-12 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
className="block w-full py-2 pl-4 pr-12 leading-5 placeholder-gray-500 bg-white border border-gray-300 rounded-md focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="absolute inset-y-0 right-0 flex items-center pr-3"
|
||||
>
|
||||
<svg className="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<svg className="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -79,82 +79,84 @@ const VulnerabilityListPage = () => {
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 rounded-md p-4 mb-6">
|
||||
<div className="text-red-800 text-sm">
|
||||
<div className="p-4 mb-6 border border-red-200 rounded-md bg-red-50">
|
||||
<div className="text-sm text-red-800">
|
||||
{error}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex justify-center items-center h-64">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600"></div>
|
||||
<div className="flex items-center justify-center h-64">
|
||||
<div className="w-12 h-12 border-b-2 border-indigo-600 rounded-full animate-spin"></div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{vulnerabilities.map((vuln) => (
|
||||
<div key={vuln.id} className="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-300 ease-in-out">
|
||||
<Link to={`/vulns/${vuln.id}`} className="block h-full">
|
||||
<div className="p-6 h-full flex flex-col">
|
||||
<div className="flex justify-between items-start">
|
||||
<h3 className="text-lg font-bold text-gray-900 truncate">{vuln.title}</h3>
|
||||
<span className={`ml-2 px-2 py-1 text-xs font-semibold rounded-full ${
|
||||
vuln.severity === 'Critical' ? 'bg-red-100 text-red-800' :
|
||||
vuln.severity === 'High' ? 'bg-orange-100 text-orange-800' :
|
||||
vuln.severity === 'Medium' ? 'bg-yellow-100 text-yellow-800' :
|
||||
'bg-green-100 text-green-800'
|
||||
}`}>
|
||||
{vuln.severity}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p className="mt-3 text-gray-600 text-sm flex-grow">
|
||||
{vuln.description.substring(0, 120)}...
|
||||
</p>
|
||||
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{vuln.tags && vuln.tags.slice(0, 3).map((tag, index) => (
|
||||
<span key={index} className="px-2 py-1 bg-indigo-100 text-indigo-800 text-xs font-medium rounded-full">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
{vuln.tags && vuln.tags.length > 3 && (
|
||||
<span className="px-2 py-1 bg-gray-100 text-gray-800 text-xs font-medium rounded-full">
|
||||
+{vuln.tags.length - 3}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex items-center justify-between text-sm">
|
||||
<div className="flex items-center">
|
||||
<svg className="h-4 w-4 text-gray-500 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
||||
</svg>
|
||||
<span className="text-gray-500">CVE: {vuln.cve || 'N/A'}</span>
|
||||
<div className="overflow-hidden bg-white shadow sm:rounded-md">
|
||||
<ul className="divide-y divide-gray-200">
|
||||
{vulnerabilities.map((vuln) => (
|
||||
<li key={vuln.id}>
|
||||
<Link to={`/vulns/${vuln.id}`} className="block hover:bg-gray-50">
|
||||
<div className="px-4 py-4 sm:px-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm font-medium text-indigo-600 truncate">{vuln.title}</p>
|
||||
<div className="flex flex-shrink-0 ml-2">
|
||||
<span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
|
||||
vuln.severity === 'Critical' ? 'bg-red-100 text-red-800' :
|
||||
vuln.severity === 'High' ? 'bg-orange-100 text-orange-800' :
|
||||
vuln.severity === 'Medium' ? 'bg-yellow-100 text-yellow-800' :
|
||||
'bg-green-100 text-green-800'
|
||||
}`}>
|
||||
{vuln.severity}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<svg className="h-4 w-4 text-gray-500 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span className="text-gray-500">
|
||||
{vuln.pushed ? '已推送' : '未推送'}
|
||||
</span>
|
||||
<div className="mt-2 sm:flex sm:justify-between">
|
||||
<div className="sm:flex">
|
||||
<p className="flex items-center text-sm text-gray-500">
|
||||
CVE: {vuln.cve || 'N/A'}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mt-2 sm:mt-0 sm:ml-6">
|
||||
{vuln.tags && vuln.tags.slice(0, 5).map((tag, index) => (
|
||||
<span key={index} className="px-2 py-1 text-xs font-medium text-indigo-800 bg-indigo-100 rounded-full">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
{vuln.tags && vuln.tags.length > 5 && (
|
||||
<span className="px-2 py-1 text-xs font-medium text-gray-800 bg-gray-100 rounded-full">
|
||||
+{vuln.tags.length - 5}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center mt-2 text-sm text-gray-500 sm:mt-0">
|
||||
<svg className="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clipRule="evenodd" />
|
||||
</svg>
|
||||
<p>
|
||||
更新时间: <time dateTime={vuln.updated_at}>{new Date(vuln.updated_at).toLocaleDateString('zh-CN')}</time>
|
||||
</p>
|
||||
<span className={`ml-4 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
|
||||
vuln.pushed ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{vuln.pushed ? '已推送' : '未推送'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-gray-500 line-clamp-2">
|
||||
{vuln.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 text-xs text-gray-400">
|
||||
更新时间: {new Date(vuln.updated_at).toLocaleDateString('zh-CN')}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
))}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* 分页组件 */}
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<div className="flex items-center justify-between mt-6">
|
||||
<div className="text-sm text-gray-700">
|
||||
显示第 {(pageNo - 1) * pageSize + 1} 到 {Math.min(pageNo * pageSize, totalCount)} 条记录,
|
||||
总共 {totalCount} 条记录
|
||||
|
||||
@@ -7,5 +7,7 @@ export default {
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
plugins: [
|
||||
require('@tailwindcss/line-clamp'),
|
||||
],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user