Execution detail workspace
https://fve.meiermade.com/components/page-examples/execution-detail?state=error&item=run-2410 Workspace
Customer analytics
This view could not be loaded
Your selection is preserved. Try loading it again.
open System
open FSharp.ViewEngine
open Acme.Components.Primitives
open Acme.Components.Application
open Acme.Components.Documentation
open type Html
open type Svg
open type Datastar
type ExamplePage =
| DependencyGraph
| ExecutionDetail
| FinancialReporting
| Messaging
| Operations
| Scheduling
| MediaManagement
type ReviewState =
| Setup
| Ready
| Loading
| Empty
| Failed
type ExampleQuery =
{ state: ReviewState
item: string
view: string
range: string }
let defaultQuery =
{ state = Ready
item = ""
view = ""
range = "" }
let slug =
function
| DependencyGraph -> "dependency-graph"
| ExecutionDetail -> "execution-detail"
| FinancialReporting -> "financial-reporting"
| Messaging -> "messaging"
| Operations -> "operations-dashboard"
| Scheduling -> "scheduling"
| MediaManagement -> "media-management"
let title =
function
| DependencyGraph -> "Dependency graph"
| ExecutionDetail -> "Execution detail"
| FinancialReporting -> "Financial reporting"
| Messaging -> "Messaging"
| Operations -> "Operations dashboard"
| Scheduling -> "Scheduling"
| MediaManagement -> "Media management"
let url page =
"/components/page-examples/" + slug page
let stateKey =
function
| Setup -> "setup"
| Ready -> "ready"
| Loading -> "loading"
| Empty -> "empty"
| Failed -> "error"
let queryUrl page query =
let pairs =
[ "state", stateKey query.state
"item", query.item
"view", query.view
"range", query.range ]
url page
+ "?"
+ (pairs
|> List.filter (snd >> String.IsNullOrEmpty >> not)
|> List.map (fun (key, value) -> key + "=" + Uri.EscapeDataString value)
|> String.concat "&")
let link (href: string) (label: string) : HtmlElement =
a {
_href href
_class
"font-medium text-[var(--fve-brand-text)] underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-[var(--fve-brand-ring)]"
label
}
let section (heading: string) (content: HtmlElement) =
Section.create (SectionHeader.create heading |> SectionHeader.withDivider) content
|> Section.render id
let details (fields: (string * string) list) =
DescriptionList.create [ for label, value in fields -> DetailField.text label value ]
|> DescriptionList.withColumns DescriptionListColumns.Three
|> DescriptionList.render
let reviewStates page =
(if page = Operations then [ Setup, "Setup" ] else [])
@ [ Ready, "Populated"; Loading, "Loading"; Empty, "Empty"; Failed, "Error" ]
let stateContent page query content =
match query.state with
| Setup
| Ready -> content
| Loading ->
div {
_class "p-8"
LoadingIndicator.create ("Loading " + (title page).ToLowerInvariant())
|> LoadingIndicator.withVisibleLabel
|> LoadingIndicator.render
}
| Empty ->
EmptyState.create "Nothing to show yet" "Change the current selection or return to the populated workspace."
|> EmptyState.withActions (link (queryUrl page { query with state = Ready }) "Return to workspace")
|> EmptyState.render
| Failed ->
Notice.create
"workspace-error"
"This view could not be loaded"
(p { "Your selection is preserved. Try loading it again." })
|> Notice.withTone Tone.Critical
|> Notice.withActions (link (queryUrl page { query with state = Ready }) "Try again")
|> Notice.render
/// Place durable workspace identity above the scrollable destination list.
let sideNavWorkspace (name: string) =
div {
p {
_class "text-xs font-semibold uppercase tracking-wide text-[var(--fve-muted-text)]"
"Workspace"
}
p {
_class "mt-1 truncate text-sm font-semibold"
name
}
}
let workspace page heading subtitle canvas actions content =
let product, workspaceName, destinations =
match page with
| DependencyGraph
| ExecutionDetail ->
"Relay", "Customer analytics", [ DependencyGraph, "Dependencies"; ExecutionDetail, "Executions" ]
| FinancialReporting -> "Ledger", "Northwind Studio", [ FinancialReporting, "Overview" ]
| Messaging -> "Gather", "Northwind Outdoor", [ Messaging, "Messages" ]
| _ ->
"Fieldwork", "Northwind Outdoor", [ Operations, "Overview"; Scheduling, "Schedule"; MediaManagement, "Photos" ]
let items =
[ for destination, label in destinations -> SideNavItem.create destination label ]
let navigation =
SideNav.create
(slug page + "-nav")
(product + " navigation")
(SideNavHeader.create product)
[ SideNavSection.ungrouped items ]
|> SideNav.withCurrent page
|> SideNav.withWidth SideNavWidth.Narrow
|> SideNav.withContext (sideNavWorkspace workspaceName)
|> SideNav.withMobileContext (sideNavWorkspace workspaceName)
|> SideNav.withFooter (
div {
_class "flex min-w-0 items-center gap-3"
Avatar.create "Andy Meier" "AM" |> Avatar.render
p {
_class "truncate text-sm font-medium"
"Andy Meier"
}
}
)
let header =
PageHeader.create heading
|> PageHeader.withSubtitle subtitle
|> PageHeader.withActions (ActionCluster.create (slug page + "-actions") actions)
let topBar =
PageTopBar.create ()
|> PageTopBar.withContent (
div {
_class "flex min-h-[var(--fve-shell-bar-min-height)] items-center px-4 sm:px-6 lg:px-8"
Breadcrumbs.create
(slug page + "-breadcrumbs")
(product + " breadcrumb")
[ BreadcrumbItem.create page product; BreadcrumbItem.create page heading ]
|> Breadcrumbs.render url
}
)
let body =
Page.create header content
|> Page.withTopBar topBar
|> Page.withWidth PageWidth.Full
|> Page.withBodyLayout (
if canvas then
PageBodyLayout.Canvas
else
PageBodyLayout.Padded
)
|> Page.render id
AppShell.create (slug page + "-shell") navigation body
|> AppShell.withTheme (
ComponentsTheme.sky
|> ComponentsTheme.withDensity Density.Compact
|> ComponentsTheme.withControlSize ControlSize.Small)
|> AppShell.withBoundary AppShellBoundary.Container
|> AppShell.asPreview (product + " workspace")
|> AppShell.render url
type DependencyNode =
{ key: string
name: string
operation: string
status: string
x: int
y: int
run: string }
let dependencyNodes =
[ { key = "customers"
name = "source.customers"
operation = "Fetch customer records"
status = "Succeeded"
x = 1
y = 2
run = "run-2401" }
{ key = "orders"
name = "source.orders"
operation = "Fetch recent orders"
status = "Succeeded"
x = 1
y = 15
run = "run-2402" }
{ key = "customer-load"
name = "warehouse.customers"
operation = "Load customer dimension"
status = "Succeeded"
x = 20
y = 2
run = "run-2407" }
{ key = "order-load"
name = "warehouse.orders"
operation = "Load order facts"
status = "Failed"
x = 20
y = 15
run = "run-2408" }
{ key = "revenue"
name = "reporting.revenue"
operation = "Build revenue summary"
status = "Blocked"
x = 39
y = 2
run = "run-2410" }
{ key = "retention"
name = "reporting.retention"
operation = "Calculate returning customers"
status = "Succeeded"
x = 39
y = 15
run = "run-2411" } ]
let nodeStatus status =
Status.create status
|> Status.withTone (
match status with
| "Succeeded" -> Tone.Positive
| "Failed" -> Tone.Critical
| _ -> Tone.Warning
)
|> Status.render
let selectedNode query =
dependencyNodes
|> List.tryFind (fun node -> node.key = query.item || node.run = query.item)
|> Option.defaultValue dependencyNodes[2]
type TraceSpan =
{ id: string
operation: string
service: string
start: int
duration: int
depth: int }
let traceSpans =
[ { id = "worker"
operation = "Execute dependency"
service = "worker-01"
start = 0
duration = 1240
depth = 0 }
{ id = "auth"
operation = "Check credentials"
service = "identity"
start = 20
duration = 90
depth = 1 }
{ id = "fetch"
operation = "GET /customers"
service = "source-api"
start = 140
duration = 460
depth = 1 }
{ id = "parse"
operation = "Decode 1,842 records"
service = "worker-01"
start = 600
duration = 120
depth = 1 }
{ id = "write"
operation = "INSERT customer_dimension"
service = "postgres"
start = 740
duration = 420
depth = 1 }
{ id = "commit"
operation = "Commit and publish"
service = "worker-01"
start = 1160
duration = 80
depth = 1 } ]
let spansFor node =
let order = node.name.Contains("orders", StringComparison.Ordinal)
traceSpans
|> List.map (fun span ->
{ span with
operation =
match span.id with
| "fetch" when order -> "GET /orders"
| "parse" when order -> "Decode 962 order records"
| "write" when order -> "INSERT order_facts"
| "commit" when node.status = "Failed" -> "Roll back transaction"
| _ -> span.operation })
let executionContent query =
let node = selectedNode query
let spans = spansFor node
let selectedSpan =
spans
|> List.tryFind (fun span -> span.id = query.view)
|> Option.defaultValue spans[4]
let failed = node.status = "Failed"
div {
_class "grid gap-6"
details
[ "Dependency", node.name
"Worker", "warehouse-worker-01"
"Started",
(if node.status = "Blocked" then
"Not started"
else
"17 Sep 2026, 09:42:18 UTC")
"Duration", (if node.status = "Blocked" then "—" else "1.24 s")
"Attempt", (if node.status = "Blocked" then "0" else "1")
"Execution", node.run ]
div {
_class "flex flex-wrap items-center gap-3"
nodeStatus node.status
link (queryUrl DependencyGraph { defaultQuery with item = node.key }) "View in dependency graph"
}
if node.status = "Blocked" then
Notice.create
"blocked-run"
"Waiting for an upstream dependency"
(p { "warehouse.orders must succeed before this execution can start." })
|> Notice.withTone Tone.Warning
|> Notice.withActions (
link (queryUrl ExecutionDetail { defaultQuery with item = "run-2408" }) "Inspect failed dependency"
)
|> Notice.render
else
section
"Trace waterfall"
(div {
_class "grid gap-3"
p {
_class "text-sm text-[var(--fve-muted-text)]"
"Select a span to inspect its timing and service. All timings are relative to execution start."
}
div {
_role "region"
_ariaLabel "Trace timings"
_tabindex 0
_class "overflow-x-auto"
Table.create
"Execution spans"
[ Table.column "Operation" (fun (item: TraceSpan) ->
div {
_style $"padding-left:{item.depth}rem"
link (queryUrl ExecutionDetail { query with view = item.id }) item.operation
})
|> Table.asRowHeader
Table.column "Service" (fun item -> text item.service)
Table.column "Start" (fun item -> text $"{item.start} ms") |> Table.alignEnd
Table.column "Duration" (fun item -> text $"{item.duration} ms")
|> Table.alignEnd
Table.column "0 — 620 — 1,240 ms" (fun item ->
div {
_ariaHidden "true"
_class "relative h-6 min-w-64 rounded bg-[var(--fve-surface-subtle)]"
div {
_class (
if failed && item.id = "write" then
"absolute top-1 h-4 rounded bg-[var(--fve-critical-text)]"
else
"absolute top-1 h-4 rounded bg-[var(--fve-brand-solid)]"
)
_style (
sprintf
"left:%.2f%%;width:%.2f%%"
(float item.start / 12.4)
(float item.duration / 12.4)
)
}
}) ]
spans
|> Table.withDensity Density.Compact
|> Table.render
}
})
section
("Span · " + selectedSpan.operation)
(details
[ "Service", selectedSpan.service
"Start offset", $"{selectedSpan.start} ms"
"Duration", $"{selectedSpan.duration} ms"
"Span ID", selectedSpan.id
"Result",
(if failed && selectedSpan.id = "write" then
"Failed · unique constraint"
else
"Succeeded")
"Execution", node.run ])
section
"Correlated logs"
(ul {
_class "divide-y divide-[var(--fve-border)] font-mono text-xs"
for time, level, message in
[ "09:42:18.000", "INFO", "Execution started on warehouse-worker-01"
"09:42:18.600",
"INFO",
(if failed then
"Fetched 962 order records"
else
"Fetched 1,842 source records")
"09:42:19.160",
(if failed then "ERROR" else "INFO"),
(if failed then
"Duplicate order key: ORD-1042. Transaction rolled back."
else
"Committed 1,842 records to customer_dimension") ] do
li {
_class "grid gap-2 py-3 sm:grid-cols-[8rem_4rem_1fr]"
span { time }
strong { level }
span {
_class "break-words"
message
}
}
})
}
let executionDetail query =
let node = selectedNode query
workspace
ExecutionDetail
node.run
(node.name + " · Production")
false
[ ApplicationAction.link (queryUrl DependencyGraph { defaultQuery with item = node.key }) "View dependency" ]
(stateContent ExecutionDetail query (executionContent query))
div { _class "h-[44rem]"; executionDetail defaultQuery }
|> Browser.create
|> Browser.withAddress "https://fve.meiermade.com/components/page-examples/execution-detail?state=ready"
|> Fixture.browser "page-workspace" "Workspace" "/components/page-examples/execution-detail?state=ready"
|> Fixture.render