SearchCtrlK

  • ↑↓navigate
  • ↵open
  • escclose

Can’t find it? Contact us

LogViewer

A CI job's log.

Show timestamps
Set up job2s
Current runner version: '2.321.0'
Operating System
Ubuntu 24.04.1 LTS
Runner Image: ubuntu-24.04
Install dependencies14s
Run bun install --frozen-lockfile
bun install v1.3.2
Resolving dependencies
Resolved, downloaded and extracted [412]
+ vitest@4.1.11
+ typescript@6.0.3
412 packages installed [13.82s]
Run tests41s
bun run test --reporter=dot
RUN v4.1.11 /home/runner/work/delta/delta
✓ src/lexer/chars.test.ts (18 tests) 6ms
✓ src/lexer/tokens.test.ts (42 tests) 11ms
✗ src/lexer/identifier.test.ts (9 tests | 1 failed) 9ms
× reads an identifier that starts with a Unicode letter
✓ src/parser/expression.test.ts (64 tests) 23ms
FAIL src/lexer/identifier.test.ts > reads an identifier that starts with a Unicode letter
AssertionError: expected undefined to deeply equal { kind: 'identifier', value: 'ñandú' }
❯ src/lexer/identifier.test.ts:27:41
Test Files 1 failed | 3 passed (4)
Tests 1 failed | 132 passed (133)
Process completed with exit code 1.
Upload coverage
Complete job1s
Cleaning up orphan processes
View code
tsx
<LogViewer
	steps={job.steps}
	lineHref={(step, n) => `#step:${step}:${n}`}
	timestamps={showTimes}
	timestampsHref={showTimes ? "?" : "?ts=1"}
	labels={{
		log: "Job log",
		states: { success: "Succeeded", failure: "Failed", running: "In progress", queued: "Queued", skipped: "Skipped", cancelled: "Cancelled" },
		search: "Search logs",
		matches: "{index} of {count}",
		noMatches: "No results",
		previousMatch: "Previous match",
		nextMatch: "Next match",
		showTimestamps: "Show timestamps",
		hideTimestamps: "Hide timestamps",
		jumpToLatest: "Jump to latest",
		refresh: "Refresh",
	}}
/>

Demo apps

Whole pages built only from @sdxc/ui, each for an invented product with its own palette and type. They open in a new tab.

Every demo, landings and docs sites alike, is listed in the demo gallery.

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

Terminal
npm add @sdxc/ui remix
typescript
import "@sdxc/ui/theme.css";

Usage

typescript
import { LogViewer } from "@sdxc/ui/app";

Every line is in the page from the start, so find-in-page and line links work without script; mapping @sdxc/ui/app/log-viewer runs LogViewerController for search, streaming and tail-follow. Set --ui-log-viewer-height for the scroll box, --ui-log-chunk-lines per chunk.

Composition

The parts the component publishes, each a static property of the host.

  • LogViewer
  • LogViewer.StreamRenders the step the viewer draws for a running step: the lines so far, then each line the stream answers appended in place while the log follows its tail.

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeRequiredDescription
stepsStep[]YesThe job's steps in run order; each becomes one collapsible section.
lineHref(step: number, n: number) => stringYesA line's link, e.g. (step, n) => "#step:" + step + ":" + n; its fragment becomes the line's id.
timestampsbooleanNoDraws each line's time beside its number.
timestampsHrefstringNoThe page with timestamps toggled, e.g. ?ts=1; omitted, the toggle is not drawn.
labelsLabelsYesEvery string the viewer shows or announces, so it reads in any language.

Also accepts everything in Omit<TagProps<"section">, "children">.

LogViewer.Stream

PropTypeRequiredDescription
indexnumberYesThe step's position in the job, from 1, as lineHref receives it.
stepStep & { stream: StreamSource }YesThe running step, with the stream its further lines come from.
lineHref(step: number, n: number) => stringYesThe viewer's lineHref, so streamed lines link like drawn ones.
labelsLabelsYesThe viewer's strings.

Types

NameValuesWhat it decides
State"success" | "failure" | "running" | "queued" | "skipped" | "cancelled"Where a step stands.
@sdxc/ui

Can’t find it? Contact us