Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions frontend/src/pages/leaderboard/LeaderboardEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ import {

const DEFAULT_CODE = `# Write your code here`;

function isTerminalErrorStatus(status?: string | null) {
const v = typeof status === "string" ? status.toLowerCase() : "";
return (
v.includes("fail") ||
v.includes("err") ||
v.includes("hack") ||
v.includes("timed") ||
v.includes("timeout")
);
}

export default function LeaderboardEditor() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
Expand Down Expand Up @@ -428,8 +439,17 @@ export default function LeaderboardEditor() {
</Alert>
)}
{editorStatus.kind === "done" && (
<Alert severity="success" sx={{ mt: 1 }}>
Submission completed!
<Alert
severity={
isTerminalErrorStatus(editorStatus.result.status)
? "error"
: "success"
}
sx={{ mt: 1 }}
>
{isTerminalErrorStatus(editorStatus.result.status)
? `Submission completed with status: ${editorStatus.result.status}`
: "Submission completed!"}
</Alert>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,30 @@ interface JobOutputPanelProps {
uploadStatus: SubmitStatus;
}

function isTerminalErrorStatus(status?: string | null) {
const v = typeof status === "string" ? status.toLowerCase() : "";
return (
v.includes("fail") ||
v.includes("err") ||
v.includes("hack") ||
v.includes("timed") ||
v.includes("timeout")
);
}

export function JobOutputPanel({ editorStatus, uploadStatus }: JobOutputPanelProps) {
const completedResult =
editorStatus.kind === "done"
? editorStatus.result
: uploadStatus.kind === "done"
? uploadStatus.result
: undefined;
const completedWithError = isTerminalErrorStatus(completedResult?.status);
const doneLabel = completedWithError
? (completedResult?.status ?? "failed")
: "Done";
const doneColor = completedWithError ? "error" : "success";

return (
<Box sx={{ flex: 1, minHeight: 80, display: "flex", flexDirection: "column" }}>
<Stack direction="row" alignItems="center" spacing={1} sx={{ mb: 1, flexShrink: 0 }}>
Expand All @@ -28,8 +51,8 @@ export function JobOutputPanel({ editorStatus, uploadStatus }: JobOutputPanelPro
{(editorStatus.kind === "done" || uploadStatus.kind === "done") && (
<Chip
icon={<CheckCircleIcon />}
label="Done"
color="success"
label={doneLabel}
color={doneColor}
size="small"
sx={{ height: 20, fontSize: "0.7rem" }}
/>
Expand Down Expand Up @@ -109,7 +132,7 @@ export function JobOutputPanel({ editorStatus, uploadStatus }: JobOutputPanelPro

{editorStatus.kind === "done" && editorStatus.result && (
<Box>
<div style={{ color: "#569cd6" }}>
<div style={{ color: completedWithError ? "#f14c4c" : "#569cd6" }}>
Submission #{editorStatus.submissionId} completed
</div>
{editorStatus.result.error && (
Expand Down Expand Up @@ -154,7 +177,16 @@ export function JobOutputPanel({ editorStatus, uploadStatus }: JobOutputPanelPro
)}
</Box>
))}
<div style={{ color: "#4ec9b0", marginTop: 8 }}>$ Done</div>
<div
style={{
color: completedWithError ? "#f14c4c" : "#4ec9b0",
marginTop: 8,
}}
>
{completedWithError
? `$ ${editorStatus.result.status ?? "failed"}`
: "$ Done"}
</div>
</Box>
)}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
import { Tooltip } from "@mui/material";
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HourglassEmptyIcon from "@mui/icons-material/HourglassEmpty";

function SubmissionDoneCell({ done }: { done: boolean }) {
function SubmissionDoneCell({
done,
status,
}: {
done: boolean;
status?: string | null;
}) {
const v = typeof status === "string" ? status.toLowerCase() : "";
const hasErrorStatus =
v.includes("fail") ||
v.includes("err") ||
v.includes("hack") ||
v.includes("timed") ||
v.includes("timeout");

if (!done) {
return (
<Tooltip title="In progress">
<HourglassEmptyIcon fontSize="small" />
</Tooltip>
);
}

if (hasErrorStatus) {
return (
<Tooltip title={`Completed with status: ${v}`}>
<ErrorOutlineIcon color="error" fontSize="small" />
</Tooltip>
);
}

return done ? (
<Tooltip title="Completed">
<CheckCircleOutlineIcon fontSize="small" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@ export default function SubmissionHistorySection({
<SubmissionStatusChip status={s.status} />
</TableCell>
<TableCell align="center">
<SubmissionDoneCell done={s.submission_done} />
<SubmissionDoneCell
done={s.submission_done}
status={s.status}
/>
</TableCell>
<TableCell>
{hasRuns ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import { Chip, Tooltip } from "@mui/material";
function SubmissionStatusChip({ status }: { status?: string | null }) {
const str = typeof status === "string" ? status : ""; // normalize
const v = str.toLowerCase();
const isSuccess = v.includes("ok") || v.includes("succ");
const isRunning = v.includes("run");
const isError =
v.includes("fail") ||
v.includes("err") ||
v.includes("hack") ||
v.includes("timed") ||
v.includes("timeout");

const color: "default" | "success" | "warning" | "error" = v.includes("run")
const color: "default" | "success" | "warning" | "error" = isRunning
? "warning"
: v.includes("ok") || v.includes("succ")
: isSuccess
? "success"
: v.includes("fail") || v.includes("err")
: isError
? "error"
: "default";

const showFallback = !str;
const label = showFallback
? "via CLI/Discord bot"
: v.includes("ok") || v.includes("succ")
: isSuccess
? "finished"
: v;

Expand Down