Attention Routing 01 - Review queue
v0.5.1Fully 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.
Preview
Install & usage
npx shadcn@4.1.2 add @signalos/attention-routing-01Pulls 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
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| key* | string | - | |
| value* | string | - | |
| onChange* | (value: string) => void | - | |
| options* | readonly AttentionFilterOption[] | - | |
| placeholder | string | undefined | - |
AttentionFilterOption
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | string | - | |
| label* | string | - |
AttentionRouting01Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items* | readonly TData[] | - | The items to render in the queue. |
| title | ReactNode | "Attention Routing" | Page heading. |
| description | ReactNode | - | Sub-heading under the title. |
| loading | boolean | undefined | - | Loading state — renders skeletons via `renderSkeleton`. |
| error | boolean | undefined | - | Error state — renders `errorMessage`. |
| errorMessage | ReactNode | - | |
| segmentFilters | readonly AttentionSegmentFilter[] | undefined | - | Segmented pill-group filters (severity, deadline window, …). |
| selectFilters | readonly AttentionSelectFilter[] | undefined | - | Dropdown filters (owner, role, …). |
| toolbarExtras | ReactNode | - | Additional content rendered inside the FilterToolbar (e.g. action buttons, toggles, badges). |
| searchValue | string | undefined | - | Free-text search value + handler. |
| onSearchChange | ((value: string) => void) | undefined | - | |
| searchPlaceholder | string | undefined | "Search attention items..." | |
| resultLabel | string | undefined | "item" | Singular noun for the result count, e.g. "item". |
| onRefresh | (() => void) | undefined | - | Refresh affordance. |
| isRefreshing | boolean | undefined | - | |
| selectedId | string | 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. |
| emptyTitle | ReactNode | - | Empty-state copy. |
| emptyDescription | ReactNode | - | |
| summary | ReactNode | - | KPI/summary content rendered above the toolbar. |
| showPagination | boolean | undefined | - | Pagination (hidden while searching). |
| currentPage | number | undefined | - | |
| pageSize | number | undefined | - | |
| totalRecords | number | undefined | - | |
| onPageChange | ((page: number) => void) | undefined | - | |
| onPageSizeChange | ((pageSize: number) => void) | undefined | - | |
| detailPanel | ReactNode | - | Detail drawer/panel rendered at the end of the block. |
| className | string | undefined | - | |
| data-testid | string | undefined | - |
RoutingDetailSignal
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| id* | string | - | |
| label* | string | - | |
| severity* | BlackboardSeverity | - | |
| status* | HypothesisStatus | - | |
| created_at* | string | - |
RoutingDetailResponse
| Prop | Type | Default | Description |
|---|---|---|---|
| item* | RoutingFeedItem | - | |
| signals* | RoutingDetailSignal[] | - | |
| transfer_history* | RoutingTransferEntry[] | - | |
| related_hypotheses* | RoutingRelatedHypothesis[] | - |
RoutingFeedItem
| Prop | Type | Default | Description |
|---|---|---|---|
| slot* | RoutingFeedSlot | - | |
| hypothesis* | RoutingFeedHypothesis | - | |
| signal_summary* | RoutingFeedSignalSummary | - | |
| routed_to* | RoutingFeedUser | null | - | |
| routed_to_role* | RoutingFeedRole | null | - | |
| lifecycle* | RoutingFeedLifecycle | - |
RoutingTransferEntry
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| id* | string | - | |
| status* | SlotStatus | - | |
| priority_rank* | number | - | |
| priority_score* | number | - | |
| created_at* | string | - | |
| escalated_from* | string | null | - |
RoutingFeedHypothesis
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
| Prop | Type | Default | Description |
|---|---|---|---|
| user_id* | string | - | |
| email* | string | - | |
| full_name* | string | - |
RoutingFeedRole
| Prop | Type | Default | Description |
|---|---|---|---|
| role_id* | string | - | |
| role_name* | string | - |
RoutingFeedLifecycle
| Prop | Type | Default | Description |
|---|---|---|---|
| signal_to_hypothesis_seconds* | number | null | - | |
| hypothesis_to_routing_seconds* | number | null | - | |
| age_seconds* | number | - |
AttentionSlot
| Prop | Type | Default | Description |
|---|---|---|---|
| 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_id | string | null | undefined | - |
SignalSummary
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | undefined | - | |
| cagg | number | undefined | - | |
| sufficiency | number | undefined | - | |
| signal_count | number | undefined | - | |
| severity | BlackboardSeverity | undefined | - | |
| domain | string | undefined | - | |
| cluster | string | undefined | - | |
| equilibrium_state | string | undefined | - | |
| contributing_signals | ContributingSignal[] | undefined | - |
ContributingSignal
| Prop | Type | Default | Description |
|---|---|---|---|
| role* | string | - | |
| cluster* | string | - | |
| deviation* | number | - | |
| metric_id* | string | - | |
| signal_id* | string | - | |
| confidence* | number | - |
RoutingFlowResponse
| Prop | Type | Default | Description |
|---|---|---|---|
| hypothesis_id* | string | - | |
| timeline* | RoutingFlowEvent[] | - |
RoutingFlowEvent
| Prop | Type | Default | Description |
|---|---|---|---|
| at* | string | - | |
| event* | RoutingFlowEventType | - | |
| detail* | Record<string, unknown> | - |
RoutingDashboardSummary
| Prop | Type | Default | Description |
|---|---|---|---|
| in_flight_total* | number | - | |
| by_status* | RoutingSummaryStatusCounts | - | |
| by_severity* | RoutingSummarySeverityCounts | - | |
| by_role* | RoutingSummaryRoleCount[] | - | |
| deadlines* | RoutingSummaryDeadlines | - | |
| throughput_last_24h* | RoutingSummaryThroughput | - |
RoutingSummaryStatusCounts
| Prop | Type | Default | Description |
|---|---|---|---|
| ACTIVE | number | undefined | - | |
| IN_PROGRESS | number | undefined | - | |
| EXPIRED | number | undefined | - | |
| ESCALATED | number | undefined | - |
RoutingSummarySeverityCounts
| Prop | Type | Default | Description |
|---|---|---|---|
| critical | number | undefined | - | |
| high | number | undefined | - | |
| medium | number | undefined | - | |
| low | number | undefined | - | |
| info | number | undefined | - |
RoutingSummaryRoleCount
| Prop | Type | Default | Description |
|---|---|---|---|
| role_id* | string | - | |
| role_name* | string | - | |
| count* | number | - |
RoutingSummaryDeadlines
| Prop | Type | Default | Description |
|---|---|---|---|
| breaching_within_1h* | number | - | |
| breaching_within_4h* | number | - | |
| breaching_within_24h* | number | - | |
| past_deadline* | number | - |
RoutingSummaryThroughput
| Prop | Type | Default | Description |
|---|---|---|---|
| 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
routingprop (AttentionRoutingDomainProps) added in 0.4.0. WiringSignalFeedCard,RoutingSummaryTiles, andRoutingDetailPaneldirectly 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/onSelectdrive what renders. Consumers composeRoutingSummaryTiles,RoutingDetailPanel, andSignalFeedCard(viatoSignalFeedItem) themselves and pass the result through those generic props — see the preview'sFullDemofor 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 optionalroutingprop (AttentionRoutingDomainProps). When passed, the block renders the built-inSignalFeedCardfeed, 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/detailPanelprops are unchanged and still work for non-routing consumers;routingtakes 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/skeletontoregistryDependenciesfor the now-wired components.
0.3.4
- Resolved a merge conflict.
0.3.3
- Title styling now comes from
page-headerdefaults;classNamenow 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
Buttonimport 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 theMetaBox/SectionLabel/EmptyStateatoms) were extracted into reusable, domain-agnostic widgets:ranked-list-card,lifecycle-timeline,metric-bar-list, anddata-primitives. - The block is now a pure orchestrator with a generic, strongly-typed API:
segmentFilters/selectFiltersarrays replace the hardcoded severity/breaching/owner filter props;title/description/searchPlaceholder/resultLabelare configurable;summaryreplacessummaryData. - Removed the hardcoded filter-option constants and the item
cvavariants (styling now lives inranked-list-card). - Removed
class-variance-authority,@signalos/badge,@signalos/button,@signalos/dropdown-menu, and@signalos/status-badgefrom the block's direct dependencies (now transitive through the extracted widgets). - Removed leftover
console.logcalls 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
segmentFiltersandselectFiltersarrays for flexible filtering - Added configurable
pageTitleandpageDescriptionprops - 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, andlist-viewwidgets. Renders items with a severity badge, owner, wait time, and an overflow actions menu.