refactor(web): simplify run logs view

Drop unjustified useMemo around byteCount, add void to mutate(), let
errorMessage return undefined for non-Error values so the description
doesn't duplicate the retry button label, and reuse formatBytes (hoisted
to lib/format.ts from insights-editor) so log size renders as "1.23 MB"
instead of "1,234,567 bytes".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-26 17:47:10 -04:00
parent 4e9d3774ef
commit 7ecd8df32e
No known key found for this signature in database
5 changed files with 100 additions and 98 deletions

View file

@ -19,6 +19,16 @@ export function formatElapsedSecs(secs: number): string {
return remainHrs > 0 ? `${days}d ${remainHrs}h` : `${days}d`;
}
/**
* Format a byte count for display (e.g., "1.23 MB", "247.32 KB", "742 B").
*/
export function formatBytes(bytes: number): string {
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(2)} GB`;
if (bytes >= 1e6) return `${(bytes / 1e6).toFixed(2)} MB`;
if (bytes >= 1e3) return `${(bytes / 1e3).toFixed(2)} KB`;
return `${bytes} B`;
}
/**
* Format seconds into a duration string for display (e.g., "1m 12s", "23s").
*/

View file

@ -15,6 +15,7 @@ import {
ArrowPathIcon,
PencilIcon,
} from "@heroicons/react/24/outline";
import { formatBytes } from "../lib/format";
// ── Types ──
@ -95,13 +96,6 @@ function generateMockResult(sql: string): QueryResult {
// ── Formatting helpers ──
function formatBytes(bytes: number): string {
if (bytes >= 1e9) return `${(bytes / 1e9).toFixed(2)} GB`;
if (bytes >= 1e6) return `${(bytes / 1e6).toFixed(2)} MB`;
if (bytes >= 1e3) return `${(bytes / 1e3).toFixed(2)} KB`;
return `${bytes} B`;
}
function formatNumber(n: number): string {
return n.toLocaleString();
}

View file

@ -4,6 +4,7 @@ import { useParams } from "react-router";
import { EmptyState, ErrorState, LoadingState } from "../components/state";
import { StageSidebar } from "../components/stage-sidebar";
import { CopyButton } from "../components/ui";
import { formatBytes } from "../lib/format";
import { useRun, useRunLogs, useRunStages } from "../lib/queries";
import { mapRunStagesToSidebarStages } from "../lib/stage-sidebar";
@ -36,7 +37,7 @@ function renderBody(logsQuery: ReturnType<typeof useRunLogs>) {
<ErrorState
title="Couldn't load run log"
description={errorMessage(logsQuery.error)}
onRetry={() => logsQuery.mutate()}
onRetry={() => void logsQuery.mutate()}
/>
);
}
@ -55,15 +56,13 @@ function renderBody(logsQuery: ReturnType<typeof useRunLogs>) {
}
function LogPanel({ text }: { text: string }) {
const byteCount = useMemo(() => new Blob([text]).size, [text]);
const byteCount = new Blob([text]).size;
return (
<div className="rounded-md border border-line bg-panel-alt">
<div className="flex items-center justify-between gap-3 border-b border-line px-3 py-2">
<span className="font-mono text-xs text-fg-muted">runtime/server.log</span>
<div className="flex items-center gap-3">
<span className="text-xs tabular-nums text-fg-muted">
{byteCount.toLocaleString()} bytes
</span>
<span className="text-xs tabular-nums text-fg-muted">{formatBytes(byteCount)}</span>
<CopyButton value={text} label="Copy run log" />
</div>
</div>
@ -74,7 +73,6 @@ function LogPanel({ text }: { text: string }) {
);
}
function errorMessage(error: unknown): string {
if (error instanceof Error) return error.message;
return "Please try again.";
function errorMessage(error: unknown): string | undefined {
return error instanceof Error ? error.message : undefined;
}

View file

@ -59,7 +59,7 @@
<script type="module" src="/assets/chunk-nkw6kj41.js"></script>
<script type="module" src="/assets/chunk-71s03bbh.js"></script>
<script type="module" src="/assets/chunk-ept66kdn.js"></script>
<script type="module" src="/assets/entry-2fvwpvjj.js"></script>
<script type="module" src="/assets/entry-ge8df28x.js"></script>
<script type="module" src="/assets/chunk-dep0g6mr.js"></script>
<script type="module" src="/assets/chunk-c8zhk10v.js"></script>
<script type="module" src="/assets/chunk-n9tc6j4j.js"></script>