Add Modrinth and CurseForge project ID lookup to field validation

This commit is contained in:
CPTProgrammer 2026-07-14 14:29:56 +08:00
parent 9658773fa2
commit 52ef5bf927
No known key found for this signature in database
2 changed files with 63 additions and 59 deletions

View File

@ -13,7 +13,6 @@ import {
App,
} from "antd";
import { PlusOutlined, DeleteOutlined } from "@ant-design/icons";
import { useDebouncedCallback } from "use-debounce";
import { createConfig, updateConfig } from "@/services/config";
import {
getModrinthLoaders,
@ -25,6 +24,8 @@ import {
readProjectVersion,
checkArtifactFiles,
checkSourceFiles,
lookupModrinthProject,
lookupCurseforgeProject,
} from "@/services/project";
import {
useFieldValidations,
@ -137,6 +138,32 @@ const STATIC_DEFS: StaticValidationDef<Config>[] = [
: { status: "error", help: r.error };
},
},
// 5. Modrinth 项目 ID
{
target: ["modrinth", "project_id"],
deps: [["modrinth", "project_id"]],
async validate(getVal) {
const id = getVal(["modrinth", "project_id"]) as string | undefined;
if (!id) return null;
const r = await lookupModrinthProject(id);
return r.ok
? { status: "success", help: `项目:${r.name}` }
: { status: "error", help: r.error };
},
},
// 6. CurseForge 项目 ID
{
target: ["curseforge", "project_id"],
deps: [["curseforge", "project_id"]],
async validate(getVal) {
const id = getVal(["curseforge", "project_id"]) as number | undefined;
if (id == null || id === 0) return null;
const r = await lookupCurseforgeProject(id);
return r.ok
? { status: "success", help: `项目:${r.name}` }
: { status: "error", help: r.error };
},
},
];
const LIST_DEFS: ListValidationDef<Config>[] = [];
@ -299,29 +326,6 @@ export function ConfigModal({
[mode, initialName, onSaved, message],
);
// --------------- Debounced project name lookup ---------------
const [modrinthProjectName, setModrinthProjectName] = useState<string | null>(null);
const [curseforgeProjectName, setCurseforgeProjectName] = useState<string | null>(null);
const lookupModrinthProject = useDebouncedCallback(async (projectId: string) => {
if (!projectId) {
setModrinthProjectName(null);
return;
}
// TODO: call Modrinth API to get project name
setModrinthProjectName(null);
}, 800);
const lookupCurseforgeProject = useDebouncedCallback(async (projectId: number | null) => {
if (projectId == null) {
setCurseforgeProjectName(null);
return;
}
// TODO: call CurseForge API to get project name
setCurseforgeProjectName(null);
}, 800);
// --------------- Render ---------------
return (
@ -351,10 +355,6 @@ export function ConfigModal({
<ConfigModalForm
mode={mode}
initialConfig={initialConfig}
modrinthProjectName={modrinthProjectName}
curseforgeProjectName={curseforgeProjectName}
lookupModrinthProject={lookupModrinthProject}
lookupCurseforgeProject={lookupCurseforgeProject}
onSave={handleSave}
/>
</Modal>
@ -368,20 +368,12 @@ export function ConfigModal({
interface ConfigModalFormProps {
mode: "add" | "edit";
initialConfig: Config | null;
modrinthProjectName: string | null;
curseforgeProjectName: string | null;
lookupModrinthProject: (projectId: string) => void;
lookupCurseforgeProject: (projectId: number | null) => void;
onSave: (values: ConfigValues) => void;
}
function ConfigModalForm({
mode,
initialConfig,
modrinthProjectName,
curseforgeProjectName,
lookupModrinthProject,
lookupCurseforgeProject,
onSave,
}: ConfigModalFormProps) {
const [form] = Form.useForm<ConfigValues>();
@ -527,23 +519,15 @@ function ConfigModalForm({
label: "Modrinth",
children: (
<>
<Form.Item
<ValidatedFormItem
name={["modrinth", "project_id"]}
label="项目 ID"
rules={[
{ required: true, message: "请输入 Modrinth 项目 ID" },
]}
extra={
modrinthProjectName
? `项目名称: ${modrinthProjectName}`
: undefined
}
>
<Input
placeholder="8 位 base62"
onChange={(e) => lookupModrinthProject(e.target.value)}
/>
</Form.Item>
<Input placeholder="8 位 base62" />
</ValidatedFormItem>
<Form.Item
name={["modrinth", "version_name"]}
@ -658,7 +642,7 @@ function ConfigModalForm({
label: "CurseForge",
children: (
<>
<Form.Item
<ValidatedFormItem
name={["curseforge", "project_id"]}
label="项目 ID"
rules={[
@ -667,22 +651,12 @@ function ConfigModalForm({
message: "请输入 CurseForge 项目 ID",
},
]}
extra={
curseforgeProjectName
? `项目名称: ${curseforgeProjectName}`
: undefined
}
>
<InputNumber
style={{ width: "100%" }}
placeholder="数字 ID"
onChange={(val) =>
lookupCurseforgeProject(
typeof val === "number" ? val : null,
)
}
/>
</Form.Item>
</ValidatedFormItem>
<Form.Item
name={["curseforge", "version_name"]}

View File

@ -250,3 +250,33 @@ export async function checkSourceFiles(
}
return { ok: true, matched };
}
// ---------------------------------------------------------------------------
// 平台项目查询
// ---------------------------------------------------------------------------
import { getProject } from "@/lib/modrinth/project";
import { getMod } from "@/lib/curseforge/mod";
import { modrinthClient, curseforgeClient } from "./clients";
export async function lookupModrinthProject(
projectId: string,
): Promise<OkResult<{ name: string }> | ErrResult> {
try {
const project = await getProject(modrinthClient, projectId);
return { ok: true, name: project.title };
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : "查询 Modrinth 项目失败" };
}
}
export async function lookupCurseforgeProject(
projectId: number,
): Promise<OkResult<{ name: string }> | ErrResult> {
try {
const mod = await getMod(curseforgeClient, projectId);
return { ok: true, name: mod.data.name };
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : "查询 CurseForge 项目失败" };
}
}