mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-11-01 07:02:30 +00:00
Merge pull request #1080 from fabro-sh/codex/remove-overview-platform-records
Some checks are pending
Rust / Rustdoc (push) Waiting to run
Rust / Generated Docs (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
Rust / Process titles (musl) (push) Waiting to run
Rust / Format (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Sandbox providers (Docker) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
Some checks are pending
Rust / Rustdoc (push) Waiting to run
Rust / Generated Docs (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
Rust / Process titles (musl) (push) Waiting to run
Rust / Format (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Sandbox providers (Docker) (push) Waiting to run
TypeScript / Typecheck (push) Waiting to run
TypeScript / Test (push) Waiting to run
TypeScript / Build (push) Waiting to run
fix(web): remove platform records from run overview
This commit is contained in:
commit
022f3df2b1
6 changed files with 3 additions and 191 deletions
|
|
@ -1,93 +0,0 @@
|
|||
import { useMemo } from "react";
|
||||
import type { RunProjection } from "@qltysh/fabro-api-client";
|
||||
|
||||
import { formatAbsoluteTs } from "../lib/format";
|
||||
import {
|
||||
platformRecordsOf,
|
||||
type PlatformRecordEntry,
|
||||
} from "../lib/petri-stream";
|
||||
import { useRunState, useRunStream } from "../lib/queries";
|
||||
|
||||
const KIND_LABEL: Record<string, string> = {
|
||||
"checkpoint": "Checkpoint",
|
||||
"pull_request.created": "Pull request",
|
||||
"run.notice": "Notice",
|
||||
"run.title": "Title",
|
||||
"run.branch": "Run branch",
|
||||
};
|
||||
|
||||
function kindLabel(kind: string): string {
|
||||
return KIND_LABEL[kind] ?? kind;
|
||||
}
|
||||
|
||||
/**
|
||||
* The platform records of a Petri run: Fabro's own facts beside the engine's
|
||||
* events (a checkpoint with its commit, a pull request, a notice), each with
|
||||
* the stage it belongs to when it belongs to one.
|
||||
*/
|
||||
export function PlatformRecordsPanelView({
|
||||
records,
|
||||
projection,
|
||||
}: {
|
||||
records: PlatformRecordEntry[];
|
||||
projection: RunProjection | null | undefined;
|
||||
}) {
|
||||
const pullRequest = projection?.pull_request ?? null;
|
||||
if (records.length === 0 && !pullRequest) return null;
|
||||
return (
|
||||
<section
|
||||
aria-label="Platform records"
|
||||
className="rounded-md border border-line bg-panel/60 px-6 py-4"
|
||||
>
|
||||
<h3 className="text-[10px] font-medium uppercase tracking-[0.08em] text-fg-muted">
|
||||
Platform records
|
||||
</h3>
|
||||
<ul className="mt-2 space-y-1 text-sm">
|
||||
{pullRequest && (
|
||||
<li className="flex items-baseline gap-3">
|
||||
<span className="w-28 shrink-0 text-fg-muted">Pull request</span>
|
||||
<a
|
||||
href={pullRequest.html_url}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="truncate font-mono text-teal-500 hover:text-teal-300"
|
||||
>
|
||||
#{pullRequest.number}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{records.map((record) => (
|
||||
<li
|
||||
key={record.streamSeq}
|
||||
data-kind={record.kind}
|
||||
className="flex items-baseline gap-3"
|
||||
>
|
||||
<span className="w-28 shrink-0 text-fg-muted">{kindLabel(record.kind)}</span>
|
||||
<span className="min-w-0 flex-1 truncate font-mono text-fg-2">
|
||||
{record.detail ?? "—"}
|
||||
</span>
|
||||
{record.stageKey && (
|
||||
<span className="shrink-0 font-mono text-xs text-fg-muted">
|
||||
stage {record.stageKey}
|
||||
</span>
|
||||
)}
|
||||
<span className="shrink-0 font-mono text-xs tabular-nums text-fg-muted">
|
||||
{formatAbsoluteTs(record.ts)}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
/** The panel for a run: the platform records on its stream. */
|
||||
export function PlatformRecordsPanel({ runId }: { runId: string }) {
|
||||
const runStateQuery = useRunState(runId);
|
||||
const streamQuery = useRunStream(runId);
|
||||
const records = useMemo(
|
||||
() => (streamQuery.data ? platformRecordsOf(streamQuery.data) : []),
|
||||
[streamQuery.data],
|
||||
);
|
||||
return <PlatformRecordsPanelView records={records} projection={runStateQuery.data} />;
|
||||
}
|
||||
|
|
@ -21,7 +21,6 @@ import {
|
|||
petriEventName,
|
||||
petriStageLabel,
|
||||
platformRecordKind,
|
||||
platformRecordsOf,
|
||||
reducerTranscriptFromProjection,
|
||||
stagesFromProjection,
|
||||
streamItemName,
|
||||
|
|
@ -204,27 +203,6 @@ describe("run phases", () => {
|
|||
});
|
||||
|
||||
describe("platform records", () => {
|
||||
test("a notice recorded between the branches lists with its message", () => {
|
||||
const records = platformRecordsOf(parallel.stream);
|
||||
const notices = records.filter((record) => record.kind === "run.notice");
|
||||
expect(notices).toHaveLength(1);
|
||||
expect(notices[0].detail).toBe("recorded while both branches ran");
|
||||
expect(notices[0].stageKey).toBeNull();
|
||||
});
|
||||
|
||||
test("each stage's checkpoint lists with its commit and its stage", () => {
|
||||
const records = platformRecordsOf(parallel.stream);
|
||||
const checkpoints = records.filter((record) => record.kind === "checkpoint");
|
||||
// start, fork, a, b, merge, exit, and the two branch delegates.
|
||||
expect(checkpoints.length).toBeGreaterThanOrEqual(6);
|
||||
for (const checkpoint of checkpoints) {
|
||||
expect(checkpoint.detail).toMatch(/^[0-9a-f]{12}$/);
|
||||
expect(checkpoint.stageKey).not.toBeNull();
|
||||
}
|
||||
const order = records.map((record) => record.kind);
|
||||
expect(order.indexOf("checkpoint")).toBeLessThan(order.indexOf("run.notice"));
|
||||
});
|
||||
|
||||
test("the debug rows name every item and carry its stage", () => {
|
||||
const rows = debugRowsFromStream(parallel.stream);
|
||||
expect(rows).toHaveLength(parallel.stream.length);
|
||||
|
|
|
|||
|
|
@ -412,55 +412,6 @@ export function deriveRunPhasesFromStream(
|
|||
return phases;
|
||||
}
|
||||
|
||||
// ── Platform records ────────────────────────────────────────────────────
|
||||
|
||||
export interface PlatformRecordEntry {
|
||||
streamSeq: number;
|
||||
kind: string;
|
||||
ts: string;
|
||||
/** The stage the record belongs to, as `execution:firing`, if any. */
|
||||
stageKey: string | null;
|
||||
/** A one-line summary: the commit sha, the pull request url, the notice. */
|
||||
detail: string | null;
|
||||
}
|
||||
|
||||
/** The platform records on the stream that name a Fabro fact worth a row. */
|
||||
export function platformRecordsOf(stream: PetriStream): PlatformRecordEntry[] {
|
||||
const out: PlatformRecordEntry[] = [];
|
||||
for (const item of stream) {
|
||||
const kind = platformRecordKind(item);
|
||||
if (!kind) continue;
|
||||
const rec = record(item) ?? {};
|
||||
const position = getObject(item.item, "position");
|
||||
const execution = getNumber(position, "execution") ?? getNumber(rec, "execution");
|
||||
const firing = getNumber(position, "firing") ?? getNumber(rec, "firing");
|
||||
const stageKey =
|
||||
execution !== undefined && firing !== undefined ? `${execution}:${firing}` : null;
|
||||
let detail: string | null = null;
|
||||
switch (kind) {
|
||||
case "checkpoint":
|
||||
detail = getString(rec, "git_commit_sha")?.slice(0, 12) ?? null;
|
||||
break;
|
||||
case "pull_request.created":
|
||||
detail = getString(rec, "html_url") ?? getString(rec, "url") ?? null;
|
||||
break;
|
||||
case "run.notice":
|
||||
detail = getString(rec, "message") ?? getString(rec, "code") ?? null;
|
||||
break;
|
||||
case "run.title":
|
||||
detail = getString(rec, "title") ?? null;
|
||||
break;
|
||||
case "run.branch":
|
||||
detail = getString(rec, "run_branch") ?? null;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
out.push({ streamSeq: item.stream_seq, kind, ts: streamItemTs(item), stageKey, detail });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// ── Debug rows ──────────────────────────────────────────────────────────
|
||||
|
||||
/** A stream item as the events listing and the stage debug tab show it. */
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ mock.module("../lib/queries", () => ({
|
|||
mutate: graphMutateMock,
|
||||
}),
|
||||
useRunGraphSource: () => ({ data: undefined }),
|
||||
useRunState: () => ({ data: undefined }),
|
||||
useRunStream: () => ({ data: undefined }),
|
||||
}));
|
||||
|
||||
mock.module("../components/run-summary-panel", () => ({
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { stagePath } from "../lib/stage-routes";
|
|||
import { ApiError } from "../lib/api-client";
|
||||
import { useRun, useRunGraph, useRunGraphSource, useRunStages } from "../lib/queries";
|
||||
import { FloatingTooltip } from "../components/floating-tooltip";
|
||||
import { PlatformRecordsPanel } from "../components/platform-records-panel";
|
||||
import { RunSummaryPanel } from "../components/run-summary-panel";
|
||||
import { StagePopover } from "../components/stage-popover";
|
||||
import { StageSidebar } from "../components/stage-sidebar";
|
||||
|
|
@ -154,9 +153,8 @@ export default function RunOverview() {
|
|||
</div>
|
||||
|
||||
<div className="flex min-h-0 min-w-0 flex-1 flex-col gap-4 pb-[var(--fabro-interview-dock-clearance,0px)]">
|
||||
<div className="shrink-0 space-y-4">
|
||||
<div className="shrink-0">
|
||||
<RunSummaryPanel runId={id!} />
|
||||
<PlatformRecordsPanel runId={id!} />
|
||||
</div>
|
||||
{graphSvg === undefined && graphQuery.isLoading ? (
|
||||
<div className="flex-1" />
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import type { RunStage } from "@qltysh/fabro-api-client";
|
|||
import TestRenderer, { act } from "react-test-renderer";
|
||||
import { MemoryRouter } from "react-router";
|
||||
|
||||
import { PlatformRecordsPanelView } from "../components/platform-records-panel";
|
||||
import { RunWaterfall } from "../components/run-waterfall";
|
||||
import { StageSidebar } from "../components/stage-sidebar";
|
||||
import { FanInResults } from "../components/stage-renderers/fan-in-results";
|
||||
|
|
@ -26,7 +25,6 @@ import {
|
|||
parallelOverviewFromProjection,
|
||||
parsePetriInterviewPairs,
|
||||
petriParsed,
|
||||
platformRecordsOf,
|
||||
reducerTranscriptFromProjection,
|
||||
stagesFromProjection,
|
||||
} from "../lib/petri-stream";
|
||||
|
|
@ -197,7 +195,7 @@ describe("a two-branch parallel run", () => {
|
|||
expect(html).not.toContain("Reducer transcript");
|
||||
});
|
||||
|
||||
test("the events view lists Petri events by name and the platform notice", () => {
|
||||
test("the events view lists Petri events, platform notices and checkpoints", () => {
|
||||
const html = render(
|
||||
<StreamEventsView
|
||||
rows={debugRowsFromStream(fixture.stream)}
|
||||
|
|
@ -212,29 +210,11 @@ describe("a two-branch parallel run", () => {
|
|||
expect(html).toContain(name);
|
||||
}
|
||||
expect(html).toContain("run.notice");
|
||||
expect(html).toContain("checkpoint");
|
||||
expect(html).toContain('"data-stage":"a@1"');
|
||||
expect(html).toContain(`${fixture.stream.length} items`);
|
||||
});
|
||||
|
||||
test("the overview lists the platform records", () => {
|
||||
const html = render(
|
||||
<PlatformRecordsPanelView
|
||||
records={platformRecordsOf(fixture.stream)}
|
||||
projection={fixture.projection}
|
||||
/>,
|
||||
);
|
||||
expect(html).toContain("Platform records");
|
||||
expect(html).toContain("Notice");
|
||||
expect(html).toContain("recorded while both branches ran");
|
||||
// The checkpoint hook wrote one record per stage, with its commit.
|
||||
expect(html).toContain("Checkpoint");
|
||||
const checkpoint = fixture.stream.find(
|
||||
(item) => item.kind === "platform" && item.item.record?.kind === "checkpoint",
|
||||
);
|
||||
expect(checkpoint).toBeDefined();
|
||||
expect(html).toContain(String(checkpoint!.item.record.git_commit_sha).slice(0, 12));
|
||||
});
|
||||
|
||||
test("the sidebar groups the branches under the fork", () => {
|
||||
const branches = stages.filter((stage) => stage.parallelGroupId === "fork@1");
|
||||
expect(branches.map((stage) => stage.id)).toEqual(["a@1", "b@1"]);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue