Skip to content

feat(cli): Add shiny inspect command with Reactlog visualization and interactive HTML export - #2467

Draft
karangattu wants to merge 60 commits into
mainfrom
feat-shiny-inspect
Draft

karangattu wants to merge 60 commits into
mainfrom
feat-shiny-inspect

Conversation

@karangattu

@karangattu karangattu commented Aug 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR adds shiny inspect, a CLI command that helps developers understand how a Shiny app reacts to user actions.

It shows dependencies, records browser sessions, replays reactive events, and creates reports for debugging or documentation.

Open the Reactlog report - Core Mode

Open another live Reactlog report - Express Mode

Quick start

Create an interactive HTML report:

shiny inspect app.py --html reactlog.html

Or run an app with live Reactlog enabled:

shiny run --reactlog app.py
More command examples

Inspect an app in the terminal

shiny inspect app.py

Run an app with live Reactlog support

shiny run --reactlog app.py

Record browser actions and video

shiny inspect app.py --record --video demo.webm --html session.html

Create a light-themed report

shiny inspect app.py --html report.html --theme light

Import a Shiny for R Reactlog file

shiny inspect legacy_reactlog.json --html imported-report.html

Export structured JSON

shiny inspect app.py --format json > graph.json

Export a Mermaid diagram

shiny inspect app.py --format mermaid > graph.md

Export a Graphviz DOT diagram

shiny inspect app.py --format dot > graph.dot

Show the event stream in the terminal

shiny inspect app.py --reactlog

Simulate input changes

shiny inspect app.py --input price=30 --input units=2
What the interactive report shows
  • The full graph appears when the report opens.
  • The timeline groups related events into action bursts.
  • The Live Story explains each reactive step in plain language.
  • Selecting an event or node updates the timeline, graph, and causal inspector.
  • The causal inspector answers “Why did this run?” and “Why did this not run?”
  • Input nodes focus on downstream effects. Calculation and output nodes focus on upstream causes.
  • Filtering by lineage keeps focus on selected ancestors and descendants during timeline playback.
  • Recorded video stays synchronized with the reactive timeline.
  • Users can open another Reactlog JSON file from the report.
New Reactlog features
  • Live app shortcuts:
    • Run with shiny run --reactlog app.py.
    • Press Cmd+F3 (macOS) or Ctrl+F3 (Windows/Linux) in the running app to open the report at /__reactlog__.
    • Press Cmd+Shift+F3 or Ctrl+Shift+F3 to save a bookmark label during an active session.
  • User marks:
    • Call reactive.mark("label") in Python code to add timeline bookmarks.
    • Marks display as pins directly on the timeline bar.
  • Isolated edge styling:
    • Values read inside with reactive.isolate(): display as dashed lines with isolated arrowheads in the graph.
  • Keyboard navigation in reports:
    • Left / Right or h / l: Step backward and forward.
    • Up / Down or k / j: Jump between action bursts.
    • Space: Play and pause timeline playback.
    • Home / End: Jump to start or end.
    • ?: Open keyboard shortcut reference.
  • Hotspot badges:
    • Nodes that run repeatedly display run count badges.
    • Nodes running 4 or more times show a flame icon badge with run counts to highlight reactive bottlenecks.
Compatibility and correctness
  • Imports Shiny for R Reactlog JSON fields and normalizes epoch timestamps.
  • Models @reactive.event() triggers as dependencies while keeping body reads isolated.
  • Respects with reactive.isolate(): blocks during static analysis.
  • Escapes imported labels and details before adding them to HTML.
  • Supports dark, light, and automatic themes.
  • Uses consistent Lucide SVG icons throughout the report.
CLI behavior
  • --format controls the selected output, even when --record is present.
  • Recording controls appear only when the report includes a recording.
  • --html writes to reactlog.html when the user does not supply an output path.
  • --record writes video to recording.webm when the user does not supply a path.
  • --reactlog enables live Reactlog recording on shiny run.

@karangattu
karangattu marked this pull request as draft August 23, 2026 02:17
karangattu and others added 28 commits August 24, 2026 14:18
…llisions, deduplicate inputs, and fix relative video paths
… unresolved inputs, and use synthetic IDs for graph export
…cs, and regressions

- Passive headless recording by default; require --auto-interact for auto fills/clicks
- Redact passwords and secret tokens at collection time before entering recorded actions
- Distinguish observed execution vs inferred evaluation and update did-not-run messaging
- Use precomputed action waves with wave-scoped causal explanations
- Remove inline JavaScript event handler string interpolation for XSS protection
- Revert serialize_dtype signature in _tbl_data.py to nw.Series
- Use concise trigger names on timeline burst anchors with ellipsis and max-width constraints
- Store full user action descriptions on title/tooltip and live story
- Coalesce consecutive same-timestamp click/input bursts
- Require significant idle duration and distance before displaying idle gap indicators
karangattu and others added 18 commits September 25, 2026 12:31
…styling, keyboard navigation, and bottleneck badges
This change fixes reactlog mark timing by normalizing and sorting mark timestamps consistently and by converting app-side timestamps to page-relative values when needed. It also avoids duplicate mark collection during session recording and adds a regression test covering the express showcase reactlog features. The repo config now ignores the generated dist2 directory and excludes it from pyright checks.
- `shiny inspect --html app.py` no longer writes the report over app.py;
  refuse to overwrite the inspected file in any case
- Always route /__reactlog__ and check reactlog_enabled per request, so
  run_app(reactlog=...) and --no-reactlog take effect on an existing App
- Don't treat proxied loopback requests as local; app source is only
  served to direct local requests
- Use relative reactlog URLs so Cmd+F3 works under a path prefix

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants