refactor: style css -> tailwindcss

This commit is contained in:
tao.chen
2026-08-24 18:34:43 +08:00
parent 9ce0b106fa
commit 6b7701852f
9 changed files with 475 additions and 2142 deletions
+122 -52
View File
@@ -216,13 +216,16 @@ export function RunHistory({
};
return (
<section className="schedule-run-history">
<header>
<div>
<strong></strong>
<span>{runs.length}</span>
<section className="flex min-h-0 flex-col border-t border-[#e0e7ee] bg-[#fbfcfe]">
<header className="flex min-h-[44px] items-center justify-between border-b border-[#e8edf2] bg-white px-3">
<div className="flex items-center gap-[7px]">
<strong className="text-[12px] text-[#2b4056]"></strong>
<span className="inline-grid h-[18px] min-w-[18px] place-items-center rounded-[9px] bg-[#edf2f7] text-[9px] text-[#71849a]">
{runs.length}
</span>
</div>
<button
className="grid h-[27px] w-[27px] cursor-pointer place-items-center rounded-[5px] border border-[#dce5ee] bg-white text-[#66809a] disabled:cursor-not-allowed disabled:opacity-[0.45]"
type="button"
aria-label="刷新运行记录"
disabled={disabled || loading}
@@ -231,34 +234,50 @@ export function RunHistory({
<Icon name="refresh" size={13} />
</button>
</header>
<div className="schedule-run-list">
<div className="flex min-h-0 flex-1 flex-col gap-[7px] overflow-auto p-[9px]">
{loading && runs.length === 0 ? (
<p></p>
<p className="my-auto p-3 text-center text-[10px] leading-[1.6] text-[#929fac]">
</p>
) : runs.length === 0 ? (
<p></p>
<p className="my-auto p-3 text-center text-[10px] leading-[1.6] text-[#929fac]">
</p>
) : (
runs.map((run) => {
const expanded = expandedRunId === run.run_id;
const detail = runDetails[run.run_id];
return (
<article
className={`schedule-run-card${expanded ? " is-expanded" : ""}`}
data-state={expanded ? "expanded" : "collapsed"}
className="flex-none overflow-hidden rounded-[6px] border border-[#e1e8ef] bg-white data-[state=expanded]:border-[#b9d6f1] data-[state=expanded]:shadow-[0_3px_10px_rgb(38_117_185_/_8%)]"
key={run.run_id}
>
<div
className="schedule-run-summary"
className="grid w-full items-center gap-[7px] border-0 bg-white p-2 text-left text-inherit [grid-template-columns:8px_minmax(0,1fr)_auto_auto] hover:bg-[#f7fbff]"
>
<span className={`run-status-dot is-${run.run_status}`} />
<span className="schedule-run-summary-copy">
<strong>{RUN_STATUS_LABELS[run.run_status]}</strong>
<small>
<span
data-state={run.run_status}
className="mt-[3px] size-[7px] rounded-full bg-slate-400 data-[state=queued]:bg-warning data-[state=running]:bg-blue-500 data-[state=succeeded]:bg-emerald-500 data-[state=failed]:bg-red-500 data-[state=cancelled]:bg-red-500 data-[state=timed_out]:bg-red-500 data-[state=skipped]:bg-slate-400"
/>
<span className="flex min-w-0 flex-col gap-[2px]">
<strong className="text-[10px] text-[#425970]">
{RUN_STATUS_LABELS[run.run_status]}
</strong>
<small className="text-[8px] text-ink-subtle">
{formatTime(run.queued_at)} · {formatDuration(run.duration_ms)}
</small>
{run.error_message && <span>{run.error_message}</span>}
{run.error_message && (
<span className="truncate text-[8px] leading-[1.4] text-[#b65353]">
{run.error_message}
</span>
)}
</span>
<code title={run.run_id}>{run.run_id.slice(-8)}</code>
<code className="font-mono text-[8px] text-[#8b9bad]" title={run.run_id}>
{run.run_id.slice(-8)}
</code>
<button
className="schedule-run-result-button"
className="min-h-[27px] cursor-pointer whitespace-nowrap rounded-[5px] border border-[#bcd4e9] bg-[#f5faff] px-[9px] text-[9px] text-[#2374ba] [font-weight:650] hover:border-[#7eafe0] hover:bg-[#eaf5ff]"
type="button"
aria-haspopup="dialog"
onClick={() => toggleRun(run.run_id)}
@@ -270,25 +289,29 @@ export function RunHistory({
{expanded && (
<>
<button
className="schedule-run-result-backdrop"
className="fixed inset-0 z-[40] cursor-default border-0 bg-[rgb(10_27_45_/_46%)]"
type="button"
aria-label="关闭运行结果"
onClick={() => toggleRun(run.run_id)}
/>
<section
className="schedule-run-result-modal"
className="fixed left-1/2 top-1/2 z-[41] grid max-h-[min(760px,calc(100vh-64px))] w-[min(780px,calc(100vw-48px))] -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-[12px] border border-[#d8e2eb] bg-white shadow-[0_24px_80px_rgb(8_27_48_/_30%)] [grid-template-rows:auto_minmax(0,1fr)]"
role="dialog"
aria-modal="true"
aria-label="调度运行结果"
>
<header className="schedule-run-result-modal__header">
<div>
<span></span>
<strong>{RUN_STATUS_LABELS[run.run_status]}</strong>
<code>{run.run_id}</code>
<header className="flex items-center justify-between gap-[18px] border-b border-[#e3eaf0] bg-white p-[17px_20px]">
<div className="grid min-w-0 items-center gap-[5px_10px] [grid-template-columns:auto_auto]">
<span className="text-[17px] font-bold text-[#1f344a]"></span>
<strong className="justify-self-start rounded-[11px] bg-success-soft px-2 py-[3px] text-[10px] text-[#17805a]">
{RUN_STATUS_LABELS[run.run_status]}
</strong>
<code className="col-span-2 truncate font-mono text-[10px] text-[#8291a1]">
{run.run_id}
</code>
</div>
<button
className="icon-button"
className="grid h-[34px] w-[34px] cursor-pointer place-items-center rounded-[7px] border border-[#dfe6ed] bg-white hover:border-[#b9c9da] hover:bg-[#f7faff]"
type="button"
aria-label="关闭运行结果"
onClick={() => toggleRun(run.run_id)}
@@ -296,49 +319,90 @@ export function RunHistory({
<Icon name="close" size={16} />
</button>
</header>
<div className="schedule-run-detail">
<div className="min-h-0 overflow-auto bg-[#f8fbfe] p-[18px]">
{detailLoadingId === run.run_id && !detail ? (
<p className="run-detail-message"></p>
<p className="m-0 p-[8px_4px] text-center text-[9px] leading-[1.5] text-[#8796a6]">
</p>
) : detailErrors[run.run_id] ? (
<p className="run-detail-message is-error">
<p
data-state="error"
className="m-0 p-[8px_4px] text-center text-[9px] leading-[1.5] text-[#8796a6] data-[state=error]:text-[#bf5656]"
>
{detailErrors[run.run_id]}
</p>
) : detail ? (
<>
<dl className="schedule-run-meta">
<div><dt></dt><dd>{TRIGGER_TYPE_LABELS[detail.trigger_type]}</dd></div>
<div><dt></dt><dd>v{detail.workflow_version}</dd></div>
<div><dt></dt><dd>{formatTime(detail.started_at)}</dd></div>
<div><dt></dt><dd>{formatTime(detail.finished_at)}</dd></div>
<dl className="mb-[14px] grid gap-[10px_18px] [grid-template-columns:repeat(4,minmax(0,1fr))]">
<div className="min-w-0">
<dt className="mb-1 text-[10px] text-[#95a2af]"></dt>
<dd className="m-0 truncate text-[12px] text-[#41566c]">
{TRIGGER_TYPE_LABELS[detail.trigger_type]}
</dd>
</div>
<div className="min-w-0">
<dt className="mb-1 text-[10px] text-[#95a2af]"></dt>
<dd className="m-0 truncate text-[12px] text-[#41566c]">
v{detail.workflow_version}
</dd>
</div>
<div className="min-w-0">
<dt className="mb-1 text-[10px] text-[#95a2af]"></dt>
<dd className="m-0 truncate text-[12px] text-[#41566c]">
{formatTime(detail.started_at)}
</dd>
</div>
<div className="min-w-0">
<dt className="mb-1 text-[10px] text-[#95a2af]"></dt>
<dd className="m-0 truncate text-[12px] text-[#41566c]">
{formatTime(detail.finished_at)}
</dd>
</div>
</dl>
{(detail.error_code || detail.error_message) && (
<div className="schedule-run-error">
{detail.error_code && <code>{detail.error_code}</code>}
{detail.error_message && <p>{detail.error_message}</p>}
<div className="mb-2 rounded-[5px] border border-[#f0cece] bg-danger-soft p-[7px] text-danger-strong">
{detail.error_code && <code className="text-[8px] font-bold">{detail.error_code}</code>}
{detail.error_message && (
<p className="mt-[3px] text-[8px] leading-[1.45]">{detail.error_message}</p>
)}
</div>
)}
<div className="schedule-node-run-list">
<div className="flex flex-col gap-2.5">
{detail.node_runs.length === 0 ? (
<p className="run-detail-message"></p>
<p className="m-0 p-[8px_4px] text-center text-[9px] leading-[1.5] text-[#8796a6]">
</p>
) : detail.node_runs.map((nodeRun) => {
const node = nodes.find((item) => item.node_id === nodeRun.node_id);
const logState = logStates[nodeRun.node_run_id];
const logOpen = openLogNodeRunIds.has(nodeRun.node_run_id);
return (
<article className="schedule-node-run" key={nodeRun.node_run_id}>
<header>
<span className={`run-status-dot is-${nodeRun.node_status}`} />
<strong>{node?.node_name ?? nodeRun.node_id.slice(-8)}</strong>
<span>{NODE_STATUS_LABELS[nodeRun.node_status]}</span>
<article className="rounded-[7px] border border-[#dde7f0] bg-white p-3" key={nodeRun.node_run_id}>
<header className="grid items-start gap-1.5 [grid-template-columns:8px_minmax(0,1fr)_auto]">
<span
data-state={nodeRun.node_status}
className="mt-[3px] size-[7px] rounded-full bg-slate-400 data-[state=queued]:bg-warning data-[state=running]:bg-blue-500 data-[state=succeeded]:bg-emerald-500 data-[state=failed]:bg-red-500 data-[state=cancelled]:bg-red-500 data-[state=timed_out]:bg-red-500 data-[state=skipped]:bg-slate-400"
/>
<strong className="truncate text-[13px] text-[#40566c]">
{node?.node_name ?? nodeRun.node_id.slice(-8)}
</strong>
<span className="text-[10px] text-[#71869a]">
{NODE_STATUS_LABELS[nodeRun.node_status]}
</span>
</header>
<div className="schedule-node-run-meta">
<div className="ml-[14px] mt-[5px] flex flex-wrap gap-[3px_8px] text-[10px] text-[#8a98a7]">
<span> {nodeRun.attempt_no} </span>
<span>{formatDuration(nodeRun.duration_ms)}</span>
<span>退 {nodeRun.exit_code ?? "—"}</span>
</div>
{nodeRun.message && <p>{nodeRun.message}</p>}
<div className="schedule-node-run-actions">
{nodeRun.message && (
<p className="ml-[14px] mt-[5px] text-[10px] leading-[1.45] text-[#6c7e90]">
{nodeRun.message}
</p>
)}
<div className="ml-[14px] mt-[7px] flex gap-1.5">
<button
className="cursor-pointer rounded-[4px] border border-[#cbddeb] bg-[#f5faff] p-[6px_10px] text-[10px] text-[#2878bd] disabled:cursor-not-allowed disabled:opacity-[0.45]"
type="button"
disabled={!nodeRun.logs_object_id || logState?.loading}
onClick={() => void toggleLog(run.run_id, nodeRun.node_run_id)}
@@ -346,6 +410,7 @@ export function RunHistory({
{logState?.loading ? "读取中…" : logOpen ? "收起日志" : "查看日志"}
</button>
<button
className="cursor-pointer rounded-[4px] border border-[#cbddeb] bg-[#f5faff] p-[6px_10px] text-[10px] text-[#2878bd] disabled:cursor-not-allowed disabled:opacity-[0.45]"
type="button"
disabled={
!nodeRun.logs_object_id
@@ -358,6 +423,7 @@ export function RunHistory({
: "下载日志"}
</button>
<button
className="cursor-pointer rounded-[4px] border border-[#cbddeb] bg-[#f5faff] p-[6px_10px] text-[10px] text-[#2878bd] disabled:cursor-not-allowed disabled:opacity-[0.45]"
type="button"
disabled={
!nodeRun.result_object_id
@@ -371,24 +437,28 @@ export function RunHistory({
</button>
</div>
{artifactErrors[nodeRun.node_run_id] && (
<p className="schedule-artifact-error">
<p className="!text-[#b65353]">
{artifactErrors[nodeRun.node_run_id]}
</p>
)}
{logOpen && (
<div className="schedule-node-log">
<div className="ml-[14px] mt-[7px] overflow-hidden rounded-[4px] border border-slate-700 bg-bg-log">
{logState?.fileName && (
<header>
<header className="flex items-center justify-between border-b border-slate-700 bg-bg-log p-[5px_7px] text-[10px] text-slate-300">
<span>{logState.fileName}</span>
<small>
<small className="text-[#8292a1]">
{formatSize(new TextEncoder().encode(logState.content ?? "").length)}
</small>
</header>
)}
{logState?.error ? (
<p>{logState.error}</p>
<p className="m-0 max-h-[260px] overflow-auto p-[11px] font-mono text-[11px] leading-relaxed whitespace-pre-wrap break-words text-slate-200">
{logState.error}
</p>
) : (
<pre>{logState?.content ?? "正在读取日志…"}</pre>
<pre className="m-0 max-h-[260px] overflow-auto p-[11px] font-mono text-[11px] leading-relaxed whitespace-pre-wrap break-words text-slate-200">
{logState?.content ?? "正在读取日志…"}
</pre>
)}
</div>
)}