2025-09-24 23:24:00 +08:00
|
|
|
|
import { useState, useEffect, useMemo } from "react";
|
2023-09-06 00:25:46 +08:00
|
|
|
|
import Stack from "@mui/material/Stack";
|
|
|
|
|
|
import TextField from "@mui/material/TextField";
|
|
|
|
|
|
import Button from "@mui/material/Button";
|
2024-04-16 16:39:11 +08:00
|
|
|
|
import LoadingButton from "@mui/lab/LoadingButton";
|
2025-06-03 23:07:10 +08:00
|
|
|
|
import MenuItem from "@mui/material/MenuItem";
|
2025-07-01 10:54:30 +08:00
|
|
|
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
|
|
|
|
import Switch from "@mui/material/Switch";
|
2025-09-24 23:24:00 +08:00
|
|
|
|
import { useI18n } from "../../hooks/I18n";
|
|
|
|
|
|
import Typography from "@mui/material/Typography";
|
|
|
|
|
|
import Accordion from "@mui/material/Accordion";
|
|
|
|
|
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
|
|
|
|
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
|
|
|
|
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
|
|
|
|
import AddIcon from "@mui/icons-material/Add";
|
|
|
|
|
|
import Alert from "@mui/material/Alert";
|
|
|
|
|
|
import Menu from "@mui/material/Menu";
|
|
|
|
|
|
import Grid from "@mui/material/Grid";
|
|
|
|
|
|
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
|
|
|
|
|
import { useAlert } from "../../hooks/Alert";
|
|
|
|
|
|
import { useApiList, useApiItem } from "../../hooks/Api";
|
|
|
|
|
|
import { useConfirm } from "../../hooks/Confirm";
|
|
|
|
|
|
import { apiTranslate } from "../../apis";
|
|
|
|
|
|
import Box from "@mui/material/Box";
|
|
|
|
|
|
import { limitNumber, limitFloat } from "../../libs/utils";
|
|
|
|
|
|
import ReusableAutocomplete from "./ReusableAutocomplete";
|
2025-09-25 23:08:39 +08:00
|
|
|
|
import ShowMoreButton from "./ShowMoreButton";
|
2023-09-06 00:25:46 +08:00
|
|
|
|
import {
|
2024-04-20 14:01:34 +08:00
|
|
|
|
OPT_TRANS_DEEPLX,
|
2024-04-28 21:43:20 +08:00
|
|
|
|
OPT_TRANS_OLLAMA,
|
2023-09-06 00:25:46 +08:00
|
|
|
|
OPT_TRANS_CUSTOMIZE,
|
2024-04-12 11:31:01 +08:00
|
|
|
|
OPT_TRANS_NIUTRANS,
|
2025-10-04 21:25:54 +08:00
|
|
|
|
OPT_TRANS_BUILTINAI,
|
2024-03-21 15:07:50 +08:00
|
|
|
|
DEFAULT_FETCH_LIMIT,
|
|
|
|
|
|
DEFAULT_FETCH_INTERVAL,
|
2025-07-01 12:38:06 +08:00
|
|
|
|
DEFAULT_HTTP_TIMEOUT,
|
2025-09-03 00:37:35 +08:00
|
|
|
|
DEFAULT_BATCH_INTERVAL,
|
|
|
|
|
|
DEFAULT_BATCH_SIZE,
|
|
|
|
|
|
DEFAULT_BATCH_LENGTH,
|
2025-09-03 20:43:07 +08:00
|
|
|
|
DEFAULT_CONTEXT_SIZE,
|
2025-09-24 23:24:00 +08:00
|
|
|
|
OPT_ALL_TYPES,
|
|
|
|
|
|
API_SPE_TYPES,
|
|
|
|
|
|
BUILTIN_STONES,
|
2025-10-01 13:22:22 +08:00
|
|
|
|
BUILTIN_PLACEHOLDERS,
|
|
|
|
|
|
BUILTIN_PLACETAGS,
|
2023-09-06 00:25:46 +08:00
|
|
|
|
} from "../../config";
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
function TestButton({ apiSlug, api }) {
|
2023-09-06 00:25:46 +08:00
|
|
|
|
const i18n = useI18n();
|
|
|
|
|
|
const alert = useAlert();
|
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const handleApiTest = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
const [text] = await apiTranslate({
|
2025-09-24 23:24:00 +08:00
|
|
|
|
apiSlug,
|
2023-09-06 14:57:02 +08:00
|
|
|
|
text: "hello world",
|
|
|
|
|
|
fromLang: "en",
|
2023-09-06 00:25:46 +08:00
|
|
|
|
toLang: "zh-CN",
|
2023-10-21 11:54:04 +08:00
|
|
|
|
apiSetting: api,
|
|
|
|
|
|
useCache: false,
|
2023-09-06 00:25:46 +08:00
|
|
|
|
});
|
|
|
|
|
|
if (!text) {
|
2025-07-01 17:03:52 +08:00
|
|
|
|
throw new Error("empty result");
|
2023-09-06 00:25:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
alert.success(i18n("test_success"));
|
|
|
|
|
|
} catch (err) {
|
2023-11-02 23:35:36 +08:00
|
|
|
|
// alert.error(`${i18n("test_failed")}: ${err.message}`);
|
2024-03-19 17:28:07 +08:00
|
|
|
|
let msg = err.message;
|
|
|
|
|
|
try {
|
|
|
|
|
|
msg = JSON.stringify(JSON.parse(err.message), null, 2);
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
// skip
|
|
|
|
|
|
}
|
2023-11-02 23:35:36 +08:00
|
|
|
|
alert.error(
|
|
|
|
|
|
<>
|
2024-03-19 17:28:07 +08:00
|
|
|
|
<div>{i18n("test_failed")}</div>
|
2024-04-12 11:31:01 +08:00
|
|
|
|
{msg === err.message ? (
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={{
|
|
|
|
|
|
maxWidth: 400,
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{msg}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<pre
|
|
|
|
|
|
style={{
|
|
|
|
|
|
maxWidth: 400,
|
|
|
|
|
|
overflow: "auto",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{msg}
|
|
|
|
|
|
</pre>
|
|
|
|
|
|
)}
|
2023-11-02 23:35:36 +08:00
|
|
|
|
</>
|
|
|
|
|
|
);
|
2023-09-06 00:25:46 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2024-04-16 16:39:11 +08:00
|
|
|
|
<LoadingButton
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
variant="outlined"
|
2024-04-16 16:39:11 +08:00
|
|
|
|
onClick={handleApiTest}
|
|
|
|
|
|
loading={loading}
|
|
|
|
|
|
>
|
2023-09-06 00:25:46 +08:00
|
|
|
|
{i18n("click_test")}
|
2024-04-16 16:39:11 +08:00
|
|
|
|
</LoadingButton>
|
2023-09-06 00:25:46 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|
|
|
|
|
const { api, update, reset } = useApiItem(apiSlug);
|
2023-09-06 00:25:46 +08:00
|
|
|
|
const i18n = useI18n();
|
2025-09-24 23:24:00 +08:00
|
|
|
|
const [formData, setFormData] = useState({});
|
|
|
|
|
|
const [isModified, setIsModified] = useState(false);
|
2025-09-25 23:08:39 +08:00
|
|
|
|
const [showMore, setShowMore] = useState(false);
|
2025-09-24 23:24:00 +08:00
|
|
|
|
const confirm = useConfirm();
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (api) {
|
|
|
|
|
|
setFormData(api);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [api]);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!api) return;
|
|
|
|
|
|
const hasChanged = JSON.stringify(api) !== JSON.stringify(formData);
|
|
|
|
|
|
setIsModified(hasChanged);
|
|
|
|
|
|
}, [api, formData]);
|
2023-09-06 00:25:46 +08:00
|
|
|
|
|
|
|
|
|
|
const handleChange = (e) => {
|
2025-09-24 23:24:00 +08:00
|
|
|
|
let { name, value, type, checked } = e.target;
|
|
|
|
|
|
|
|
|
|
|
|
if (type === "checkbox" || type === "switch") {
|
|
|
|
|
|
value = checked;
|
|
|
|
|
|
}
|
|
|
|
|
|
// if (value === "true") value = true;
|
|
|
|
|
|
// if (value === "false") value = false;
|
|
|
|
|
|
|
2024-03-21 15:07:50 +08:00
|
|
|
|
switch (name) {
|
|
|
|
|
|
case "fetchLimit":
|
|
|
|
|
|
value = limitNumber(value, 1, 100);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "fetchInterval":
|
|
|
|
|
|
value = limitNumber(value, 0, 5000);
|
|
|
|
|
|
break;
|
2025-07-01 12:38:06 +08:00
|
|
|
|
case "httpTimeout":
|
2025-09-03 20:43:07 +08:00
|
|
|
|
value = limitNumber(value, 5000, 60000);
|
2025-07-01 12:38:06 +08:00
|
|
|
|
break;
|
2024-05-21 23:15:46 +08:00
|
|
|
|
case "temperature":
|
|
|
|
|
|
value = limitFloat(value, 0, 2);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "maxTokens":
|
|
|
|
|
|
value = limitNumber(value, 0, 2 ** 15);
|
|
|
|
|
|
break;
|
2025-09-03 00:37:35 +08:00
|
|
|
|
case "batchInterval":
|
2025-09-03 12:16:41 +08:00
|
|
|
|
value = limitNumber(value, 100, 10000);
|
2025-09-03 00:37:35 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "batchSize":
|
|
|
|
|
|
value = limitNumber(value, 1, 100);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "batchLength":
|
2025-09-03 12:16:41 +08:00
|
|
|
|
value = limitNumber(value, 1000, 100000);
|
2025-09-03 00:37:35 +08:00
|
|
|
|
break;
|
2025-09-03 20:43:07 +08:00
|
|
|
|
case "contextSize":
|
|
|
|
|
|
value = limitNumber(value, 1, 20);
|
|
|
|
|
|
break;
|
2024-03-21 15:07:50 +08:00
|
|
|
|
default:
|
|
|
|
|
|
}
|
2025-09-24 23:24:00 +08:00
|
|
|
|
|
|
|
|
|
|
setFormData((prevData) => ({
|
|
|
|
|
|
...prevData,
|
2023-09-06 00:25:46 +08:00
|
|
|
|
[name]: value,
|
2025-09-24 23:24:00 +08:00
|
|
|
|
}));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleSave = () => {
|
|
|
|
|
|
// 过滤掉 api 对象中不存在的字段
|
|
|
|
|
|
// const updatedFields = Object.keys(formData).reduce((acc, key) => {
|
|
|
|
|
|
// if (api && Object.keys(api).includes(key)) {
|
|
|
|
|
|
// acc[key] = formData[key];
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return acc;
|
|
|
|
|
|
// }, {});
|
|
|
|
|
|
// update(updatedFields);
|
|
|
|
|
|
update(formData);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
|
reset();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleDelete = async () => {
|
|
|
|
|
|
const isConfirmed = await confirm({
|
|
|
|
|
|
confirmText: i18n("delete"),
|
|
|
|
|
|
cancelText: i18n("cancel"),
|
2023-09-06 00:25:46 +08:00
|
|
|
|
});
|
2025-09-24 23:24:00 +08:00
|
|
|
|
|
|
|
|
|
|
if (isConfirmed) {
|
|
|
|
|
|
deleteApi(apiSlug);
|
|
|
|
|
|
}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
const {
|
|
|
|
|
|
url = "",
|
|
|
|
|
|
key = "",
|
|
|
|
|
|
model = "",
|
|
|
|
|
|
apiType,
|
|
|
|
|
|
systemPrompt = "",
|
|
|
|
|
|
// userPrompt = "",
|
|
|
|
|
|
customHeader = "",
|
|
|
|
|
|
customBody = "",
|
|
|
|
|
|
think = false,
|
|
|
|
|
|
thinkIgnore = "",
|
|
|
|
|
|
fetchLimit = DEFAULT_FETCH_LIMIT,
|
|
|
|
|
|
fetchInterval = DEFAULT_FETCH_INTERVAL,
|
|
|
|
|
|
httpTimeout = DEFAULT_HTTP_TIMEOUT,
|
|
|
|
|
|
dictNo = "",
|
|
|
|
|
|
memoryNo = "",
|
|
|
|
|
|
reqHook = "",
|
|
|
|
|
|
resHook = "",
|
|
|
|
|
|
temperature = 0,
|
|
|
|
|
|
maxTokens = 256,
|
|
|
|
|
|
apiName = "",
|
|
|
|
|
|
isDisabled = false,
|
|
|
|
|
|
useBatchFetch = false,
|
|
|
|
|
|
batchInterval = DEFAULT_BATCH_INTERVAL,
|
|
|
|
|
|
batchSize = DEFAULT_BATCH_SIZE,
|
|
|
|
|
|
batchLength = DEFAULT_BATCH_LENGTH,
|
|
|
|
|
|
useContext = false,
|
|
|
|
|
|
contextSize = DEFAULT_CONTEXT_SIZE,
|
|
|
|
|
|
tone = "neutral",
|
2025-10-01 13:22:22 +08:00
|
|
|
|
placeholder = BUILTIN_PLACEHOLDERS[0],
|
|
|
|
|
|
placetag = BUILTIN_PLACETAGS[0],
|
2025-09-24 23:24:00 +08:00
|
|
|
|
// aiTerms = false,
|
|
|
|
|
|
} = formData;
|
|
|
|
|
|
|
|
|
|
|
|
const keyHelper = useMemo(
|
|
|
|
|
|
() => (API_SPE_TYPES.mulkeys.has(apiType) ? i18n("mulkeys_help") : ""),
|
|
|
|
|
|
[apiType, i18n]
|
|
|
|
|
|
);
|
2024-04-12 11:31:01 +08:00
|
|
|
|
|
2023-09-06 00:25:46 +08:00
|
|
|
|
return (
|
|
|
|
|
|
<Stack spacing={3}>
|
2025-07-01 10:54:30 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={i18n("api_name")}
|
|
|
|
|
|
name="apiName"
|
|
|
|
|
|
value={apiName}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
2025-10-04 21:25:54 +08:00
|
|
|
|
{!API_SPE_TYPES.machine.has(apiType) &&
|
|
|
|
|
|
apiType !== OPT_TRANS_BUILTINAI && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"URL"}
|
|
|
|
|
|
name="url"
|
|
|
|
|
|
value={url}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline={apiType === OPT_TRANS_DEEPLX}
|
|
|
|
|
|
maxRows={10}
|
|
|
|
|
|
helperText={
|
|
|
|
|
|
apiType === OPT_TRANS_DEEPLX ? i18n("mulkeys_help") : ""
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"KEY"}
|
|
|
|
|
|
name="key"
|
|
|
|
|
|
value={key}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline={API_SPE_TYPES.mulkeys.has(apiType)}
|
|
|
|
|
|
maxRows={10}
|
|
|
|
|
|
helperText={keyHelper}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
2024-03-21 15:07:50 +08:00
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{API_SPE_TYPES.ai.has(apiType) && (
|
2023-09-06 00:25:46 +08:00
|
|
|
|
<>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<Box>
|
|
|
|
|
|
<Grid container spacing={2} columns={12}>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{/* todo: 改成 ReusableAutocomplete 可选择和填写模型 */}
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={"MODEL"}
|
|
|
|
|
|
name="model"
|
|
|
|
|
|
value={model}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<ReusableAutocomplete
|
|
|
|
|
|
freeSolo
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
options={BUILTIN_STONES}
|
|
|
|
|
|
name="tone"
|
|
|
|
|
|
label={i18n("translation_style")}
|
|
|
|
|
|
value={tone}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={"Temperature"}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="temperature"
|
|
|
|
|
|
value={temperature}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={"Max Tokens"}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="maxTokens"
|
|
|
|
|
|
value={maxTokens}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}></Grid>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
2023-09-06 00:25:46 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2024-11-30 00:41:29 +08:00
|
|
|
|
label={"SYSTEM PROMPT"}
|
|
|
|
|
|
name="systemPrompt"
|
|
|
|
|
|
value={systemPrompt}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
2024-04-20 14:01:34 +08:00
|
|
|
|
maxRows={10}
|
2025-09-24 23:24:00 +08:00
|
|
|
|
helperText={i18n("system_prompt_helper")}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
/>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{/* <TextField
|
2024-09-30 16:41:58 +08:00
|
|
|
|
size="small"
|
2024-11-30 00:41:29 +08:00
|
|
|
|
label={"USER PROMPT"}
|
|
|
|
|
|
name="userPrompt"
|
|
|
|
|
|
value={userPrompt}
|
2024-09-30 16:41:58 +08:00
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
2025-09-24 23:24:00 +08:00
|
|
|
|
/> */}
|
2024-09-30 16:41:58 +08:00
|
|
|
|
</>
|
|
|
|
|
|
)}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{apiType === OPT_TRANS_OLLAMA && (
|
2025-05-01 23:41:08 +08:00
|
|
|
|
<>
|
2025-06-03 23:07:10 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
select
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
name="think"
|
|
|
|
|
|
value={think}
|
|
|
|
|
|
label={i18n("if_think")}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
>
|
|
|
|
|
|
<MenuItem value={false}>{i18n("nothink")}</MenuItem>
|
|
|
|
|
|
<MenuItem value={true}>{i18n("think")}</MenuItem>
|
|
|
|
|
|
</TextField>
|
2025-05-01 23:41:08 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={i18n("think_ignore")}
|
|
|
|
|
|
name="thinkIgnore"
|
|
|
|
|
|
value={thinkIgnore}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{apiType === OPT_TRANS_NIUTRANS && (
|
2024-04-12 11:31:01 +08:00
|
|
|
|
<>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"DictNo"}
|
|
|
|
|
|
name="dictNo"
|
|
|
|
|
|
value={dictNo}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"MemoryNo"}
|
|
|
|
|
|
name="memoryNo"
|
|
|
|
|
|
value={memoryNo}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{apiType === OPT_TRANS_CUSTOMIZE && (
|
2024-05-12 16:10:11 +08:00
|
|
|
|
<>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"Request Hook"}
|
|
|
|
|
|
name="reqHook"
|
|
|
|
|
|
value={reqHook}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
FormHelperTextProps={{
|
|
|
|
|
|
component: "div",
|
|
|
|
|
|
}}
|
|
|
|
|
|
helperText={
|
|
|
|
|
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
|
|
|
|
|
{i18n("request_hook_helper")}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
}
|
2024-05-12 16:10:11 +08:00
|
|
|
|
/>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"Response Hook"}
|
|
|
|
|
|
name="resHook"
|
|
|
|
|
|
value={resHook}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
FormHelperTextProps={{
|
|
|
|
|
|
component: "div",
|
|
|
|
|
|
}}
|
|
|
|
|
|
helperText={
|
|
|
|
|
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
|
|
|
|
|
{i18n("response_hook_helper")}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
}
|
2024-05-12 16:10:11 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</>
|
2024-04-17 17:38:54 +08:00
|
|
|
|
)}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{API_SPE_TYPES.batch.has(api.apiType) && (
|
|
|
|
|
|
<Box>
|
|
|
|
|
|
<Grid container spacing={2} columns={12}>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
select
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
name="useBatchFetch"
|
|
|
|
|
|
value={useBatchFetch}
|
|
|
|
|
|
label={i18n("use_batch_fetch")}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
>
|
|
|
|
|
|
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
|
|
|
|
|
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
|
|
|
|
|
</TextField>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-03 00:37:35 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
fullWidth
|
2025-09-03 00:37:35 +08:00
|
|
|
|
label={i18n("batch_interval")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="batchInterval"
|
|
|
|
|
|
value={batchInterval}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-03 00:37:35 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
fullWidth
|
2025-09-03 00:37:35 +08:00
|
|
|
|
label={i18n("batch_size")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="batchSize"
|
|
|
|
|
|
value={batchSize}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-03 00:37:35 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
fullWidth
|
2025-09-03 00:37:35 +08:00
|
|
|
|
label={i18n("batch_length")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="batchLength"
|
|
|
|
|
|
value={batchLength}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</Box>
|
2025-09-03 00:37:35 +08:00
|
|
|
|
)}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{API_SPE_TYPES.context.has(api.apiType) && (
|
2025-09-03 20:43:07 +08:00
|
|
|
|
<>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<Box>
|
|
|
|
|
|
<Grid container spacing={2} columns={12}>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{" "}
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
select
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
name="useContext"
|
|
|
|
|
|
value={useContext}
|
|
|
|
|
|
label={i18n("use_context")}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
>
|
|
|
|
|
|
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
|
|
|
|
|
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
|
|
|
|
|
</TextField>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{" "}
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={i18n("context_size")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="contextSize"
|
|
|
|
|
|
value={contextSize}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<Box>
|
|
|
|
|
|
<Grid container spacing={2} columns={12}>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-03 20:43:07 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
fullWidth
|
|
|
|
|
|
label={i18n("fetch_limit")}
|
2025-09-03 20:43:07 +08:00
|
|
|
|
type="number"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
name="fetchLimit"
|
|
|
|
|
|
value={fetchLimit}
|
2025-09-03 20:43:07 +08:00
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={i18n("fetch_interval")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="fetchInterval"
|
|
|
|
|
|
value={fetchInterval}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
label={i18n("http_timeout")}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="httpTimeout"
|
|
|
|
|
|
value={httpTimeout}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Grid>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}></Grid>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
</Grid>
|
|
|
|
|
|
</Box>
|
2025-07-01 10:54:30 +08:00
|
|
|
|
|
2025-09-25 23:08:39 +08:00
|
|
|
|
{showMore && (
|
|
|
|
|
|
<>
|
2025-10-01 13:22:22 +08:00
|
|
|
|
<Box>
|
|
|
|
|
|
<Grid container spacing={2} columns={12}>
|
|
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
select
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
name="placeholder"
|
|
|
|
|
|
value={placeholder}
|
|
|
|
|
|
label={i18n("api_placeholder")}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
>
|
|
|
|
|
|
{BUILTIN_PLACEHOLDERS.map((item) => (
|
|
|
|
|
|
<MenuItem key={item} value={item}>
|
|
|
|
|
|
{item}
|
|
|
|
|
|
</MenuItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</TextField>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
select
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
name="placetag"
|
|
|
|
|
|
value={placetag}
|
|
|
|
|
|
label={i18n("api_placetag")}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
>
|
|
|
|
|
|
{BUILTIN_PLACETAGS.map((item) => (
|
|
|
|
|
|
<MenuItem key={item} value={item}>
|
2025-10-01 15:35:20 +08:00
|
|
|
|
{`<${item}>`}
|
2025-10-01 13:22:22 +08:00
|
|
|
|
</MenuItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</TextField>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
2025-10-04 21:25:54 +08:00
|
|
|
|
{apiType !== OPT_TRANS_BUILTINAI && (
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<>
|
2025-10-04 21:25:54 +08:00
|
|
|
|
{" "}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-10-04 21:25:54 +08:00
|
|
|
|
label={i18n("custom_header")}
|
|
|
|
|
|
name="customHeader"
|
|
|
|
|
|
value={customHeader}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
2025-10-04 21:25:54 +08:00
|
|
|
|
helperText={i18n("custom_header_help")}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
/>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
2025-10-04 21:25:54 +08:00
|
|
|
|
label={i18n("custom_body")}
|
|
|
|
|
|
name="customBody"
|
|
|
|
|
|
value={customBody}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
2025-10-04 21:25:54 +08:00
|
|
|
|
helperText={i18n("custom_body_help")}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
2025-10-04 21:25:54 +08:00
|
|
|
|
|
|
|
|
|
|
{apiType !== OPT_TRANS_CUSTOMIZE &&
|
|
|
|
|
|
apiType !== OPT_TRANS_BUILTINAI && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"Request Hook"}
|
|
|
|
|
|
name="reqHook"
|
|
|
|
|
|
value={reqHook}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
|
|
|
|
|
FormHelperTextProps={{
|
|
|
|
|
|
component: "div",
|
|
|
|
|
|
}}
|
|
|
|
|
|
helperText={
|
|
|
|
|
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
|
|
|
|
|
{i18n("request_hook_helper")}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<TextField
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
label={"Response Hook"}
|
|
|
|
|
|
name="resHook"
|
|
|
|
|
|
value={resHook}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
maxRows={10}
|
|
|
|
|
|
FormHelperTextProps={{
|
|
|
|
|
|
component: "div",
|
|
|
|
|
|
}}
|
|
|
|
|
|
helperText={
|
|
|
|
|
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
|
|
|
|
|
{i18n("response_hook_helper")}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
2025-09-25 23:08:39 +08:00
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2025-09-25 11:31:12 +08:00
|
|
|
|
<Stack
|
|
|
|
|
|
direction="row"
|
|
|
|
|
|
alignItems="center"
|
|
|
|
|
|
spacing={2}
|
|
|
|
|
|
useFlexGap
|
|
|
|
|
|
flexWrap="wrap"
|
|
|
|
|
|
>
|
2024-03-21 15:07:50 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
size="small"
|
2025-09-24 23:24:00 +08:00
|
|
|
|
variant="contained"
|
|
|
|
|
|
onClick={handleSave}
|
|
|
|
|
|
disabled={!isModified}
|
2024-03-21 15:07:50 +08:00
|
|
|
|
>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{i18n("save")}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<TestButton apiSlug={apiSlug} api={api} />
|
|
|
|
|
|
<Button size="small" variant="outlined" onClick={handleReset}>
|
2024-03-21 15:07:50 +08:00
|
|
|
|
{i18n("restore_default")}
|
|
|
|
|
|
</Button>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{isUserApi && (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
variant="outlined"
|
|
|
|
|
|
color="error"
|
|
|
|
|
|
onClick={handleDelete}
|
|
|
|
|
|
>
|
|
|
|
|
|
{i18n("delete")}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<FormControlLabel
|
|
|
|
|
|
control={
|
|
|
|
|
|
<Switch
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
name="isDisabled"
|
|
|
|
|
|
checked={isDisabled}
|
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
}
|
|
|
|
|
|
label={i18n("is_disabled")}
|
|
|
|
|
|
/>
|
2025-09-25 23:08:39 +08:00
|
|
|
|
|
|
|
|
|
|
<ShowMoreButton showMore={showMore} onChange={setShowMore} />
|
2023-09-06 00:25:46 +08:00
|
|
|
|
</Stack>
|
2023-09-06 14:57:02 +08:00
|
|
|
|
|
2025-09-25 23:08:39 +08:00
|
|
|
|
{/* {apiType === OPT_TRANS_CUSTOMIZE && <pre>{i18n("custom_api_help")}</pre>} */}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
</Stack>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-24 23:24:00 +08:00
|
|
|
|
function ApiAccordion({ api, isUserApi, deleteApi }) {
|
2023-09-06 00:25:46 +08:00
|
|
|
|
const [expanded, setExpanded] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
const handleChange = (e) => {
|
|
|
|
|
|
setExpanded((pre) => !pre);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Accordion expanded={expanded} onChange={handleChange}>
|
|
|
|
|
|
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
2025-09-21 19:51:57 +08:00
|
|
|
|
<Typography
|
|
|
|
|
|
sx={{
|
|
|
|
|
|
opacity: api.isDisabled ? 0.5 : 1,
|
|
|
|
|
|
overflowWrap: "anywhere",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
{`[${api.apiType}] ${api.apiName}`}
|
2025-08-10 22:32:38 +08:00
|
|
|
|
</Typography>
|
2023-09-06 00:25:46 +08:00
|
|
|
|
</AccordionSummary>
|
|
|
|
|
|
<AccordionDetails>
|
2025-08-10 22:32:38 +08:00
|
|
|
|
{expanded && (
|
|
|
|
|
|
<ApiFields
|
2025-09-24 23:24:00 +08:00
|
|
|
|
apiSlug={api.apiSlug}
|
|
|
|
|
|
isUserApi={isUserApi}
|
|
|
|
|
|
deleteApi={deleteApi}
|
2025-08-10 22:32:38 +08:00
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2023-09-06 00:25:46 +08:00
|
|
|
|
</AccordionDetails>
|
|
|
|
|
|
</Accordion>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function Apis() {
|
2023-09-06 14:57:02 +08:00
|
|
|
|
const i18n = useI18n();
|
2025-09-24 23:24:00 +08:00
|
|
|
|
const { userApis, builtinApis, addApi, deleteApi } = useApiList();
|
|
|
|
|
|
|
|
|
|
|
|
const apiTypes = useMemo(
|
|
|
|
|
|
() =>
|
|
|
|
|
|
OPT_ALL_TYPES.map((type) => ({
|
|
|
|
|
|
type,
|
|
|
|
|
|
label: type,
|
|
|
|
|
|
})),
|
|
|
|
|
|
[]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
|
|
|
|
const open = Boolean(anchorEl);
|
|
|
|
|
|
|
|
|
|
|
|
const handleClick = (event) => {
|
|
|
|
|
|
setAnchorEl(event.currentTarget);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleClose = () => {
|
|
|
|
|
|
setAnchorEl(null);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMenuItemClick = (apiType) => {
|
|
|
|
|
|
addApi(apiType);
|
|
|
|
|
|
handleClose();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-09-06 14:57:02 +08:00
|
|
|
|
return (
|
|
|
|
|
|
<Box>
|
|
|
|
|
|
<Stack spacing={3}>
|
2025-10-04 21:25:54 +08:00
|
|
|
|
<Alert severity="info">
|
|
|
|
|
|
{i18n("about_api")}
|
|
|
|
|
|
<br />
|
|
|
|
|
|
{i18n("about_api_2")}
|
|
|
|
|
|
</Alert>
|
2023-09-06 14:57:02 +08:00
|
|
|
|
|
|
|
|
|
|
<Box>
|
2025-09-24 23:24:00 +08:00
|
|
|
|
<Button
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
id="add-api-button"
|
|
|
|
|
|
variant="contained"
|
|
|
|
|
|
onClick={handleClick}
|
|
|
|
|
|
aria-controls={open ? "add-api-menu" : undefined}
|
|
|
|
|
|
aria-haspopup="true"
|
|
|
|
|
|
aria-expanded={open ? "true" : undefined}
|
|
|
|
|
|
endIcon={<KeyboardArrowDownIcon />}
|
|
|
|
|
|
startIcon={<AddIcon />}
|
|
|
|
|
|
>
|
|
|
|
|
|
{i18n("add")}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Menu
|
|
|
|
|
|
id="add-api-menu"
|
|
|
|
|
|
anchorEl={anchorEl}
|
|
|
|
|
|
open={open}
|
|
|
|
|
|
onClose={handleClose}
|
|
|
|
|
|
MenuListProps={{
|
|
|
|
|
|
"aria-labelledby": "add-api-button",
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{apiTypes.map((apiOption) => (
|
|
|
|
|
|
<MenuItem
|
|
|
|
|
|
key={apiOption.type}
|
|
|
|
|
|
onClick={() => handleMenuItemClick(apiOption.type)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{apiOption.label}
|
|
|
|
|
|
</MenuItem>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</Menu>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
|
|
|
|
<Box>
|
|
|
|
|
|
{userApis.map((api) => (
|
|
|
|
|
|
<ApiAccordion
|
|
|
|
|
|
key={api.apiSlug}
|
|
|
|
|
|
api={api}
|
|
|
|
|
|
isUserApi={true}
|
|
|
|
|
|
deleteApi={deleteApi}
|
|
|
|
|
|
/>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
<Box>
|
|
|
|
|
|
{builtinApis.map((api) => (
|
|
|
|
|
|
<ApiAccordion key={api.apiSlug} api={api} />
|
2023-09-06 14:57:02 +08:00
|
|
|
|
))}
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
</Stack>
|
|
|
|
|
|
</Box>
|
|
|
|
|
|
);
|
2023-09-06 00:25:46 +08:00
|
|
|
|
}
|