Attention Routing 01 - Review queue

v0.5.1

Fully reusable list-based workflow block composed from Page Header, Filter Toolbar, Record List, and Pagination. Supports generic filtering, search, selection, and custom rendering. Domain-agnostic and configurable via props.

View as Markdown

Preview

Open full page ↗

Install & usage

npx shadcn@4.1.2 add @signalos/attention-routing-01

Pulls the page source plus its widget dependencies (@signalos/tokens, @signalos/utils, @signalos/filter-toolbar, @signalos/page-header, @signalos/record-list, @signalos/pagination, @signalos/signal-feed-card, @signalos/status-badge, @signalos/metric-tile, @signalos/circular-progress, @signalos/sidebar-detail-panel, @signalos/data-primitives, @signalos/lifecycle-timeline, @signalos/badge, @signalos/skeleton) into your app - you own the copy. Requires access.

usage
// after: npx shadcn@4.1.2 add @signalos/attention-routing-01
// mount the pulled page in a route, e.g. src/app/attention-routing/page.tsx
import { AttentionRouting01 } from "@/components/blocks/attention-routing-01/AttentionRouting01"

export default function Page() {
  return <AttentionRouting01 />
}

Props

AttentionSegmentFilter

PropTypeDefaultDescription
key*string-Stable key.
value*string-Current value.
onChange*(value: string) => void-Change handler.
options*readonly AttentionFilterOption[]-Selectable options.
tone"warning" | "primary" | "neutral" | undefined-Accent tone for the active segment.

AttentionSelectFilter

PropTypeDefaultDescription
key*string-
value*string-
onChange*(value: string) => void-
options*readonly AttentionFilterOption[]-
placeholderstring | undefined-

AttentionFilterOption

PropTypeDefaultDescription
value*string-
label*string-

AttentionRouting01Props

PropTypeDefaultDescription
items*readonly TData[]-The items to render in the queue.
titleReactNode"Attention Routing"Page heading.
descriptionReactNode-Sub-heading under the title.
loadingboolean | undefined-Loading state — renders skeletons via `renderSkeleton`.
errorboolean | undefined-Error state — renders `errorMessage`.
errorMessageReactNode-
segmentFiltersreadonly AttentionSegmentFilter[] | undefined-Segmented pill-group filters (severity, deadline window, …).
selectFiltersreadonly AttentionSelectFilter[] | undefined-Dropdown filters (owner, role, …).
toolbarExtrasReactNode-Additional content rendered inside the FilterToolbar (e.g. action buttons, toggles, badges).
searchValuestring | undefined-Free-text search value + handler.
onSearchChange((value: string) => void) | undefined-
searchPlaceholderstring | undefined"Search attention items..."
resultLabelstring | undefined"item"Singular noun for the result count, e.g. "item".
onRefresh(() => void) | undefined-Refresh affordance.
isRefreshingboolean | undefined-
selectedIdstring | null | undefined-Currently-selected item id (for highlight state in `renderItem`).
onSelect((item: TData) => void) | undefined-Fired when an item is activated (click / Enter / Space).
renderItem((item: TData, index: number) => ReactNode) | undefined-Renders a single item.
renderSkeleton((index: number) => ReactNode) | undefined-Renders a single loading skeleton row.
getItemKey((item: TData, index: number) => string) | undefined-Stable key for an item.
emptyTitleReactNode-Empty-state copy.
emptyDescriptionReactNode-
summaryReactNode-KPI/summary content rendered above the toolbar.
showPaginationboolean | undefined-Pagination (hidden while searching).
currentPagenumber | undefined-
pageSizenumber | undefined-
totalRecordsnumber | undefined-
onPageChange((page: number) => void) | undefined-
onPageSizeChange((pageSize: number) => void) | undefined-
detailPanelReactNode-Detail drawer/panel rendered at the end of the block.
classNamestring | undefined-
data-testidstring | undefined-

RoutingDetailSignal

PropTypeDefaultDescription
id*string-
metric_id*string-
signal_type*string-
severity*BlackboardSeverity-
deviation_std*number-
crlb_score*number-
fired_at*string-
source_connector_id*string | null-
dimension_key*Record<string, unknown>-

RoutingRelatedHypothesis

PropTypeDefaultDescription
id*string-
label*string-
severity*BlackboardSeverity-
status*HypothesisStatus-
created_at*string-

RoutingDetailResponse

PropTypeDefaultDescription
item*RoutingFeedItem-
signals*RoutingDetailSignal[]-
transfer_history*RoutingTransferEntry[]-
related_hypotheses*RoutingRelatedHypothesis[]-

RoutingFeedItem

PropTypeDefaultDescription
slot*RoutingFeedSlot-
hypothesis*RoutingFeedHypothesis-
signal_summary*RoutingFeedSignalSummary-
routed_to*RoutingFeedUser | null-
routed_to_role*RoutingFeedRole | null-
lifecycle*RoutingFeedLifecycle-

RoutingTransferEntry

PropTypeDefaultDescription
offer_id*string-
status*OpenEnum<RoutingTransferStatus>-
from_user*RoutingFeedUser | null-
to_user*RoutingFeedUser | null-
reason*string | null-
created_at*string-
responded_at*string | null-

RoutingFeedSlot

PropTypeDefaultDescription
id*string-
status*SlotStatus-
priority_rank*number-
priority_score*number-
created_at*string-
escalated_from*string | null-

RoutingFeedHypothesis

PropTypeDefaultDescription
id*string-
label*string-
severity*BlackboardSeverity-
domain*string | null-
cagg*number-
confidence_current*number-
created_at*string-
act_by_deadline*string | null-
time_to_act_seconds*number | null-Seconds until/past the act_by_deadline. - null = no deadline set - positive = time left - NEGATIVE = past-due (guide §4)

RoutingFeedSignalSummary

PropTypeDefaultDescription
count*number-
earliest_fired_at*string | null-
latest_fired_at*string | null-
metric_ids*string[]-
max_deviation_std*number | null-
dimension_keys*Record<string, unknown>[]-

RoutingFeedUser

PropTypeDefaultDescription
user_id*string-
email*string-
full_name*string-

RoutingFeedRole

PropTypeDefaultDescription
role_id*string-
role_name*string-

RoutingFeedLifecycle

PropTypeDefaultDescription
signal_to_hypothesis_seconds*number | null-
hypothesis_to_routing_seconds*number | null-
age_seconds*number-

AttentionSlot

PropTypeDefaultDescription
id*string-
executive_id*string-
hypothesis_id*string-
priority_rank*number-
priority_score*number-
signal_summary*SignalSummary-
escalation_deadline*string | null-
escalated_from*string | null-
status*SlotStatus-
closed_reason*string | null-
created_at*string-
updated_at*string-
decayed_at*string | null-
act_by_deadline*string | null-
severity*BlackboardSeverity | null-
confidence_initial*number | null-
confidence_current*number | null-
swap_out_slot_idstring | null | undefined-

SignalSummary

PropTypeDefaultDescription
labelstring | undefined-
caggnumber | undefined-
sufficiencynumber | undefined-
signal_countnumber | undefined-
severityBlackboardSeverity | undefined-
domainstring | undefined-
clusterstring | undefined-
equilibrium_statestring | undefined-
contributing_signalsContributingSignal[] | undefined-

ContributingSignal

PropTypeDefaultDescription
role*string-
cluster*string-
deviation*number-
metric_id*string-
signal_id*string-
confidence*number-

RoutingFlowResponse

PropTypeDefaultDescription
hypothesis_id*string-
timeline*RoutingFlowEvent[]-

RoutingFlowEvent

PropTypeDefaultDescription
at*string-
event*RoutingFlowEventType-
detail*Record<string, unknown>-

RoutingDashboardSummary

PropTypeDefaultDescription
in_flight_total*number-
by_status*RoutingSummaryStatusCounts-
by_severity*RoutingSummarySeverityCounts-
by_role*RoutingSummaryRoleCount[]-
deadlines*RoutingSummaryDeadlines-
throughput_last_24h*RoutingSummaryThroughput-

RoutingSummaryStatusCounts

PropTypeDefaultDescription
ACTIVEnumber | undefined-
IN_PROGRESSnumber | undefined-
EXPIREDnumber | undefined-
ESCALATEDnumber | undefined-

RoutingSummarySeverityCounts

PropTypeDefaultDescription
criticalnumber | undefined-
highnumber | undefined-
mediumnumber | undefined-
lownumber | undefined-
infonumber | undefined-

RoutingSummaryRoleCount

PropTypeDefaultDescription
role_id*string-
role_name*string-
count*number-

RoutingSummaryDeadlines

PropTypeDefaultDescription
breaching_within_1h*number-
breaching_within_4h*number-
breaching_within_24h*number-
past_deadline*number-

RoutingSummaryThroughput

PropTypeDefaultDescription
signals_fired*number-
hypotheses_created*number-
slots_routed*number-
decisions_made*number-
median_signal_to_route_sec*number | null-
median_route_to_decision_sec*number | null-

Supporting types

export type BlackboardSeverity = "info" | "low" | "medium" | "high" | "critical"
export type HypothesisStatus =
  "FORMING" | "SUFFICIENT" | "ROUTED" | "DECIDED" | "EXPIRED"
export type SlotStatus = "ACTIVE" | "IN_PROGRESS" | "EXPIRED" | "ESCALATED"
export type RoutingTransferStatus =
  "PENDING" | "ACCEPTED" | "DECLINED" | "EXPIRED" | "CANCELED" | "WITHDRAWN"
export type OpenEnum<T extends string> = T | (string & {})
export type RoutingFlowEventType = OpenEnum<
  | "signal.fired"
  | "hypothesis.formed"
  | "hypothesis.routed"
  | "slot.transferred"
  | "decision.created"
>

Changelog

attention-routing-01

0.5.1

  • BREAKING: Removed the routing prop (AttentionRoutingDomainProps) added in 0.4.0. Wiring SignalFeedCard, RoutingSummaryTiles, and RoutingDetailPanel directly into the block violated the "pure composition, no new visual language" rule the block has followed since 0.3.0 — the block special-cased one domain instead of staying a generic orchestrator.
  • The block is back to a pure orchestrator: only items / renderItem / summary / detailPanel / getItemKey / onSelect drive what renders. Consumers compose RoutingSummaryTiles, RoutingDetailPanel, and SignalFeedCard (via toSignalFeedItem) themselves and pass the result through those generic props — see the preview's FullDemo for the pattern.
  • The routing-domain widgets and mappers shipped in 0.4.0 (RoutingSummaryTiles, RoutingDetailPanel, routing-feed.mappers, routing-detail-sections, RoutingSignalsSection, RoutingRelatedList, RoutingTransfersList, RoutingDeadlineBar) are unchanged and still shipped — only the block's own special-casing of them was removed.

0.4.0

  • Wired the routing-domain subcomponents (RoutingSummaryTiles, RoutingDetailPanel, routing-feed.mappers, routing-detail-sections, RoutingSignalsSection, RoutingRelatedList, RoutingTransfersList, RoutingDeadlineBar) into the orchestrator via a new optional routing prop (AttentionRoutingDomainProps). When passed, the block renders the built-in SignalFeedCard feed, KPI tiles, and detail drawer directly from routing-typed props — no fetching or business logic added to the block.
  • The existing generic items / renderItem / summary / detailPanel props are unchanged and still work for non-routing consumers; routing takes precedence when supplied.
  • Added @signalos/signal-feed-card, @signalos/status-badge, @signalos/metric-tile, @signalos/circular-progress, @signalos/sidebar-detail-panel, @signalos/data-primitives, @signalos/lifecycle-timeline, @signalos/badge, and @signalos/skeleton to registryDependencies for the now-wired components.

0.3.4

  • Resolved a merge conflict.

0.3.3

  • Title styling now comes from page-header defaults; className now lands on the block root instead of the inner record list.
  • Use semantic status tokens (text-text-error, bg-bg-warning, border-border-, bg-status-) instead of raw palette scales so client theme overrides restyle status colors.

0.3.2

  • Removed unused Button import from preview file.

0.3.1

  • BREAKING: extra props added

0.3.0

  • BREAKING: Fully componentized. The block's domain-specific local components (RoutingFeedCard, RoutingFlowTimeline, SignalsList, RelatedHypothesisRow, SignalSummaryFallback, and the MetaBox / SectionLabel / EmptyState atoms) were extracted into reusable, domain-agnostic widgets: ranked-list-card, lifecycle-timeline, metric-bar-list, and data-primitives.
  • The block is now a pure orchestrator with a generic, strongly-typed API: segmentFilters / selectFilters arrays replace the hardcoded severity/breaching/owner filter props; title / description / searchPlaceholder / resultLabel are configurable; summary replaces summaryData.
  • Removed the hardcoded filter-option constants and the item cva variants (styling now lives in ranked-list-card).
  • Removed class-variance-authority, @signalos/badge, @signalos/button, @signalos/dropdown-menu, and @signalos/status-badge from the block's direct dependencies (now transitive through the extracted widgets).
  • Removed leftover console.log calls and dead/commented code.

0.2.1

  • BREAKING: Refactored to follow a fully reusable, component-driven architecture
  • Removed domain-specific filter props (severityFilter, breachingFilter, ownerFilter, etc.)
  • Added generic segmentFilters and selectFilters arrays for flexible filtering
  • Added configurable pageTitle and pageDescription props
  • Removed hardcoded filter options and labels from constants
  • Component now acts as a pure orchestrator with no business logic
  • All data, state, and behavior injected via props for maximum reusability
  • Updated TypeScript interfaces to use generic, domain-agnostic types
  • Improved documentation with JSDoc comments

0.1.4

  • Add @signalos/pagination to registryDependencies.

0.1.3

  • Remove unused pagination props from component signature.

0.1.2

  • Remove commented unused PaginationBar import.

0.1.1

  • Content sync fix to bring source in line with published registry payload.

0.1.0

  • Initial release: attention-routing review queue composed from the shared page-header, filter-toolbar, and list-view widgets. Renders items with a severity badge, owner, wait time, and an overflow actions menu.