Skip to content

UI: render markdown in cron job prompts and run summaries#48504

Closed
garethdaine wants to merge 4 commits intoopenclaw:mainfrom
garethdaine:fix/cron-markdown-rendering
Closed

UI: render markdown in cron job prompts and run summaries#48504
garethdaine wants to merge 4 commits intoopenclaw:mainfrom
garethdaine:fix/cron-markdown-rendering

Conversation

@garethdaine
Copy link
Copy Markdown

@garethdaine garethdaine commented Mar 16, 2026

The /cron dashboard page now renders markdown content using the existing marked + dompurify pipeline. Job prompts and run summaries display formatted headings, tables, code blocks, blockquotes, lists, and links instead of raw markdown text.

Restructures the job card and run entry layouts to separate the header (title, status, meta) from the markdown body, giving block-level content full card width. Adds responsive styles for tablet and mobile breakpoints.

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Cron job prompts and run summaries render as raw markdown text in the /cron dashboard,
    making formatted content (tables, code blocks, lists, headings) unreadable.
  • Why it matters: Users author markdown prompts for cron jobs and receive markdown summaries from
    agent runs — these should render the same way chat messages do.
  • What changed: Job prompts and run summaries now pass through toSanitizedMarkdownHtml() +
    unsafeHTML() (the same pipeline used by the chat view). Job cards and run entries are restructured
    into header/body/footer sections so markdown block elements get full card width. Responsive styles
    added for tablet and mobile.
  • What did NOT change (scope boundary): No changes to the markdown parser, sanitizer, or allowed
    tags/attributes. No changes to cron business logic, API, or data model. Chat view rendering is
    untouched.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

User-visible / Behavior Changes

  • Cron job prompt text in the Jobs list now renders as formatted markdown (headings, tables, code
    blocks, lists, links, images, blockquotes, horizontal rules).
  • Cron run summaries in Run History now render as formatted markdown.
  • Job cards have a visually distinct header section (darker background, border) separating
    title/status from the prompt body.
  • Run history entries have the same header/body split.
  • On tablet/mobile, card layouts stack vertically; tables and action buttons are horizontally
    scrollable.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • All markdown passes through the existing toSanitizedMarkdownHtml() which uses marked (GFM, with
    raw HTML escaped) + DOMPurify with a strict allowlist of tags and attributes. No new tags or
    attributes were added.

Repro + Verification

Environment

  • OS: macOS (Darwin 25.3.0)
  • Runtime/container: Node 25.1.0, pnpm
  • Model/provider: N/A (UI-only change)
  • Integration/channel: N/A
  • Relevant config: Default gateway config

Steps

  1. Start gateway
  2. Add a cron job with markdown in the message
  3. Open dashboard, navigate to Cron tab
  4. View the job card prompt and any run history summaries

Expected

  • Markdown renders as formatted HTML (headings, tables with borders, styled code blocks,
    blockquotes, lists)
  • Full-width block elements within the card body
  • Responsive layout on mobile (stacked header, scrollable tables/buttons)

Actual

  • Renders plain markdown text

Evidence

Screenshot 2026-03-16 at 21 47 03 Screenshot 2026-03-16 at 21 47 21

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Desktop rendering of job prompt with full markdown (headings, tables, code
    blocks, blockquotes, lists, links, images, HR). Run history summary with same. Mobile/tablet
    responsive layouts at multiple viewport widths.
  • Edge cases checked: Jobs with systemEvent payload (plain text, no markdown applied). Delivery
    section rendering alongside prompt. Empty/missing summaries in run entries.
  • What you did not verify: Light theme rendering. RTL text direction. Extremely long markdown
    content or pathological markdown patterns (covered by existing toSanitizedMarkdownHtml safeguards).
    Pre-existing test failures (2 sort-order tests fail on main).

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert commit; the two files (ui/src/ui/views/cron.ts,
    ui/src/styles/components.css) are self-contained.
  • Files/config to restore: ui/src/ui/views/cron.ts, ui/src/styles/components.css
  • Known bad symptoms reviewers should watch for: Markdown rendering as escaped HTML or raw text in
    cron cards. Layout overflow on mobile. Job cards or run entries with broken grid/flex alignment.

Risks and Mitigations

  • Risk: CSS specificity conflicts with future changes to .chat-text or .list-item base styles.
  • Mitigation: Overrides use compound selectors (.cron-run-entry__body.chat-text table) and are
    placed at the end of components.css with a comment explaining cascade ordering. Mobile-first flex
    layout with min-width: 1101px media query for desktop grid avoids cascade order issues with
    responsive rules.

Copilot AI review requested due to automatic review settings March 16, 2026 21:53
The /cron dashboard page now renders markdown content using the existing
marked + dompurify pipeline. Job prompts and run summaries display
formatted headings, tables, code blocks, blockquotes, lists, and links
instead of raw markdown text.

Restructures the job card and run entry layouts to separate the header
(title, status, meta) from the markdown body, giving block-level content
full card width. Adds responsive styles for tablet and mobile breakpoints.
@garethdaine garethdaine force-pushed the fix/cron-markdown-rendering branch from 3f257c8 to 7563a66 Compare March 16, 2026 21:56
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 16, 2026

Greptile Summary

This PR threads cron job prompts and run summaries through the existing toSanitizedMarkdownHtml() + unsafeHTML() pipeline to render formatted markdown, and restructures job card / run entry layouts into header-body-footer sections for proper block-level content width. The security model is unchanged — all HTML passes through the same DOMPurify allowlist already used by the chat view.

  • Markdown rendering: Job prompts (job.payload.message) and run summaries (entry.summary) are now rendered via toSanitizedMarkdownHtml(), consistent with the chat view. systemEvent payloads correctly bypass markdown and remain plain text.
  • Layout restructure: .cron-job grid and .cron-run-entry flex layouts are split into header/payload(body)/footer regions, with the header using the --secondary background and a bottom border. Responsive breakpoints at 1101 px and 600 px stack/scroll the layouts on smaller viewports.
  • CSS orphan: A rule targeting .cron-run-entry__summary table was added, but the class was renamed to .cron-run-entry__body in the template — the rule is dead code (see inline comment). The cascade-override block at the bottom already covers the .chat-text equivalent.
  • Error double-display: When entry.summary is absent and entry.error is set, the error appears both in the markdown body and as plain text in the meta column. This behaviour existed before the PR but is now more visible since the body section is larger.

Confidence Score: 4/5

  • Safe to merge — no security or logic regressions; one dead CSS rule is the only code-quality issue found.
  • The change reuses a well-tested sanitization pipeline (DOMPurify + marked), touches only two self-contained UI files, and has a clear revert path. The sole issue is an orphaned CSS selector that has no runtime impact. Pre-existing error double-display behaviour is unchanged.
  • ui/src/styles/components.css — orphaned .cron-run-entry__summary table rule should be removed or corrected.

Comments Outside Diff (1)

  1. ui/src/styles/components.css, line 1525-1529 (link)

    Orphaned CSS rule targeting renamed class

    .cron-run-entry__summary no longer exists in the HTML template — the element was renamed to .cron-run-entry__body in cron.ts. This rule has no effect and should either be removed or updated to match the new class name.

    Note: the cascade-override equivalent (.cron-run-entry__body.chat-text table) is already defined further down in the file, so if the intent was always to cover the chat-text case this rule can simply be removed.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: ui/src/styles/components.css
Line: 1525-1529

Comment:
**Orphaned CSS rule targeting renamed class**

`.cron-run-entry__summary` no longer exists in the HTML template — the element was renamed to `.cron-run-entry__body` in `cron.ts`. This rule has no effect and should either be removed or updated to match the new class name.

```suggestion
.cron-run-entry__body table {
  display: table;
  width: 100%;
  max-width: 100%;
}
```

Note: the cascade-override equivalent (`.cron-run-entry__body.chat-text table`) is already defined further down in the file, so if the intent was always to cover the `chat-text` case this rule can simply be removed.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 7563a66

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Cron dashboard UI to render cron job prompts and cron run summaries as sanitized, formatted markdown (matching the chat view’s marked + DOMPurify pipeline), and restructures the job/run card layouts so block-level markdown content can use the full card width with responsive behavior.

Changes:

  • Render cron job prompt (payload.message) and run summary (entry.summary) via toSanitizedMarkdownHtml() + unsafeHTML().
  • Restructure cron job cards and run history entries into header/body sections to better accommodate block markdown.
  • Add/adjust responsive CSS for cron cards (desktop grid vs. stacked mobile/tablet layouts; horizontal scroll for tables/code where needed).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
ui/src/ui/views/cron.ts Switches prompt/summary rendering to sanitized markdown HTML and refactors job/run entry DOM structure.
ui/src/styles/components.css Adds cron-specific layout + markdown presentation overrides and responsive rules for the new structure.
Comments suppressed due to low confidence (2)

ui/src/styles/components.css:1476

  • .cron-job .list-meta still sets grid-area: meta, but .cron-job-header is now a grid without grid-template-areas. Using a named grid-area here can create implicit grid lines/tracks and cause the meta column to be placed unexpectedly. Consider removing grid-area and instead rely on auto-placement (or explicitly set grid-column: 2 / justify-self: end).

.code-block {
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;

ui/src/styles/components.css:1529

  • The selector .cron-run-entry__summary table appears to be dead code now that the run summary markup was replaced with .cron-run-entry__body in the view. Keeping this rule is confusing and makes future styling harder. Remove it or update the selector to the new element/class that actually contains the markdown.
}

.list-item-clickable {
  cursor: pointer;
}

You can also share your feedback on Copilot code review. Take the survey.

Comment thread ui/src/ui/views/cron.ts
Comment thread ui/src/ui/views/cron.ts Outdated
Comment thread ui/src/ui/views/cron.ts
@BunsDev BunsDev self-assigned this Mar 16, 2026
@vincentkoc vincentkoc added the stale Marked as stale due to inactivity label Apr 26, 2026
@vincentkoc
Copy link
Copy Markdown
Member

This assigned pull request has been marked as stale after being open for 27 days.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Apr 27, 2026
@openclaw-barnacle
Copy link
Copy Markdown

This assigned pull request has been automatically marked as stale after being open for 27 days.
Please add updates or it will be closed.

@BunsDev
Copy link
Copy Markdown
Member

BunsDev commented Apr 27, 2026

Superseded by #72777.

I ported the final behavior from this PR onto current main, including the follow-up fixes for the orphaned CSS selector, markdown-link click propagation, and duplicate error rendering. Closing this stale branch so review and CI can continue on the fresh maintainer-owned PR.

Thanks @garethdaine for the original contribution.

@BunsDev BunsDev closed this Apr 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui size: M stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants