johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<script lang="ts">
import {
ago,
capitalized,
itemHref,
ran,
repoHref,
runningSteps,
shortRef,
stepLogs,
took
} from '#lib/format.ts';
import { followRun, followsEnd, type LiveRun } from '#lib/live.ts';
import { checkIcon } from '#lib/icons.ts';
import Icon from '#lib/atoms/Icon.svelte';
import Sha from '#lib/atoms/Sha.svelte';
import Time from '#lib/atoms/Time.svelte';
import RunImages from '#lib/molecules/RunImages.svelte';
import RerunMenu from '#lib/molecules/RerunMenu.svelte';
import RepoPage from '#lib/templates/RepoPage.svelte';
let { data } = $props();
const run = $derived(data.run);
const c = $derived(run.check);
const r = $derived(data.repo);
const base = $derived(repoHref(data.authority, r.name));
const logs = $derived(
run.log === undefined
? []
: stepLogs(
run.log,
run.steps.map((s) => s.name)
)
);
const length = $derived(ran(c.startedAt, c.finishedAt));
/** Whether the owner is looking, who may run it again: this workflow or all, of its pull or at its ref. */
const owns = $derived(data.viewer?.actor?.did === r.owner.did);
/** What it printed so far while it runs, as its runner sends it; the page draws again once it is filed. */
let live = $state<LiveRun>();
// Followed anew only as these change, not each time the page's answers are asked again.
const following = $derived(c.status === 'running' ? `${r.uri} ${c.uri}` : undefined);
$effect(() => {
live = undefined;
if (!following) return;
const [repo, uri] = following.split(' ');
return followRun(repo, uri, (heard) => (live = heard));
});
const going = $derived(live ? runningSteps(live.text, live.steps, live.going) : []);
</script>
<RepoPage
repo={r}
tab={run.pull ? 'pulls' : 'checks'}
title="{c.workflow} · {capitalized(c.status)} · {r.name}"
>
<div class="box run">
<div class="run-head {c.status}">
<span class="mark {c.status}"><Icon name={checkIcon(c.status)} /></span>
<h2>{c.workflow}</h2>
<span class="mute">{capitalized(c.status)}</span>
{#if owns}<span class="end"
><RerunMenu
repo={r.uri}
pull={run.pull}
ref={run.pull ? undefined : run.ref}
workflows={[c.workflow]}
/></span
>{/if}
</div>
<div class="boxhead boxfoot run-about mute">
<span
>on <b>{shortRef(run.ref)}</b> at <Sha
sha={c.commit}
href={`${base}/commit/${c.commit}`}
/></span
>
{#if run.pull}<a class="from" href={itemHref(base, run.pull)}><Icon name="merge" />Pull</a
>{/if}
<span>by {run.runner.handle}</span>
<span class="end"><Time at={c.startedAt} show={ago} />{length ? ` · ${length}` : ''}</span>
</div>
{#if c.error}<pre class="run-error">{c.error}</pre>{/if}
{#if c.skipped}<div class="run-note mute">{capitalized(c.skipped)}</div>{/if}
{#if c.status === 'queued'}<div class="run-note mute">
It starts once its runner has a job free.
</div>{/if}
{#if c.status === 'running' && going.length === 0}<div class="run-note mute">
Running: what it prints shows here as it prints it.
</div>{/if}
{#each going as g, i (i)}
<details class="step" open={g.step.status !== 'success'}>
<summary
><span class="mark {g.step.status}"><Icon name={checkIcon(g.step.status)} /></span><b
>{g.step.name}</b
><span class="end mute"
>{g.step.status === 'running'
? 'running'
: `${g.step.exitCode === undefined ? 'killed' : `exit ${g.step.exitCode}`} · ${took(g.step.durationMs ?? 0)}`}</span
></summary
>
{#if g.log}<pre class="step-log" use:followsEnd>{g.log}</pre>{:else}<div
class="run-note mute"
>
It printed nothing yet.
</div>{/if}
</details>
{/each}
{#each run.steps as s, i (i)}
<details class="step" open={s.status === 'failure'}>
<summary
><span class="mark {s.status}"><Icon name={checkIcon(s.status)} /></span><b>{s.name}</b
><span class="end mute"
>{s.status === 'skipped'
? 'skipped'
: `${s.exitCode === undefined ? 'killed' : `exit ${s.exitCode}`} · ${took(s.durationMs ?? 0)}`}</span
></summary
>
{#if logs[i]}<pre class="step-log">{logs[i]}</pre>{:else}<div class="run-note mute">
It printed nothing.
</div>{/if}
</details>
{/each}
<RunImages images={c.images} />
</div>
</RepoPage>