Merge remote-tracking branch 'origin/ji' into ji

This commit is contained in:
吉鑫升 committed 2026-06-04 16:59:05 +08:00
commit 6c30e649e3
6 files changed
+420 -74

No files matched your search

@@ -3,14 +3,18 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
Check,
ChevronLeft,
ChevronRight,
Download,
FileText,
List,
Loader2,
Pencil,
Trash2,
X,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { PointerEvent as ReactPointerEvent } from "react";
import { useParams } from "react-router-dom";
import { toast } from "sonner";
@@ -253,6 +257,10 @@ function stripTimestampSuffix(title: string): string {
}
const BODY_TAB_VALUE = "__body__";
const RUN_LIST_COLLAPSED_WIDTH = 56;
const RUN_LIST_DEFAULT_WIDTH = 380;
const RUN_LIST_MIN_WIDTH = 280;
const RUN_LIST_MAX_WIDTH = 560;
/**
* Public, unauthenticated scheduled-task viewer.
@@ -269,6 +277,9 @@ export default function PublicScheduledTaskPage() {
const { taskId } = useParams<{ taskId: string }>();
const [selectedRunId, setSelectedRunId] = useState<string | null>(null);
const [pendingDeleteRun, setPendingDeleteRun] = useState<{ id: string; title: string } | null>(null);
const [runListExpanded, setRunListExpanded] = useState(false);
const [runListWidth, setRunListWidth] = useState(RUN_LIST_DEFAULT_WIDTH);
const dragStateRef = useRef<{ startX: number; startWidth: number } | null>(null);
const queryClient = useQueryClient();
const { data, isLoading, isError, error } = useQuery({
@@ -332,6 +343,58 @@ export default function PublicScheduledTaskPage() {
}
}, [runs, selectedRunId]);
const task = data?.task;
const visibleRunListWidth = runListExpanded ? runListWidth : RUN_LIST_COLLAPSED_WIDTH;
const expandRunList = useCallback(() => {
setRunListExpanded(true);
setRunListWidth((width) =>
Math.min(RUN_LIST_MAX_WIDTH, Math.max(RUN_LIST_MIN_WIDTH, width)),
);
}, []);
const collapseRunList = useCallback(() => {
setRunListExpanded(false);
}, []);
const handleRunListDragStart = useCallback(
(event: ReactPointerEvent<HTMLDivElement>) => {
event.preventDefault();
dragStateRef.current = {
startX: event.clientX,
startWidth: visibleRunListWidth,
};
document.body.style.cursor = "col-resize";
document.body.style.userSelect = "none";
const handlePointerMove = (moveEvent: PointerEvent) => {
const drag = dragStateRef.current;
if (!drag) return;
const nextWidth = drag.startWidth + moveEvent.clientX - drag.startX;
if (nextWidth <= RUN_LIST_COLLAPSED_WIDTH + 28) {
setRunListExpanded(false);
return;
}
setRunListExpanded(true);
setRunListWidth(
Math.min(RUN_LIST_MAX_WIDTH, Math.max(RUN_LIST_MIN_WIDTH, nextWidth)),
);
};
const handlePointerUp = () => {
dragStateRef.current = null;
document.body.style.cursor = "";
document.body.style.userSelect = "";
window.removeEventListener("pointermove", handlePointerMove);
window.removeEventListener("pointerup", handlePointerUp);
};
window.addEventListener("pointermove", handlePointerMove);
window.addEventListener("pointerup", handlePointerUp);
},
[visibleRunListWidth],
);
if (!taskId) {
return (
<div className="text-muted-foreground flex h-screen items-center justify-center text-sm">
@@ -357,12 +420,19 @@ export default function PublicScheduledTaskPage() {
);
}
const task = data?.task;
return (
<TooltipProvider delayDuration={150}>
<div className="bg-muted/20 grid h-screen min-h-0 grid-cols-1 gap-4 p-4 xl:grid-cols-[380px_minmax(0,1fr)]">
<Card className="flex min-h-0 flex-col">
<div className="bg-muted/20 flex h-screen min-h-0 overflow-hidden p-4">
<div
className="relative flex min-h-0 shrink-0 transition-[width] duration-200 ease-out"
style={{ width: visibleRunListWidth }}
>
<Card
className={cn(
"flex min-h-0 w-full flex-col overflow-hidden",
!runListExpanded && "pointer-events-none [&>*]:invisible",
)}
>
<CardHeader className="gap-1">
<div className="flex items-start justify-between gap-2">
<Tooltip>
@@ -481,9 +551,31 @@ export default function PublicScheduledTaskPage() {
</div>
</ScrollArea>
</CardContent>
</Card>
</Card>
<button
type="button"
onClick={runListExpanded ? collapseRunList : expandRunList}
className="bg-background text-muted-foreground hover:bg-accent hover:text-primary focus-visible:ring-ring absolute top-3 left-1/2 z-30 flex size-9 -translate-x-1/2 items-center justify-center rounded-md border shadow-sm transition-colors focus:outline-none focus-visible:ring-2"
title={runListExpanded ? "收起执行记录列表" : "展开执行记录列表"}
aria-label={runListExpanded ? "收起执行记录列表" : "展开执行记录列表"}
>
{runListExpanded ? <ChevronLeft className="size-4" /> : <List className="size-4" />}
</button>
<div
role="separator"
aria-orientation="vertical"
title="拖拽调整列表宽度"
className="group absolute top-0 -right-3 z-20 flex h-full w-6 cursor-col-resize items-center justify-center"
onPointerDown={handleRunListDragStart}
>
<div className="bg-border group-hover:bg-primary/70 h-full w-px transition-colors" />
<div className="bg-background text-muted-foreground group-hover:text-primary absolute top-1/2 flex size-5 -translate-y-1/2 items-center justify-center rounded-full border shadow-sm transition-colors">
<ChevronRight className="size-3" />
</div>
</div>
</div>
<Card className="flex min-h-0 flex-col">
<Card className="ml-4 flex min-h-0 flex-1 flex-col">
{selectedRun ? (
<RunDetailPane key={selectedRun.id} run={selectedRun} taskId={taskId} />
) : (