SideButton Dashboard Knowledge Module
Run Logs — SideButton Dashboard Knowledge Module
The Run Logs module covers three related views for monitoring and inspecting workflow executions: the **Run Log List** (history + live running workflows with KPI stats), the **Run Log Detail** (full …
sidebutton install sidebutton.local What This Is
The Run Logs module covers three related views for monitoring and inspecting workflow executions: the Run Log List (history + live running workflows with KPI stats), the Run Log Detail (full event timeline for a completed run), and the Execution View (real-time streaming log for an in-progress execution). Together they form the execution observability surface of the SideButton dashboard.
URL Patterns
| View | URL | Notes |
|---|---|---|
| Run Log List | /run-logs | No sidebar nav entry — reached via Skills "View Run Logs" link or other in-app navigation |
| Run Log Detail | /run-logs/{id} | id is the run log record ID (not run_id) |
| Execution View | No URL | Internal view state only — triggered by navigateToExecution(workflowId, runId). Cannot be deep-linked |
View 1: Run Log List (RunLogView.svelte)
Page Structure
+--[Header: "Run Logs" h1 + item count badge]--[Clear All] [Reload]--+
| [.kpi-bar] (only when runs exist) |
| [.kpi-hero: time saved today value + label] |
| [.kpi-time-breakdown: This Week / This Month / All Time rows] |
| [.kpi-divider] |
| [.kpi-stats: Runs Today + Success Rate] |
| |
| [Currently Running section] (only when running workflows exist) |
| h2 with .pulse dot + "Currently Running ({count})" |
| [.running-list: .running-card buttons] |
| |
| [.history-section] |
| h2 "History" (only shown when running section is also visible) |
| [.run-list: .run-card buttons] |
| |
| [.empty-state] (when no runs and not loading) |
| [.loading-state] (while fetching) |
+----------------------------------------------------------------------+
Key Elements
Header
| Element | Selector | Notes |
|---|---|---|
| Page heading | h1 containing "Run Logs" | Inside .header-left |
| Item count badge | .item-count | Shows runs.length |
| Clear All button | .btn-secondary in header | Initiates inline confirm flow — does NOT open a dialog |
| Reload button | .reload-btn | Refetches run logs and running workflows immediately |
Clear All Inline Confirm
Clicking "Clear All" does NOT use window.confirm(). It replaces the button area with an inline confirm UI in-place.
| Element | Selector | Notes |
|---|---|---|
| Confirm text | .confirm-text | Text: "Clear all logs?" |
| Confirm delete button | .btn-danger | Text: "Yes, Clear". Executes the clear operation |
| Cancel button | .btn-secondary (inside confirm) | Text: "Cancel". Dismisses confirm without action |
KPI Stats Bar
Visible only when runs.length > 0. Hidden entirely during empty state.
| Element | Selector | Notes |
|---|---|---|
| Stats bar container | .kpi-bar | Horizontal row; absent when no runs |
| Hero value | .kpi-hero-value | Large green text — time saved today (formatted duration string) |
| Hero label | .kpi-hero-label | Text: "Time Saved Today" |
| Time breakdown rows | .kpi-time-breakdown | Contains rows for This Week, This Month, All Time |
| Time row label | .kpi-time-label | e.g., "This Week", "This Month", "All Time" |
| Time row value | .kpi-time-value | Formatted duration for that period |
| Vertical divider | .kpi-divider | Separates hero + breakdown from stats column |
| Stats column | .kpi-stats | Contains Runs Today count + Success Rate percentage |
Running Workflows Section
Shown only when $runningWorkflows.length > 0.
| Element | Selector | Notes |
|---|---|---|
| Section heading | h2 with .pulse dot | Animated dot + "Currently Running ({count})" text |
| Running list | .running-list | Flex/grid container of running cards |
| Running card | button.running-card | Clickable — calls navigateToRunningExecution(run_id, workflow_id) → opens ExecutionView |
| Card header | .running-header | Contains workflow title + StatusBadge showing "running" |
| Card meta | .running-meta | Shows run_id + started time |
History Section
| Element | Selector | Notes |
|---|---|---|
| History section container | .history-section | Always rendered when runs exist |
| History heading | h2 "History" | Only rendered when the Running section is also visible (i.e., hasRunning is true) |
| Run list | .run-list | Container of completed run cards |
| Run card | button.run-card | Clickable — calls navigateToRunLogDetail(run.id) → opens Run Log Detail |
| Card header | .run-header | Contains workflow title + StatusBadge |
| Card meta | .run-meta | Shows run_id + duration + timestamp |
StatusBadge Component
Used on both running cards and history cards.
| Status value | Visual |
|---|---|
"running" | Blue badge (animated) |
"success" | Green badge |
"failed" | Red badge |
Empty and Loading States
| Element | Selector | Notes |
|---|---|---|
| Empty state | .empty-state | Clock SVG icon + h3 "No Run History" + "Workflow executions will appear here." |
| Loading state | .loading-state | Text: "Loading run logs..." |
WebSocket Behavior
- Subscribes to
running-workflows-changedevents on mount - When a running workflow completes, triggers auto-refresh of run logs after a 500ms delay
- Unsubscribes on component destroy
Data Sources
listRunLogs(50)— fetches up to 50 most recent completed run logsgetRunningWorkflows()— fetches currently active executions
View 2: Run Log Detail (RunLogDetailView.svelte)
Page Structure
+--[Back btn] [.header-actions: Delete confirm area]--+
| [.run-info container, max-width 900px] |
| [.title-row: h1 workflow title + StatusBadge] |
| [.meta-grid: auto-fill grid of .meta-item cards] |
| [.params-list] (conditional: when params exist) |
| [h2 "Events ({count})"] |
| [.events-container: .event-item rows] |
| |
| [.not-found] (when ID not found) |
| [.error] (on API error) |
| [.loading] (while fetching) |
+------------------------------------------------------+
Key Elements
Header
| Element | Selector | Notes |
|---|---|---|
| Back button | .back-btn | Text: "Back". Calls navigateToRunLogs() |
| Header actions area | .header-actions | Right side of header — contains delete button or inline confirm |
| Delete button | button inside .header-actions | Initial state — triggers inline confirm |
Delete Inline Confirm
Clicking Delete replaces the button with inline confirm UI in-place. Does NOT use window.confirm().
| Element | Selector | Notes |
|---|---|---|
| Confirm text | .confirm-text | Text: "Delete this log?" |
| Confirm delete button | .btn-danger | Text: "Yes, Delete". Deletes and navigates to run logs list |
| Cancel button | .btn-secondary | Text: "Cancel". Returns to delete button |
After delete completes: navigateToRunLogs() is called automatically.
Run Info
| Element | Selector | Notes |
|---|---|---|
| Info container | .run-info | max-width: 900px, centered |
| Title row | .title-row | Contains h1 (workflow title) + StatusBadge component |
| Meta grid | .meta-grid | grid-template-columns: repeat(auto-fill, minmax(..., 1fr)) |
| Meta item card | .meta-item | One card per metadata field |
| Meta label | .meta-item .label | Uppercase text — field name (e.g., "RUN ID", "DURATION") |
| Meta value | .meta-item .value | Field value |
| Monospace value | .meta-item .value.mono | Used for IDs and timestamps |
Meta grid fields (one card each): Run ID, Workflow ID, Duration, Events, Triggered By, Timestamp.
Parameters Section
Shown only when runLog.params has one or more entries.
| Element | Selector | Notes |
|---|---|---|
| Params list | .params-list | Grid of parameter cards |
| Param card | .param-item | One per parameter |
| Param name | .param-name | Purple text — parameter key |
| Param value | .param-value | Monospace — parameter value |
Events Section
| Element | Selector | Notes |
|---|---|---|
| Section heading | h2 | Text: "Events ({count})" |
| Events container | .events-container | Monospace font family |
| Event row | .event-item | Depth-based left padding (calc(depth * N px)) |
| Event index | .event-index | Row number (0-based) |
| Event type | .event-type | Type label with color class (see below) |
| Event message | .event-message | Content of the event |
Event Type CSS Classes
| Event type | CSS class | Color |
|---|---|---|
workflow_start | .event-run | Blue |
workflow_end | .event-end | Green |
step_start | .event-step | Gray |
step_end | .event-step-end | Purple |
error | .event-error | Red |
log | .event-log | Orange / warning |
Terminal States
| Element | Selector | Notes |
|---|---|---|
| Not found | .not-found | Text: "Run log not found." |
| Error | .error | API error message text |
| Loading | .loading | Text: "Loading run log..." |
View 3: Execution View (ExecutionView.svelte)
Page Structure
+--[.back-btn (disabled while running)] [.header-info] [.header-actions]--+
| [.error-banner] (on error) |
| |
| [.log-header: event count + run ID] |
| [.log-container: scrolling monospace log area] |
| [.empty-state with .spinner] (while waiting for first event) |
| -- or -- |
| [.log-entry rows] |
+----------------------------------------------------------------------------+
Key Elements
Header
| Element | Selector | Notes |
|---|---|---|
| Back button | .back-btn | Disabled (disabled attr) while $isRunning. Enabled when completed |
| Header info | .header-info | Contains h1 (workflow title or "Execution" if title unknown) + status badge |
| Status badge (running) | .status.running | Blue — contains .pulse animated dot |
| Status badge (completed) | .status.completed | Green |
| Header actions | .header-actions | Right side — contains Stop or Done button |
| Stop button | .btn-stop | Red-tinted. Visible while $isRunning. Calls stopWorkflow(runId) |
| Done button | .btn-primary | Visible when completed. Navigates back |
Error Banner
| Element | Selector | Notes |
|---|---|---|
| Error banner | .error-banner | Shown when an error occurs. Contains error message text |
Log Area
| Element | Selector | Notes |
|---|---|---|
| Log header | .log-header | Shows event count + run ID |
| Log container | .log-container | Monospace font, scrollable. Auto-scrolls to bottom as new entries arrive |
| Empty state | .empty-state | Shown when $logs.length === 0. Contains .spinner + "Waiting for execution events..." |
| Spinner | .spinner | Spinning blue circle (CSS animation) |
| Log entry | .log-entry | One row per event. Depth-based left padding |
| Log time | .log-time | Timestamp column |
| Log type | .log-type | Type label with color class (see below) |
| Log message | .log-message | Content text |
Log Entry Type CSS Classes
| Event type | CSS class | Color |
|---|---|---|
workflow_start | .log-run | Blue |
workflow_end (success) | .log-success | Green |
error | .log-error | Red |
step_start / step_end | .log-step | Gray |
result / step_end with result | .log-result | Purple |
log with level warn | .log-warn | Orange |
WebSocket Behavior
- Calls
initWebSocket()on mount — opens real-time connection for log event streaming $effectwatches$logs.length— auto-scrolls.log-containerto bottom on every new entrystopWorkflow(runId)stops the execution and sets$isRunningto false- Back button remains disabled (
disabledattribute) while$isRunning === true
Data Models
RunLogMetadata
| Field | Type | Notes |
|---|---|---|
| id | string | Run log record ID (used in /run-logs/{id} URL) |
| workflow_id | string | Workflow identifier |
| workflow_title | string | Display name |
| status | string | "success", "failed", or "running" |
| duration_ms | number | Total execution time in milliseconds |
| event_count | number | Number of events recorded |
| timestamp | string | ISO 8601 datetime of execution start |
| triggered_by | string | Origin: "user", "agent", etc. |
RunLog (full, fetched for detail view)
| Field | Type | Notes |
|---|---|---|
| metadata | RunLogMetadata | See above |
| events | WorkflowEvent[] | Complete ordered event list |
| params | Record<string, string> | Input parameters provided at execution time |
WorkflowEvent
| Field | Type | Notes |
|---|---|---|
| type | string | workflow_start, workflow_end, step_start, step_end, error, log |
| action_id | string | Workflow ID this event belongs to |
| action_title | string | Workflow display name |
| step_index | number | 0-based step position |
| step_type | string | Step type name |
| step_details | string | Step detail text |
| success | boolean | Outcome — present on workflow_end and step_end events |
| message | string | Error or log message text |
| result | string | Step result text (shown as .log-result / .event-step-end) |
| level | string | For log events: "info", "warn", "error" |
| depth | number | Indentation level — drives left padding in both detail and execution views |
| timestamp | string | ISO 8601 datetime of this specific event |
RunningWorkflow
| Field | Type | Notes |
|---|---|---|
| run_id | string | Active run ID (used to navigate to ExecutionView) |
| workflow_id | string | Workflow identifier |
| workflow_title | string | Display name |
| started_at | string | ISO 8601 datetime when execution started |
States
RunLogView States
| State | Trigger | Visual |
|---|---|---|
| Loading | Initial fetch in progress | .loading-state "Loading run logs..." |
| Empty | Fetched, no runs found | .empty-state with clock icon, h3 "No Run History" |
| Populated (no running) | Runs exist, none active | .kpi-bar + .history-section only |
| Populated (with running) | Runs exist + active runs | .kpi-bar + Running section + h2 "History" + history section |
| Clear All: confirm pending | Clicked "Clear All" | .confirm-text + .btn-danger + .btn-secondary replace button |
| Auto-refresh | Running workflow completes | 500ms delay then data refetched silently |
RunLogDetailView States
| State | Trigger | Visual |
|---|---|---|
| Loading | Fetching run log | .loading "Loading run log..." |
| Loaded | Fetch succeeds | .run-info with title, meta grid, optional params, events |
| Not Found | ID not in records | .not-found "Run log not found." |
| Error | API failure | .error with error message |
| Delete: confirm pending | Clicked Delete | .confirm-text + .btn-danger + .btn-secondary |
| Deleted | Confirmed delete | Navigates to run logs list |
ExecutionView States
| State | Trigger | Visual |
|---|---|---|
| Running (no events yet) | Started, WebSocket connected, no events | .empty-state with .spinner + "Waiting for execution events..." |
| Running (events streaming) | Events arriving via WebSocket | .log-entry rows; auto-scrolling; Back disabled; Stop button visible |
| Completed | Final event received | .status.completed badge; Done button; Back enabled |
| Error | Error event or API failure | .error-banner visible |
| Stopped | User clicked Stop | stopWorkflow() called; $isRunning set false; transitions to completed state |
Common Tasks
- View run history: Navigate to
/run-logs— history cards appear in.run-listsorted most-recent-first - Open a completed run: Click a
.run-cardin the history section → navigates to/run-logs/{id} - Open a live execution: Click a
.running-cardin the Running section → opens ExecutionView with real-time log stream - Read KPI stats: Load
/run-logswith existing runs —.kpi-hero-valueshows time saved today;.kpi-statsshows Runs Today count and Success Rate - Delete a run log: In Run Log Detail, click Delete button →
.confirm-textappears → click "Yes, Delete" → returns to list - Clear all logs: In Run Log List, click "Clear All" → confirm text appears → click "Yes, Clear" → all logs deleted
- Reload logs: Click
.reload-btn— immediately refetches both run logs and running workflows - Stop a running execution: In ExecutionView, click
.btn-stop→stopWorkflow(runId)called → transitions to completed state - Read event details: In Run Log Detail, inspect
.event-itemrows — color-coded by.event-*class; indented bydepth - Read parameters: In Run Log Detail,
.params-listshows input params if any were provided (absent if no params)
Tips
- Running vs History are separate data sources: Running workflows come from
getRunningWorkflows()(live store); history comes fromlistRunLogs(50). They render in separate sections and refresh independently - History heading is conditional: The
h2 "History"heading only renders when there are also running workflows visible. When there are no running workflows, the list renders without a heading - KPI bar is data-dependent:
.kpi-baris absent from the DOM whenruns.length === 0. Do not assert its presence in empty-state tests - Depth field drives indentation: Both
.event-item(detail) and.log-entry(execution) usedepthto calculate left padding — deeper nesting = more indentation - ExecutionView has no URL: It is rendered as an internal view state — navigating directly to any URL will not open it. It must be reached via a running-card click or
navigateToExecution()call - Auto-scroll is reactive: ExecutionView scrolls
.log-containerto the bottom on every new log entry via a Svelte$effect. The container is always showing the latest event during a live run idvsrun_id:RunLogMetadata.idis the database record ID used for the detail URL.run_id(onRunningWorkflow) is the active execution handle. These are distinct fields with different uses- WebSocket refresh delay: When a running workflow completes, RunLogView waits 500ms before refetching — the history list may briefly not show the just-completed run
Gotchas
- Clear All and Delete use INLINE confirm, not
window.confirm(): Clicking these buttons does NOT open a browser dialog. They transform the button area into.confirm-text+.btn-danger+.btn-secondaryin-place. Automation must click through the two-step sequence - ExecutionView Back button is disabled while running:
.back-btnhas thedisabledattribute while$isRunning. Attempting to click it during execution will have no effect — wait for completion or click Stop first - No deep link to ExecutionView:
navigateToExecution()sets internal view state only. There is no URL to construct. Cannot be reached by navigating the browser address bar - Run Log List has no sidebar nav entry:
/run-logsis not listed in the left sidebar. It must be reached from Skills "View Run Logs" or programmatic navigation — do not expect a sidebar button listRunLogs(50)cap: Only the 50 most recent logs are fetched. Older entries are not paginated — they are simply omitted from the list view- Empty event type falls back: If an event's
typedoes not match a known class (.event-run,.event-end, etc.), no color class is applied — the row renders in default text color - Params section absent when no params:
.params-listis not rendered at all whenrunLog.paramsis empty or undefined — do not assert its presence unless params are known to exist - WebSocket in ExecutionView is separate from RunLogView WebSocket: Each view manages its own WebSocket subscription. The execution view streams live events; the list view only subscribes to
running-workflows-changedfor refresh triggers - SPA 404 on direct
/run-logsnavigation: As with all routes, loading/run-logsdirectly in the browser address bar before the SPA shell is loaded returns a Fastify 404 JSON response. Must navigate through the SPA root first