ci fixes: cargo fmt, eslint entities, max-lines split
CI on 6ffbe97 failed on two auto-fixable gates. Both fixed:
* cargo fmt --all — rustfmt applied across the surface touched
by the last ~20 commits (world.rs, security_scan.rs,
routes/{missions,nodes,terminal}.rs, fleet_herdr.rs,
mission_workspace.rs, benchmark_runner.rs, mission_refiner.rs,
lib.rs, tests/mission_orchestrator.rs, cm-db/repo/{missions,teams}.rs,
bins/clawmates-node/src/main.rs)
* eslint apostrophe escapes in HerdrSessions + MissionWizard
* eslint max-lines: extracted EditMissionModal + RefineDiffModal
(each ~200 LoC) into their own files. MissionCanvas drops from
1424 to 1026, comfortably under both the 1250 eslint cap and the
1500 CI budget.
New files:
frontend/src/components/dashboard/EditMissionModal.tsx (211 LoC)
frontend/src/components/dashboard/RefineDiffModal.tsx (208 LoC)
Verified locally: cargo fmt --check clean, cargo check clean,
mission_orchestrator test 3/3 pass, tsc + eslint --quiet both silent.
This commit is contained in:
@@ -19,7 +19,6 @@ import {
|
||||
setMissionStatus,
|
||||
triggerBenchmark,
|
||||
triggerSecurityScan,
|
||||
updateMission,
|
||||
type MissionDetail,
|
||||
type MissionStatus,
|
||||
type PhaseKind,
|
||||
@@ -28,9 +27,11 @@ import {
|
||||
type TaskStatus,
|
||||
type TemplateKind,
|
||||
} from "@/lib/api/missions";
|
||||
import { EditMissionModal } from "./EditMissionModal";
|
||||
import { MarkdownBlock } from "./MarkdownBlock";
|
||||
import { MissionLivePane } from "./MissionLivePane";
|
||||
import { MissionWizard } from "./MissionWizard";
|
||||
import { RefineDiffModal } from "./RefineDiffModal";
|
||||
|
||||
const mono =
|
||||
"ui-monospace, SFMono-Regular, SF Mono, Menlo, Monaco, Consolas, monospace";
|
||||
@@ -988,405 +989,6 @@ function Empty({ label }: { label: string }) {
|
||||
}
|
||||
|
||||
|
||||
function EditMissionModal({
|
||||
mission,
|
||||
onClose,
|
||||
onSaved,
|
||||
}: {
|
||||
mission: MissionDetail;
|
||||
onClose: () => void;
|
||||
onSaved: () => void;
|
||||
}) {
|
||||
const [title, setTitle] = useState(mission.title);
|
||||
const [description, setDescription] = useState(mission.description ?? "");
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const dirty =
|
||||
title.trim() !== mission.title || description !== (mission.description ?? "");
|
||||
const save = async () => {
|
||||
if (!dirty) {
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
if (!title.trim()) {
|
||||
setError("title is required");
|
||||
return;
|
||||
}
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
await updateMission(mission.id, {
|
||||
title: title.trim() !== mission.title ? title.trim() : undefined,
|
||||
description:
|
||||
description !== (mission.description ?? "") ? description : undefined,
|
||||
});
|
||||
onSaved();
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "save failed");
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal
|
||||
onClick={onClose}
|
||||
style={{
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
background: "rgba(0,0,0,.55)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 900,
|
||||
padding: 24,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{
|
||||
width: "min(620px, 100%)",
|
||||
background: "#141419",
|
||||
borderRadius: 12,
|
||||
border: "1px solid rgba(255,255,255,.08)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "12px 18px",
|
||||
borderBottom: "1px solid rgba(255,255,255,.06)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: mono,
|
||||
fontSize: 10.5,
|
||||
letterSpacing: ".14em",
|
||||
color: "#7cd6e0",
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
Edit mission
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ padding: 18, display: "flex", flexDirection: "column", gap: 12 }}>
|
||||
<label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: mono,
|
||||
fontSize: 10,
|
||||
letterSpacing: ".12em",
|
||||
color: "#a0a0a8",
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
Title
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
disabled={busy}
|
||||
autoFocus
|
||||
style={{
|
||||
padding: "8px 12px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(255,255,255,.1)",
|
||||
background: "#0a0a0d",
|
||||
color: "#f3f3f5",
|
||||
fontSize: 14,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
<label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: mono,
|
||||
fontSize: 10,
|
||||
letterSpacing: ".12em",
|
||||
color: "#a0a0a8",
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
Description (Markdown; use Refine to structure)
|
||||
</span>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
disabled={busy}
|
||||
rows={12}
|
||||
style={{
|
||||
padding: "8px 12px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(255,255,255,.1)",
|
||||
background: "#0a0a0d",
|
||||
color: "#f3f3f5",
|
||||
fontFamily: mono,
|
||||
fontSize: 12,
|
||||
resize: "vertical",
|
||||
minHeight: 160,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
{error && (
|
||||
<div style={{ color: "#ff8a7a", fontSize: 12 }}>{error}</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
padding: "12px 18px",
|
||||
borderTop: "1px solid rgba(255,255,255,.06)",
|
||||
display: "flex",
|
||||
gap: 8,
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
disabled={busy}
|
||||
style={{
|
||||
padding: "6px 14px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(255,255,255,.1)",
|
||||
background: "transparent",
|
||||
color: "#a0a0a8",
|
||||
fontSize: 12,
|
||||
cursor: "pointer",
|
||||
opacity: busy ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={save}
|
||||
disabled={busy || !dirty}
|
||||
style={{
|
||||
padding: "6px 14px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(127,208,160,.5)",
|
||||
background: "rgba(127,208,160,.12)",
|
||||
color: "#7fd0a0",
|
||||
fontSize: 12,
|
||||
cursor: dirty ? "pointer" : "not-allowed",
|
||||
opacity: busy || !dirty ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
{busy ? "Saving…" : "Save"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RefineDiffModal({
|
||||
original,
|
||||
refined,
|
||||
busy,
|
||||
onAccept,
|
||||
onCancel,
|
||||
onUndoAfterAccept,
|
||||
}: {
|
||||
original: string;
|
||||
refined: string;
|
||||
busy: boolean;
|
||||
onAccept: () => void;
|
||||
onCancel: () => void;
|
||||
onUndoAfterAccept: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal
|
||||
onClick={onCancel}
|
||||
style={{
|
||||
position: "fixed",
|
||||
inset: 0,
|
||||
background: "rgba(0,0,0,.6)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 900,
|
||||
padding: 24,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{
|
||||
width: "min(1100px, 100%)",
|
||||
height: "min(720px, calc(100vh - 48px))",
|
||||
background: "#141419",
|
||||
borderRadius: 12,
|
||||
border: "1px solid rgba(255,255,255,.08)",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "12px 18px",
|
||||
borderBottom: "1px solid rgba(255,255,255,.06)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontFamily: mono,
|
||||
fontSize: 10.5,
|
||||
letterSpacing: ".14em",
|
||||
color: "#ffb44a",
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
Refine — review before/after
|
||||
</span>
|
||||
<span style={{ flex: 1 }} />
|
||||
<button
|
||||
type="button"
|
||||
onClick={onUndoAfterAccept}
|
||||
disabled={busy}
|
||||
title="Restore the original description (drops the refinement)"
|
||||
style={{
|
||||
padding: "5px 12px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(255,255,255,.1)",
|
||||
background: "transparent",
|
||||
color: "#a0a0a8",
|
||||
fontSize: 12,
|
||||
cursor: "pointer",
|
||||
opacity: busy ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
Restore original
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
disabled={busy}
|
||||
style={{
|
||||
padding: "5px 12px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(255,255,255,.1)",
|
||||
background: "transparent",
|
||||
color: "#a0a0a8",
|
||||
fontSize: 12,
|
||||
cursor: "pointer",
|
||||
opacity: busy ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onAccept}
|
||||
disabled={busy}
|
||||
style={{
|
||||
padding: "5px 14px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(127,208,160,.5)",
|
||||
background: "rgba(127,208,160,.12)",
|
||||
color: "#7fd0a0",
|
||||
fontSize: 12,
|
||||
cursor: "pointer",
|
||||
opacity: busy ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
{busy ? "Applying…" : "Accept"}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
display: "grid",
|
||||
gridTemplateColumns: "1fr 1fr",
|
||||
gap: 1,
|
||||
background: "rgba(255,255,255,.06)",
|
||||
}}
|
||||
>
|
||||
<DiffPane
|
||||
title="Before"
|
||||
color="#8a8a92"
|
||||
body={original}
|
||||
renderAsMarkdown={false}
|
||||
/>
|
||||
<DiffPane
|
||||
title="After"
|
||||
color="#7fd0a0"
|
||||
body={refined}
|
||||
renderAsMarkdown
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DiffPane({
|
||||
title,
|
||||
color,
|
||||
body,
|
||||
renderAsMarkdown,
|
||||
}: {
|
||||
title: string;
|
||||
color: string;
|
||||
body: string;
|
||||
renderAsMarkdown: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
background: "#0e0e12",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: 0,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "8px 14px",
|
||||
borderBottom: "1px solid rgba(255,255,255,.05)",
|
||||
fontFamily: mono,
|
||||
fontSize: 10,
|
||||
letterSpacing: ".14em",
|
||||
color,
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
<div style={{ flex: 1, minHeight: 0, overflow: "auto", padding: 14 }}>
|
||||
{renderAsMarkdown ? (
|
||||
<MarkdownBlock source={body} />
|
||||
) : (
|
||||
<pre
|
||||
style={{
|
||||
margin: 0,
|
||||
whiteSpace: "pre-wrap",
|
||||
wordBreak: "break-word",
|
||||
fontFamily: mono,
|
||||
fontSize: 12,
|
||||
color: "#cfcfd5",
|
||||
lineHeight: 1.55,
|
||||
}}
|
||||
>
|
||||
{body}
|
||||
</pre>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const iconBtn: React.CSSProperties = {
|
||||
width: 30,
|
||||
|
||||
Reference in New Issue
Block a user