EventStream
event-streamDisplays a live chronological stream of typed operational events.
Usage
Governance Audit Flow
The semantic color carries "which ones were stopped", click on the title to expand the basis; the released items retain the release description, and the audit can be traced.
- 09:12:01Session started · Task contract injected0.9ms
- 09:12:03Read pages/list/index.js0.3ms
- 09:12:09Write pages/list/index.js0.4ms
- 09:12:31Dispatching the 3rd subtask was intercepted1.1ms
- 09:13:02Confirmation is required to write a knowledge base entry0.8msAllowed: This time we really need to record
- 09:14:20Acceptance command execution completed · Exit code 012.4s
<EventStream
items={events}
maxHeight={320}
onItemClick={(e) => openDetail(e.id)}
/>CI pipeline
The same component can be used as a pipeline stage flow by changing a set of data; it takes time to put the meta column, and the equal-width numbers are naturally aligned.
- 14:02:11Pull code · main@a1b2c3d3.2s
- 14:02:19Dependency installation completed8.1s
- 14:03:40Unit test 194/194 passed81s
- 14:04:02There are 2 type checks any22ssrc/legacy/adapter.ts:44, :91
- 14:04:55End-to-end test 3 failures53sLogin jump timeout ×2 / Payment callback assertion does not match ×1
<EventStream items={pipelineSteps} defaultExpanded />Real-time addition (live)
Newly arrived entries fade in once and then become static. The event stream is open all year round, and any looping animation is just noise.
- 09:12:01Session started · Task contract injected0.9ms
- 09:12:03Read pages/list/index.js0.3ms
- 09:12:09Write pages/list/index.js0.4ms
<EventStream items={items} live maxHeight={280} />Time axis right
When embedding the narrow column on the right side of the main content on the left, placing the axis on the right side better fits the line of sight.
- 14:02:11Pull code · main@a1b2c3d3.2s
- 14:02:19Dependency installation completed8.1s
- 14:03:40Unit test 194/194 passed81s
- 14:04:02There are 2 type checks any22s
- 14:04:55End-to-end test 3 failures53s
<EventStream items={events} side="right" />When to use
- Audit streams and governance interceptions
- CI pipeline stages
- Logs and alerts
- Any continuously appended sequence that must expose anomalies quickly
When not to use
| Scenario | Use | Why |
|---|---|---|
| Conversation or topic list | ThreadList | Each item opens a conversation and emphasizes read progress. |
| Milestone narrative | Timeline | Sparse, manually curated points carry individual weight. |
| Priority-ordered work | QueueLane | The key information is backlog and waiting, not chronology. |
Usage
import { EventStream } from "@hulianui/ui";
<EventStream
items={[
{ id: 1, ts: "09:12:01", tone: "success", title: "Build passed", meta: "2.1s" },
{ id: 2, ts: "09:12:44", tone: "danger", title: "Unauthorized write blocked",
detail: "Target is outside the allowed scope", meta: "1.3ms" },
]}
maxHeight={320}
onItemClick={(e) => openDetail(e.id)}
/>Props
| Name | Type | Default | Description |
|---|---|---|---|
items | EventStreamItem[] | — | Displayed in input order; the component does not sort. |
maxHeight | number | string | — | Enables internal scrolling when supplied. |
emptyText | ReactNode | "\u6682\u65e0\u4e8b\u4ef6" | Empty text; the built-in Chinese means “No events.” |
onItemClick | (item) => void | — | Enables clickable and keyboard-accessible items. |
live | boolean | false | Fades newly appended items in once. |
side | "left" | "right" | "left" | Timeline side. |
defaultExpanded | boolean | false | Initially expands detail content. |
EventStreamItem
| Name | Type | Description |
|---|---|---|
id | string | number | Stable unique identity used by live-entry detection. |
ts | ReactNode | Caller-formatted time. |
tone | "neutral" | "info" | "success" | "warning" | "danger" | Semantic color, defaulting to neutral. |
title | ReactNode | One-line event summary. |
detail | ReactNode | Collapsible detail. |
meta | ReactNode | Right-aligned duration or identifier. |
overridden | ReactNode | Separate explanation for a manually overridden block. |
Design decisions
Time is not formatted. Time zone, precision, and relative-versus-absolute policy belong to the caller's domain.
`live` animates once, never continuously. A long-running event stream should not create permanent motion noise.
The first frame does not flash. Existing items are treated as seen on initial mount so only later additions stand out.
`overridden` remains a separate row. “Blocked and then allowed” must remain distinguishable from “never blocked”; folding it into tone would lose audit meaning.
The override row prepends built-in Chinese "\u5df2\u653e\u884c\uff1a", meaning “Allowed by override:”.
Playground
- 09:12:01Session started · Task contract injected0.9ms
- 09:12:03Read pages/list/index.js0.3ms
- 09:12:09Write pages/list/index.js0.4ms
- 09:12:31Dispatching the 3rd subtask was intercepted1.1ms
- 09:13:02Confirmation is required to write a knowledge base entry0.8msAllowed: This time we really need to record
- 09:14:20Acceptance command execution completed · Exit code 012.4s
<EventStream
items={events}
onItemClick={(e) => openDetail(e.id)}
/>