131 lines
3.4 KiB
TypeScript
131 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback } from "react";
|
|
import { Select, Button, Space, App } from "antd";
|
|
import { EditOutlined, PlusOutlined } from "@ant-design/icons";
|
|
import { ConfigModal } from "./ConfigModal";
|
|
import { getConfig } from "@/services/config";
|
|
import { parseProject } from "@/services/project";
|
|
import type { Config } from "@/types";
|
|
import type { ParsedProject } from "@/services/project";
|
|
|
|
interface ConfigEntry {
|
|
name: string;
|
|
file: string;
|
|
}
|
|
|
|
interface ConfigSelectorProps {
|
|
configs: ConfigEntry[];
|
|
selectedFile: string | null;
|
|
onSelect: (file: string, config: Config, project: ParsedProject) => void;
|
|
onConfigAdded: (entry: ConfigEntry) => void;
|
|
onConfigUpdated: (entry: ConfigEntry) => void;
|
|
}
|
|
|
|
export function ConfigSelector({
|
|
configs,
|
|
selectedFile,
|
|
onSelect,
|
|
onConfigAdded,
|
|
onConfigUpdated,
|
|
}: ConfigSelectorProps) {
|
|
const { message } = App.useApp();
|
|
const [selecting, setSelecting] = useState(false);
|
|
|
|
// Config modal state
|
|
const [modalOpen, setModalOpen] = useState(false);
|
|
const [modalMode, setModalMode] = useState<"add" | "edit">("add");
|
|
const [modalInitial, setModalInitial] = useState<{
|
|
file: string;
|
|
config: Config;
|
|
} | null>(null);
|
|
|
|
// Handle config selection
|
|
const handleChange = useCallback(
|
|
async (file: string) => {
|
|
setSelecting(true);
|
|
try {
|
|
const config = await getConfig(file);
|
|
const project = await parseProject(config);
|
|
onSelect(file, config, project);
|
|
} catch (err) {
|
|
message.error(
|
|
err instanceof Error ? err.message : "解析项目配置失败",
|
|
);
|
|
} finally {
|
|
setSelecting(false);
|
|
}
|
|
},
|
|
[onSelect],
|
|
);
|
|
|
|
// Open add modal
|
|
const openAdd = useCallback(() => {
|
|
setModalMode("add");
|
|
setModalInitial(null);
|
|
setModalOpen(true);
|
|
}, []);
|
|
|
|
// Open edit modal
|
|
const openEdit = useCallback(async () => {
|
|
if (!selectedFile) {
|
|
message.warning("请先选择一个配置");
|
|
return;
|
|
}
|
|
try {
|
|
const config = await getConfig(selectedFile);
|
|
setModalMode("edit");
|
|
setModalInitial({ file: selectedFile, config });
|
|
setModalOpen(true);
|
|
} catch (err) {
|
|
message.error("读取配置失败");
|
|
}
|
|
}, [selectedFile]);
|
|
|
|
// Modal save callback
|
|
const handleModalSaved = useCallback(
|
|
(file: string, name: string) => {
|
|
if (modalMode === "add") {
|
|
onConfigAdded({ name, file });
|
|
} else {
|
|
onConfigUpdated({ name, file });
|
|
}
|
|
setModalOpen(false);
|
|
},
|
|
[modalMode, onConfigAdded, onConfigUpdated],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Space.Compact style={{ width: "100%" }}>
|
|
<Select
|
|
style={{ flex: 1 }}
|
|
placeholder="选择配置…"
|
|
loading={selecting}
|
|
value={selectedFile}
|
|
onChange={handleChange}
|
|
options={configs.map((c) => ({
|
|
value: c.file,
|
|
label: c.name,
|
|
}))}
|
|
/>
|
|
<Button icon={<EditOutlined />} onClick={openEdit}>
|
|
修改配置
|
|
</Button>
|
|
<Button icon={<PlusOutlined />} onClick={openAdd}>
|
|
添加配置
|
|
</Button>
|
|
</Space.Compact>
|
|
|
|
<ConfigModal
|
|
open={modalOpen}
|
|
mode={modalMode}
|
|
initialFile={modalInitial?.file ?? null}
|
|
initialConfig={modalInitial?.config ?? null}
|
|
onCancel={() => setModalOpen(false)}
|
|
onSaved={handleModalSaved}
|
|
/>
|
|
</>
|
|
);
|
|
}
|