feat: auth

This commit is contained in:
tao.chen
2026-07-31 17:22:25 +08:00
parent 1994937349
commit fb073c6f99
24 changed files with 1177 additions and 742 deletions
@@ -1,8 +1,8 @@
import {
DragEvent,
FormEvent,
MouseEvent as ReactMouseEvent,
PointerEvent as ReactPointerEvent,
type DragEvent,
type FormEvent,
type MouseEvent as ReactMouseEvent,
type PointerEvent as ReactPointerEvent,
useEffect,
useMemo,
useRef,
@@ -11,22 +11,6 @@ import {
import {
ApiRequestError,
createSchedule,
createScheduleEdge,
createScheduleNode,
deleteSchedule,
deleteScheduleEdge,
deleteScheduleNode,
hideScheduleArtifact,
getSchedule,
listScheduleArtifacts,
listScheduleRuns,
listSchedules,
previewCron,
runScheduleNow,
updateSchedule,
updateScheduleNode,
validateSchedule,
type CronPreview,
type Schedule,
type ScheduleArtifact,
@@ -34,6 +18,8 @@ import {
type ScheduleNode,
type ScheduleRunSummary,
} from "../../services/api";
import { useApi } from "~/context/AuthContext";
import Icon from "../../components/Icon";
import "../../styles/schedule.css";
@@ -250,6 +236,7 @@ export default function SchedulePage({
const dragRef = useRef<DragState | null>(null);
const positionDraftsRef = useRef<Record<string, NodePositionDraft>>({});
const [positionDraftCount, setPositionDraftCount] = useState(0);
const api = useApi();
const selectedNode = schedule?.nodes.find(
(item) => item.node_id === selectedNodeId,
@@ -328,7 +315,7 @@ export default function SchedulePage({
): Promise<void> => {
if (showLoading) setRunsLoading(true);
try {
const items = await listScheduleRuns({
const items = await api.listScheduleRuns({
scheduleId,
limit: 20,
});
@@ -349,8 +336,8 @@ export default function SchedulePage({
preferredScheduleId?: string | null,
): Promise<void> => {
const [scheduleItems, artifactItems] = await Promise.all([
listSchedules(),
listScheduleArtifacts(),
api.listSchedules(),
api.listScheduleArtifacts(),
]);
setSchedules(scheduleItems);
setArtifacts(artifactItems);
@@ -362,20 +349,20 @@ export default function SchedulePage({
setSchedule(null);
return;
}
const detail = await getSchedule(targetId);
const detail = await api.getSchedule(targetId);
setSchedule(applyPositionDrafts(detail));
};
useEffect(() => {
let cancelled = false;
setLoading(true);
Promise.all([listSchedules(), listScheduleArtifacts()])
Promise.all([api.listSchedules(), api.listScheduleArtifacts()])
.then(async ([scheduleItems, artifactItems]) => {
if (cancelled) return;
setSchedules(scheduleItems);
setArtifacts(artifactItems);
if (scheduleItems[0]) {
const detail = await getSchedule(scheduleItems[0].schedule_id);
const detail = await api.getSchedule(scheduleItems[0].schedule_id);
if (!cancelled) setSchedule(applyPositionDrafts(detail));
}
onConnectionChange(true);
@@ -404,7 +391,7 @@ export default function SchedulePage({
}
let cancelled = false;
setRunsLoading(true);
listScheduleRuns({ scheduleId, limit: 20 })
api.listScheduleRuns({ scheduleId, limit: 20 })
.then((items) => {
if (!cancelled) setRuns(items);
})
@@ -507,7 +494,7 @@ export default function SchedulePage({
setLinkSourceId(null);
setCronResult(null);
try {
setSchedule(await getSchedule(scheduleId));
setSchedule(await api.getSchedule(scheduleId));
onConnectionChange(true);
} catch (error) {
await handleError(error, "调度详情加载失败");
@@ -529,7 +516,7 @@ export default function SchedulePage({
if (busy || !scheduleName) return;
setBusy("create-schedule");
try {
const created = await createSchedule({
const created = await api.createSchedule({
schedule_name: scheduleName,
description: "在画布中拖入稳定版本并配置执行顺序",
trigger_type: "manual",
@@ -557,7 +544,7 @@ export default function SchedulePage({
if (!window.confirm(`确定删除调度“${selectedSchedule.schedule_name}”吗?`)) return;
setBusy("delete-schedule");
try {
await deleteSchedule(
await api.deleteSchedule(
selectedSchedule.schedule_id,
selectedSchedule.workflow_version,
);
@@ -571,7 +558,7 @@ export default function SchedulePage({
setSelectedNodeId(null);
setSelectedEdgeId(null);
if (remaining[0]) {
setSchedule(await getSchedule(remaining[0].schedule_id));
setSchedule(await api.getSchedule(remaining[0].schedule_id));
}
}
onNotify({ tone: "success", message: "调度方案已删除" });
@@ -589,7 +576,7 @@ export default function SchedulePage({
if (!scheduleName || scheduleName === target.schedule_name) return;
setBusy("rename-schedule");
try {
const updated = await updateSchedule(target.schedule_id, {
const updated = await api.updateSchedule(target.schedule_id, {
workflow_version: target.workflow_version,
schedule_name: scheduleName,
});
@@ -620,7 +607,7 @@ export default function SchedulePage({
) return;
setBusy("delete-artifact");
try {
await hideScheduleArtifact(artifact.versions_id);
await api.hideScheduleArtifact(artifact.versions_id);
setArtifacts((current) => current.filter(
(item) => item.versions_id !== artifact.versions_id,
));
@@ -652,13 +639,13 @@ export default function SchedulePage({
for (const [nodeId, position] of Object.entries(
positionDraftsRef.current,
)) {
updated = await updateScheduleNode(updated.schedule_id, nodeId, {
updated = await api.updateScheduleNode(updated.schedule_id, nodeId, {
workflow_version: updated.workflow_version,
position_x: position.position_x,
position_y: position.position_y,
});
}
updated = await updateSchedule(updated.schedule_id, {
updated = await api.updateSchedule(updated.schedule_id, {
workflow_version: updated.workflow_version,
schedule_name: scheduleForm.scheduleName.trim(),
description: scheduleForm.description.trim() || null,
@@ -694,7 +681,7 @@ export default function SchedulePage({
if (busy) return;
setBusy("cron-preview");
try {
const result = await previewCron({
const result = await api.previewCron({
cron_expression: scheduleForm.cronExpression.trim(),
timezone: scheduleForm.timezone.trim(),
count: 5,
@@ -727,7 +714,7 @@ export default function SchedulePage({
}
setBusy("run-now");
try {
const created = await runScheduleNow(schedule.schedule_id);
const created = await api.runScheduleNow(schedule.schedule_id);
setRuns((current) => [
created,
...current.filter((item) => item.run_id !== created.run_id),
@@ -763,7 +750,7 @@ export default function SchedulePage({
const nodeKey = artifactNodeKey(artifact, schedule);
const updated = await withMutation(
"add-node",
() => createScheduleNode(schedule.schedule_id, {
() => api.createScheduleNode(schedule.schedule_id, {
workflow_version: schedule.workflow_version,
node_key: nodeKey,
node_name: artifact.script_name,
@@ -898,7 +885,7 @@ export default function SchedulePage({
setLinkSourceId(null);
await withMutation(
"create-edge",
() => createScheduleEdge(schedule.schedule_id, {
() => api.createScheduleEdge(schedule.schedule_id, {
workflow_version: schedule.workflow_version,
source_node_id: sourceId,
target_node_id: targetNodeId,
@@ -935,7 +922,7 @@ export default function SchedulePage({
);
await withMutation(
"save-node",
() => updateScheduleNode(schedule.schedule_id, selectedNode.node_id, {
() => api.updateScheduleNode(schedule.schedule_id, selectedNode.node_id, {
workflow_version: schedule.workflow_version,
node_name: nodeForm.nodeName.trim(),
timeout_seconds: timeoutSeconds,
@@ -958,7 +945,7 @@ export default function SchedulePage({
if (!window.confirm(`确定删除节点“${node.node_name}”吗?`)) return;
const updated = await withMutation(
"delete-node",
() => deleteScheduleNode(
() => api.deleteScheduleNode(
schedule.schedule_id,
node.node_id,
schedule.workflow_version,
@@ -974,7 +961,7 @@ export default function SchedulePage({
setContextMenu(null);
const updated = await withMutation(
"delete-edge",
() => deleteScheduleEdge(
() => api.deleteScheduleEdge(
schedule.schedule_id,
edge.edge_id,
schedule.workflow_version,
@@ -988,7 +975,7 @@ export default function SchedulePage({
if (!schedule || busy) return;
setBusy("validate");
try {
const result = await validateSchedule(schedule.schedule_id);
const result = await api.validateSchedule(schedule.schedule_id);
setSchedule((current) => current
? { ...current, dag_validation: result }
: current);