Add Modrinth and CurseForge project ID lookup to field validation
This commit is contained in:
parent
9658773fa2
commit
52ef5bf927
@ -13,7 +13,6 @@ import {
|
|||||||
App,
|
App,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import { PlusOutlined, DeleteOutlined } from "@ant-design/icons";
|
import { PlusOutlined, DeleteOutlined } from "@ant-design/icons";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import { createConfig, updateConfig } from "@/services/config";
|
import { createConfig, updateConfig } from "@/services/config";
|
||||||
import {
|
import {
|
||||||
getModrinthLoaders,
|
getModrinthLoaders,
|
||||||
@ -25,6 +24,8 @@ import {
|
|||||||
readProjectVersion,
|
readProjectVersion,
|
||||||
checkArtifactFiles,
|
checkArtifactFiles,
|
||||||
checkSourceFiles,
|
checkSourceFiles,
|
||||||
|
lookupModrinthProject,
|
||||||
|
lookupCurseforgeProject,
|
||||||
} from "@/services/project";
|
} from "@/services/project";
|
||||||
import {
|
import {
|
||||||
useFieldValidations,
|
useFieldValidations,
|
||||||
@ -137,6 +138,32 @@ const STATIC_DEFS: StaticValidationDef<Config>[] = [
|
|||||||
: { status: "error", help: r.error };
|
: { 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>[] = [];
|
const LIST_DEFS: ListValidationDef<Config>[] = [];
|
||||||
@ -299,29 +326,6 @@ export function ConfigModal({
|
|||||||
[mode, initialName, onSaved, message],
|
[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 ---------------
|
// --------------- Render ---------------
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -351,10 +355,6 @@ export function ConfigModal({
|
|||||||
<ConfigModalForm
|
<ConfigModalForm
|
||||||
mode={mode}
|
mode={mode}
|
||||||
initialConfig={initialConfig}
|
initialConfig={initialConfig}
|
||||||
modrinthProjectName={modrinthProjectName}
|
|
||||||
curseforgeProjectName={curseforgeProjectName}
|
|
||||||
lookupModrinthProject={lookupModrinthProject}
|
|
||||||
lookupCurseforgeProject={lookupCurseforgeProject}
|
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
@ -368,20 +368,12 @@ export function ConfigModal({
|
|||||||
interface ConfigModalFormProps {
|
interface ConfigModalFormProps {
|
||||||
mode: "add" | "edit";
|
mode: "add" | "edit";
|
||||||
initialConfig: Config | null;
|
initialConfig: Config | null;
|
||||||
modrinthProjectName: string | null;
|
|
||||||
curseforgeProjectName: string | null;
|
|
||||||
lookupModrinthProject: (projectId: string) => void;
|
|
||||||
lookupCurseforgeProject: (projectId: number | null) => void;
|
|
||||||
onSave: (values: ConfigValues) => void;
|
onSave: (values: ConfigValues) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConfigModalForm({
|
function ConfigModalForm({
|
||||||
mode,
|
mode,
|
||||||
initialConfig,
|
initialConfig,
|
||||||
modrinthProjectName,
|
|
||||||
curseforgeProjectName,
|
|
||||||
lookupModrinthProject,
|
|
||||||
lookupCurseforgeProject,
|
|
||||||
onSave,
|
onSave,
|
||||||
}: ConfigModalFormProps) {
|
}: ConfigModalFormProps) {
|
||||||
const [form] = Form.useForm<ConfigValues>();
|
const [form] = Form.useForm<ConfigValues>();
|
||||||
@ -527,23 +519,15 @@ function ConfigModalForm({
|
|||||||
label: "Modrinth",
|
label: "Modrinth",
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<Form.Item
|
<ValidatedFormItem
|
||||||
name={["modrinth", "project_id"]}
|
name={["modrinth", "project_id"]}
|
||||||
label="项目 ID"
|
label="项目 ID"
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: "请输入 Modrinth 项目 ID" },
|
{ required: true, message: "请输入 Modrinth 项目 ID" },
|
||||||
]}
|
]}
|
||||||
extra={
|
|
||||||
modrinthProjectName
|
|
||||||
? `项目名称: ${modrinthProjectName}`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Input
|
<Input placeholder="8 位 base62" />
|
||||||
placeholder="8 位 base62"
|
</ValidatedFormItem>
|
||||||
onChange={(e) => lookupModrinthProject(e.target.value)}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["modrinth", "version_name"]}
|
name={["modrinth", "version_name"]}
|
||||||
@ -658,7 +642,7 @@ function ConfigModalForm({
|
|||||||
label: "CurseForge",
|
label: "CurseForge",
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<Form.Item
|
<ValidatedFormItem
|
||||||
name={["curseforge", "project_id"]}
|
name={["curseforge", "project_id"]}
|
||||||
label="项目 ID"
|
label="项目 ID"
|
||||||
rules={[
|
rules={[
|
||||||
@ -667,22 +651,12 @@ function ConfigModalForm({
|
|||||||
message: "请输入 CurseForge 项目 ID",
|
message: "请输入 CurseForge 项目 ID",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
extra={
|
|
||||||
curseforgeProjectName
|
|
||||||
? `项目名称: ${curseforgeProjectName}`
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
placeholder="数字 ID"
|
placeholder="数字 ID"
|
||||||
onChange={(val) =>
|
|
||||||
lookupCurseforgeProject(
|
|
||||||
typeof val === "number" ? val : null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</ValidatedFormItem>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["curseforge", "version_name"]}
|
name={["curseforge", "version_name"]}
|
||||||
|
|||||||
@ -250,3 +250,33 @@ export async function checkSourceFiles(
|
|||||||
}
|
}
|
||||||
return { ok: true, matched };
|
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 项目失败" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user