Skip to content

Keep the trace console usable without external assets - #631

Open
yorzi wants to merge 2 commits into
activeagents:mainfrom
yorzi:fix/offline-trace-console
Open

yorzi wants to merge 2 commits into
activeagents:mainfrom
yorzi:fix/offline-trace-console

Conversation

@yorzi

@yorzi yorzi commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Refs #384. This covers only the "console CDN deps" finding. The 500-row cap, the dark-mode TracesView gaps and the tool_usage key drift are separate and stay open.

The routes describe the server-rendered console (<mount>/console/traces) as "Same data, no JavaScript — useful when the bundle can't run". Its layout, however, loaded Tailwind from cdn.tailwindcss.com and Turbo and Stimulus from unpkg.com. Offline, on an air-gapped network or behind a strict CSP, the console rendered unstyled. Its trace rows expanded through a Stimulus controller, so a trace's details could not be opened at all.

What changes

  • layouts/action_agent/application.html.erb: no scripts and no external stylesheets. Styles come from a console-scoped inline partial (traces/_styles.html.erb), with light and dark tokens and a narrow-screen layout.
  • traces/index.html.erb: each trace is a native <details> with an Open trace link to the standalone traces#show page. Expanding a trace needs no JavaScript.
  • traces/_summary.html.erb (new): the 24-hour summary tiles are shared by index and metrics instead of being duplicated.
  • traces/show, _trace_detail, metrics: rewritten with semantic markup (dl, table with scoped headers, section labels) and no Tailwind classes. The span timeline keeps the same offset math.
  • Refresh: main reloaded the index every 30 s through Turbo, which also collapsed any open trace. Refresh is now opt-in: Auto-refresh adds ?refresh=30, ?refresh=60 is also accepted, and either one renders <meta http-equiv="refresh">. The controller accepts only "30" and "60", so the value can't carry a url=. The refresh links are built from request.path plus the query string, never url_for(params), so host or script_name in the query cannot redirect them. Existing filters such as status=error are kept.
  • Docs: a "Trace console without JavaScript" section, and the stale CDN caveats removed from the "CDN assets" bullet and from the generated initializer's config.layout comment.

Behaviour notes

  • A host that sets ActionAgent.layout (the old initializer comment recommended this for CSP-strict setups) replaces the engine layout, which now carries the console's styles and refresh controls. Such hosts can drop the setting, and the initializer comment says so.
  • Under a CSP whose style-src lacks 'unsafe-inline', the inline <style> and the span bars' style attributes are still blocked. That is unchanged from before. Supporting a nonce would be a follow-up.

Checks

  • actionagent/test/trace_console_test.rb (new, 4 tests): no script, stylesheet link or data-controller on list, detail and metrics pages; native details with a standalone link; escaped error text; opt-in refresh limited to 30 and 60, with 0, -1, 1;url=https://example.com and abc rejected; filters kept; empty states. With main's views restored, 3 of 4 fail. Removing the 30/60 check fails the refresh test.
  • Browser: the dummy app on loopback, page loaded and then network emulation set to Offline. The only requests were same-origin (document, favicon). The page is styled, and a trace expands with its span timeline.
  • bin/test: 4096 runs, 0 failures, 0 errors (the docs follow-up commit changes no code; the install generator tests still pass). bin/rubocop reports no offenses.

🤖 Generated with Claude Code

yorzi added 2 commits October 24, 2026 12:34
The server-rendered fallback loads Tailwind, Turbo and Stimulus from
CDNs, so expanding a trace needs a network and JavaScript. Ship small
console-scoped styles and use native details with standalone links.

Make refresh opt-in through bounded HTML refresh intervals, preserving
filters without interpreting query parameters as routing options.
Cover list, detail, metrics, empty states and escaped trace contents.

Refs activeagents#384
The self-hosted observability guide and the generated initializer still
said the trace console loads Tailwind, Turbo and Stimulus from CDNs and
recommended a custom layout to avoid them. Neither is true any longer,
and a custom layout now drops the console's built-in styles.
@TonsOfFun

Copy link
Copy Markdown
Contributor

Thanks @yorzi — this looks good to me. Dropping the CDN Tailwind/Turbo/Stimulus from the console layout is the right call for a page whose whole selling point is "no JavaScript", and moving the expand to native <details> makes that actually true. Good catch on the 30s Turbo refresh collapsing open rows, and I appreciate that the refresh param is allowlisted to 30/60 and built from request.path rather than url_for(params). The style-src nonce caveat being called out explicitly rather than papered over is appreciated too. CI is green.

Before I merge: would you like a full review pass on this, or are you comfortable with it going in as-is? Also — you noted the 500-row cap, the dark-mode TracesView gaps and the tool_usage key drift from #384 are still open. Are you planning to pick any of those up next, or should I treat this PR as the complete scope here?

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