import React, { useState } from "react";
|
import {
|
FormDataConsumer,
|
NumberInput,
|
SelectInput,
|
TextInput,
|
useNotify,
|
useTranslate,
|
} from "react-admin";
|
import { Alert, Button, Grid, Stack, Typography } from "@mui/material";
|
import StatusSelectInput from "@/page/components/StatusSelectInput";
|
import { validateDraftMcpConnectivity } from "@/api/ai/mcpMount";
|
|
const transportChoices = [
|
{ id: "SSE_HTTP", name: "SSE_HTTP" },
|
{ id: "STDIO", name: "STDIO" },
|
{ id: "BUILTIN", name: "BUILTIN" },
|
];
|
|
const AiMcpDraftTestSection = ({ formData, readOnly }) => {
|
const notify = useNotify();
|
const translate = useTranslate();
|
const [loading, setLoading] = useState(false);
|
const [result, setResult] = useState(null);
|
|
const handleValidate = async () => {
|
setLoading(true);
|
try {
|
const data = await validateDraftMcpConnectivity(formData);
|
setResult(data);
|
notify(data?.message || translate("ai.mcp.connectivity.success"));
|
} catch (error) {
|
const nextResult = {
|
healthStatus: "UNHEALTHY",
|
message: error?.message || translate("ai.mcp.connectivity.failed"),
|
};
|
setResult(nextResult);
|
notify(nextResult.message, { type: "error" });
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
if (readOnly) {
|
return null;
|
}
|
|
return (
|
<>
|
<Grid item xs={12}>
|
<Stack direction="row" spacing={1} alignItems="center">
|
<Button variant="outlined" onClick={handleValidate} disabled={loading}>
|
{loading ? translate("ai.common.testing") : translate("ai.mcp.form.testBeforeSave")}
|
</Button>
|
<Typography variant="body2" color="text.secondary">
|
{translate("ai.mcp.form.testDescription")}
|
</Typography>
|
</Stack>
|
</Grid>
|
{result && (
|
<Grid item xs={12}>
|
<Alert severity={result.healthStatus === "HEALTHY" ? "success" : "error"}>
|
{result.message}
|
{result.initElapsedMs ? ` · ${result.initElapsedMs} ms` : ""}
|
{result.testedAt ? ` · ${result.testedAt}` : ""}
|
</Alert>
|
</Grid>
|
)}
|
</>
|
);
|
};
|
|
const AiMcpMountForm = ({ readOnly = false }) => {
|
const translate = useTranslate();
|
|
return (
|
<Grid container spacing={2} width={{ xs: "100%", xl: "80%" }}>
|
<Grid item xs={12}>
|
<Typography variant="h6">{translate("ai.mcp.form.sections.main")}</Typography>
|
</Grid>
|
<Grid item xs={12} md={6}>
|
<TextInput source="name" label="common.field.name" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12} md={6}>
|
<SelectInput source="transportType" label="ai.mcp.fields.transportType" choices={transportChoices} fullWidth disabled={readOnly} />
|
</Grid>
|
<FormDataConsumer>
|
{({ formData }) => (
|
<>
|
{formData.transportType === "BUILTIN" && (
|
<>
|
<Grid item xs={12}>
|
<SelectInput
|
source="builtinCode"
|
label="ai.mcp.fields.builtinCode"
|
choices={[
|
{ id: "RSF_WMS", name: "RSF_WMS" },
|
]}
|
fullWidth
|
disabled={readOnly}
|
/>
|
</Grid>
|
</>
|
)}
|
{formData.transportType === "SSE_HTTP" && (
|
<>
|
<Grid item xs={12}>
|
<TextInput source="serverUrl" label="ai.mcp.fields.serverUrl" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="endpoint" label="SSE Endpoint" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="headersJson" label="Headers JSON" fullWidth multiline minRows={4} disabled={readOnly} />
|
</Grid>
|
</>
|
)}
|
{formData.transportType === "STDIO" && (
|
<>
|
<Grid item xs={12}>
|
<TextInput source="command" label="ai.mcp.fields.command" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="argsJson" label="Args JSON" fullWidth multiline minRows={4} disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="envJson" label="Env JSON" fullWidth multiline minRows={4} disabled={readOnly} />
|
</Grid>
|
</>
|
)}
|
</>
|
)}
|
</FormDataConsumer>
|
<Grid item xs={12} md={4}>
|
<NumberInput source="requestTimeoutMs" label="Timeout(ms)" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12} md={4}>
|
<NumberInput source="sort" label="ai.mcp.fields.sort" fullWidth disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12} md={4}>
|
<StatusSelectInput disabled={readOnly} />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="memo" label="common.field.memo" fullWidth multiline minRows={3} disabled={readOnly} />
|
</Grid>
|
<FormDataConsumer>
|
{({ formData }) => <AiMcpDraftTestSection formData={formData} readOnly={readOnly} />}
|
</FormDataConsumer>
|
<Grid item xs={12}>
|
<Typography variant="h6">{translate("ai.mcp.form.sections.runtime")}</Typography>
|
</Grid>
|
<Grid item xs={12} md={4}>
|
<TextInput source="healthStatus" label="ai.mcp.fields.healthStatus" fullWidth disabled />
|
</Grid>
|
<Grid item xs={12} md={4}>
|
<TextInput source="lastInitElapsedMs" label="ai.mcp.fields.lastInitElapsedMs" fullWidth disabled />
|
</Grid>
|
<Grid item xs={12} md={4}>
|
<TextInput source="lastTestTime$" label="ai.mcp.fields.lastTestTime" fullWidth disabled />
|
</Grid>
|
<Grid item xs={12}>
|
<TextInput source="lastTestMessage" label="ai.mcp.fields.lastTestMessage" fullWidth multiline minRows={3} disabled />
|
</Grid>
|
<Grid item xs={12} md={6}>
|
<TextInput source="updateBy" label="ai.common.lastUpdatedBy" fullWidth disabled />
|
</Grid>
|
<Grid item xs={12} md={6}>
|
<TextInput source="updateTime$" label="ai.common.lastUpdatedAt" fullWidth disabled />
|
</Grid>
|
</Grid>
|
);
|
};
|
|
export default AiMcpMountForm;
|