Skip to content

Commit f656322

Browse files
authored
Merge pull request #1 from martinwq997/submit-button
feat
2 parents 1dd68d9 + 400258f commit f656322

File tree

5 files changed

+201
-28
lines changed

5 files changed

+201
-28
lines changed

app/api/cves/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const generateRandomCVE = (): CVE => {
3232

3333
export async function GET() {
3434
try {
35-
const randomCVEs = Array.from({ length: 5 }, generateRandomCVE);
35+
const randomCVEs = Array.from({ length: 7 }, generateRandomCVE);
3636
return NextResponse.json(randomCVEs);
3737
} catch (error) {
3838
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });

app/api/submit/route.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import pool from '../../lib/db'; // 导入数据库连接池
3+
4+
export async function POST(req: NextRequest) {
5+
try {
6+
const { content } = await req.json(); // 解析请求体中的 JSON 数据
7+
8+
if (!content) {
9+
return NextResponse.json({ error: '内容不能为空' }, { status: 400 });
10+
}
11+
12+
const client = await pool.connect(); // 获取数据库连接
13+
// 假设我们将内容插入到名为 'submissions' 的表中
14+
await client.query('INSERT INTO submissions (content) VALUES ($1)', [content]);
15+
client.release(); // 释放连接
16+
17+
return NextResponse.json({ message: '内容提交成功!' }, { status: 200 });
18+
} catch (error) {
19+
console.error('提交错误:', error);
20+
return NextResponse.json({ error: '内部服务器错误' }, { status: 500 });
21+
}
22+
}

app/programs/[name]/[version]/page.tsx

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ import Header from '../../../../components/Header';
66
import Footer from '../../../../components/Footer';
77
import CrateInfoCard from '../../../../components/CrateInfoCard';
88
import DependenciesList, { Dependency } from '../../../../components/DependenciesList';
9-
import DependencyGraph, {GraphDependency} from '../../../../components/DependencyGraph';
9+
import DependencyGraph, { GraphDependency } from '../../../../components/DependencyGraph';
1010
import VulnerabilitiesList, { Vulnerability } from '../../../../components/VulnerabilitiesList';
1111
import SecurityAdvisories from '../../../../components/SecurityAdvisories';
1212
import BenchmarkResults from '../../../../components/BenchmarkResults';
1313
import VersionsSelector from '../../../../components/VersionsSelector';
1414
import { CrateInfo } from '@/app/lib/crate_info';
1515

16-
16+
//异步获取依赖树
1717
async function fetchDependencyTree(name: string, version: string) {
1818
const response = await fetch(`/api/crates/${name}/${version}`);
1919
const versionData = await response.json();
20-
20+
2121
const dependencies = versionData.dependencies || [];
22-
22+
2323
const dependenciesDetails = await Promise.all(dependencies.map(async (subDep: { name: string; version: string; }) => {
2424
return fetchDependencyTree(subDep.name, subDep.version);
2525
}));
@@ -49,31 +49,31 @@ const CratePage = () => {
4949

5050

5151
useEffect(() => {
52-
52+
5353
fetch(`/api/crates/${crateName}`)
5454
.then(response => response.json())
5555
.then(data => {
5656
setCrateInfo(data.crateInfo || {});
5757
setVersions(data.versions || []);
58-
58+
5959
setBenchmarks(data.benchmarks || []);
6060
})
6161
.catch(error => {
6262
console.error('Error fetching data:', error);
6363
});
64-
64+
6565
}, [crateName, currentVersion]);
66-
67-
useEffect(()=>{
66+
67+
useEffect(() => {
6868
fetch(`/api/crates/${name}/${version}`)
69-
.then(response => response.json())
70-
.then(data => {
71-
setVulnerabilities(data.vulnerabilities);
72-
setDependencies(data.dependencies);
73-
})
74-
.catch(error => {
75-
console.error('Error fetching data:', error);
76-
});
69+
.then(response => response.json())
70+
.then(data => {
71+
setVulnerabilities(data.vulnerabilities);
72+
setDependencies(data.dependencies);
73+
})
74+
.catch(error => {
75+
console.error('Error fetching data:', error);
76+
});
7777

7878

7979
}, [crateName, currentVersion]);
@@ -89,7 +89,7 @@ const CratePage = () => {
8989
console.error('Error fetching dependency tree:', error);
9090
}
9191
}
92-
92+
9393
if (crateName && currentVersion) {
9494
loadDependencies();
9595
}
@@ -113,7 +113,7 @@ const CratePage = () => {
113113
<Header onBack={() => window.history.back()} />
114114
<main className="flex-grow overflow-y-auto bg-gray-100">
115115
<div className="container mx-auto p-2 flex">
116-
<div className="w-full md:w-2/3 pr-2">
116+
<div className="w-full md:w-2/3 pr-2">
117117
<CrateInfoCard crateInfo={crateInfo} />
118118
<SecurityAdvisories vulnerabilities={vulnerabilities} />
119119
<VulnerabilitiesList vulnerabilities={vulnerabilities} />
@@ -126,7 +126,7 @@ const CratePage = () => {
126126
crateName={crateInfo.name}
127127
onVersionChange={handleVersionChange}
128128
/>
129-
129+
130130
<DependenciesList dependencies={dependencies} onDependencyClick={handleDependencyClick} />
131131
<DependencyGraph crateName={name} currentVersion={version} dependencies={graphDependencies} />
132132
</div>

app/programs/page.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
import { useEffect, useState } from 'react';
33
import Link from 'next/link';
44

5+
//接口定义-Rust程序的结构
56
interface ObjectData {
67
name: string;
78
description: string;
89
category: string;
910
}
1011

12+
//接口定义-描述CVE数据的结构
1113
interface CVE {
1214
id: string;
1315
description: string;
@@ -16,15 +18,24 @@ interface CVE {
1618
}
1719

1820
const ProgramsPage = () => {
19-
const [objects, setObjects] = useState<ObjectData[]>([]);
20-
const [cveData, setCveData] = useState<CVE[]>([]);
21+
const [objects, setObjects] = useState<ObjectData[]>([]); //从接口获取Rust程序数据
22+
const [cveData, setCveData] = useState<CVE[]>([]); //从接口获取CVE数据
2123

24+
//获取数据
2225
useEffect(() => {
23-
fetch('/api/crates')
26+
fetch('/api/crates') //这里应调用后端接口:GET http://localhost:6888/api/crates (?)
2427
.then(response => response.json())
25-
.then(data => setObjects(data));
28+
.then(data => {
29+
console.log('Fetched crates data:', data); //调试输出
30+
if (Array.isArray(data)) {
31+
setObjects(data);
32+
} else {
33+
console.error('Crates data is not an array:', data);
34+
setObjects([]);//如果不是数组,设置为空数组
35+
}
36+
});
2637

27-
fetch('/api/cves')
38+
fetch('/api/cves') //这里应调用后端接口: GET http://localhost:6888/api/crates/{name} (?)
2839
.then(response => {
2940
if (!response.ok) {
3041
throw new Error(`HTTP error! status: ${response.status}`);
@@ -69,7 +80,7 @@ const ProgramsPage = () => {
6980
<h1 className="text-3xl font-bold mb-4">CVE List</h1>
7081
<ul className="grid grid-cols-1 gap-4">
7182
{cveData.map((cve) => (
72-
<li key={cve.id} className="bg-white shadow-md rounded-lg p-4 transition-transform transform hover:scale-105">
83+
<li key={cve.id} className="bg-white shadow-md rounded-lg p-4 transition-transform transform hover:scale-105">{/* 这里transform hover:scale-105和submit弹窗有冲突 */}
7384
<Link href={`programs/cves/${cve.id}`} className="text-xl font-bold text-blue-500 hover:text-blue-600">
7485
{cve.id}
7586
</Link>

app/ui/programs/nav-links.tsx

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
HomeIcon,
66
DocumentDuplicateIcon,
77
} from '@heroicons/react/24/outline';
8+
import { PaperAirplaneIcon } from '@heroicons/react/24/outline';
9+
import { useState } from 'react';
810
import Link from 'next/link';
911
import { usePathname } from 'next/navigation';
1012
import clsx from 'clsx';
@@ -23,6 +25,46 @@ const links = [
2325

2426
export default function NavLinks() {
2527
const pathname = usePathname();
28+
const [isModalOpen, setModalOpen] = useState(false);
29+
const [inputValue, setInputValue] = useState('');
30+
31+
const [file, setFile] = useState<File | null>(null);
32+
const [isGithubLink, setIsGithubLink] = useState(true); // 控制输入类型
33+
34+
//暂定上传数据类型为react表单类型
35+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
36+
e.preventDefault();
37+
38+
const formData = new FormData();
39+
if (isGithubLink) {
40+
formData.append('githubLink', inputValue);
41+
} else if (file) {
42+
formData.append('file', file);
43+
}
44+
45+
try {
46+
//用fetch向服务器发声POST请求,提交用户输入的内容
47+
const response = await fetch('/api/submi', { // 待替换为服务器API
48+
method: 'POST',
49+
//请求体,将对象转换为json字符串
50+
body: formData,
51+
});
52+
//响应处理,根据响应结果显示提示信息,并重置输入框或关闭弹窗
53+
if (response.ok) {
54+
alert('内容提交成功!');//提交成功后重置输入框的值,并关闭弹窗
55+
setInputValue('');
56+
setFile(null);
57+
setModalOpen(false);
58+
} else {
59+
alert('提交失败,请重试。');
60+
}
61+
} catch (error) {
62+
console.error('提交错误:', error);
63+
alert('提交失败,请检查网络连接。');
64+
}
65+
};
66+
67+
//渲染部分
2668
return (
2769
<>
2870
{links.map((link) => {
@@ -43,6 +85,104 @@ export default function NavLinks() {
4385
</Link>
4486
);
4587
})}
88+
89+
{/* 提交按钮 */}
90+
{/* <button
91+
onClick={() => setModalOpen(true)}
92+
className="mt-4 flex h-[48px] w-full items-center justify-center rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600"
93+
>
94+
Submit
95+
</button> */}
96+
97+
98+
99+
{/* submit按钮 */}
100+
<button
101+
onClick={() => setModalOpen(true)} //点击打开弹窗
102+
className={clsx(
103+
'mt-4 flex h-[48px] items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium text-gray-800 hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3'
104+
)}
105+
>
106+
<PaperAirplaneIcon className="w-6" /> {/* 使用的图标 */}
107+
Submit
108+
</button>
109+
110+
{/* 弹窗 条件渲染,isModalOpen为true才渲染*/}
111+
{isModalOpen && (
112+
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
113+
<div className="bg-white p-6 rounded-md w-96 ">
114+
<h2 className="text-lg font-bold mb-4">Submit Crates</h2>
115+
{/* 表单元素,包裹输入控件和提交按钮 */}
116+
<form onSubmit={handleSubmit}> {/* 将表单的提交事件绑定到handleSubmit函数,处理用户提交逻辑 */}
117+
<div className="mb-4">
118+
<label>
119+
<input
120+
type="radio"
121+
value="github"
122+
checked={isGithubLink}
123+
onChange={() => setIsGithubLink(true)}
124+
/>
125+
GitHub Link
126+
</label>
127+
<label className="ml-4">
128+
<input
129+
type="radio"
130+
value="zip"
131+
checked={!isGithubLink}
132+
onChange={() => setIsGithubLink(false)}
133+
/>
134+
Upload ZIP File
135+
</label>
136+
</div>
137+
138+
{isGithubLink ? (
139+
<input
140+
type="url"
141+
value={inputValue}
142+
onChange={(e) => setInputValue(e.target.value)}
143+
className="w-full p-2 border rounded-md"
144+
placeholder="Enter GitHub URL..."
145+
required
146+
/>
147+
) : (
148+
<div>
149+
{/*<label className="block mb-2">Select a ZIP file:</label>*/}
150+
<input
151+
type="file"
152+
accept=".zip"
153+
onChange={(e) => {
154+
const selectedFile = e.target.files?.[0]; // 使用可选链操作符检查 files 是否为 null
155+
if (selectedFile) {
156+
setFile(selectedFile);
157+
} else {
158+
setFile(null); // 如果没有文件选择,清空文件状态
159+
}
160+
}}
161+
className="w-full p-2 border rounded-md"
162+
required
163+
/>
164+
</div>
165+
)}
166+
167+
<div className="flex justify-end mt-4">
168+
<button
169+
type="button"
170+
onClick={() => setModalOpen(false)}
171+
className="mr-2 rounded-md bg-gray-300 p-2"
172+
>
173+
Cancel
174+
</button>
175+
<button
176+
type="submit"
177+
className="rounded-md bg-blue-600 text-white p-2"
178+
>
179+
Submit
180+
</button>
181+
</div>
182+
</form>
183+
</div>
184+
</div>
185+
)}
46186
</>
47187
);
48-
}
188+
}

0 commit comments

Comments
 (0)