Skip to content

feat(dashboards): add section header tile to the add menu#19

Open
lordspline wants to merge 4 commits into
masterfrom
capy/feat-dashboard-section-headers
Open

feat(dashboards): add section header tile to the add menu#19
lordspline wants to merge 4 commits into
masterfrom
capy/feat-dashboard-section-headers

Conversation

@lordspline

@lordspline lordspline commented Jun 17, 2026

Copy link
Copy Markdown

Problem

PostHog dashboards expose Insight, Text card, and Button tiles via the Add menu, but there's no first-class way to group tiles into labeled sections. The documented workaround — add a Text card, type a markdown heading, toggle transparent background, then resize to full width and drag into place — works but isn't discoverable. This adds a first-class Section header tile, inspired by PostHog/posthog#58307.

Changes

A Section header is not a new model, migration, or DB field — it is an ordinary transparent text tile whose markdown body is a heading, an optional description paragraph, and a trailing --- divider. This reuses the existing text-tile persistence and rendering end to end:

  • Add → Section header menu item (between Text card and Button) opens a compact Title + optional Description form.
  • On save it composes the markdown body, sets transparent_background = true, and places the tile full-width (w=12) on a new row by default — no resizing or dragging needed.
  • The existing TextCard renders it unchanged: transparent (no card border/background), a bold heading, the description, and a full-width hairline divider (the trailing ---) that separates the section from the tiles below.
  • Editing a section reopens the same compact form, pre-filled by parsing the title/description back out of the body; tiles that are not section-shaped fall back to the normal text editor.
  • Duplication, move, delete + undo, permissions (Editor gate), and templates are inherited for free because it is a normal text tile.
  • Inputs are normalized to a single line and a leading list/quote/heading marker on the description is neutralized so the section shape stays intact; normal punctuation is preserved verbatim and rendering safety matches existing text cards.
  • Analytics emit a dashboard section header saved event mirroring the existing tile events.

Two visual treatments were prototyped against a realistic seeded dashboard before implementation — heading + description with a bottom divider vs. without. The divider treatment was chosen because it reads more clearly as a section break and matches PostHog's divider-heavy visual language.

Why no schema change

Investigation confirmed the existing representation (Text.body + DashboardTile.transparent_background + layouts) reliably preserves every required behavior — creation, full-width placement, editing round-trip, duplication, deletion, and serialization — so no new field or migration was added.

How did you test this code?

I am an agent; these are the automated checks I actually ran (no manual testing claimed):

  • Frontend unit tests (jest): sectionHeaderMarkdown.test.ts (compose/parse/detection, escaping and shape safety) and sectionHeaderModalLogic.test.ts (default full-width/new-row layout, narrow xs layout, create/edit payloads, validation, analytics) — 36 tests passing.
  • Backend API tests (pytest): test_dashboard_section_headers.py — creation + full-width transparent persistence, serialization, in-place editing, dashboard duplication, soft delete, and a non-editor 403 permission check — 6 tests passing.
  • Lint + types: oxlint clean on the changed files; tsgo typecheck reports no errors.
  • Automated UI verification (desktop automation, not manual): on a seeded dashboard, added a Section header via the Add menu, confirmed exactly one full-width transparent tile with a bottom divider was created (no double-submit), dragged it to the top in Edit layout mode, and reopened the pre-filled edit form to rename it.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

No user-facing docs change required for this fork experiment.

🤖 Agent context

Autonomy: Human-driven (agent-assisted) — directed by the requesting user.

Built with Capy (Captain agent plus automated desktop verification). Key decisions:

  • Implemented Section headers purely on the existing text-tile API (no model/migration/field), matching the issue's stated direction and keeping duplication/delete/permissions/templates working for free.
  • Composed the divider as a trailing markdown --- rather than a renderer-level treatment, so the existing TextCard renders sections with zero rendering changes and existing dashboards are untouched.
  • Treated Title/Description as plain text: rather than backslash-escaping (the markdown parser drops escaped punctuation), inputs are whitespace-normalized and only a leading block marker on the description is neutralized. Empirically, normal titles with & ( ) : -> % - # > round-trip verbatim.
  • Caught and fixed a double-submit during UI verification (the Save button had both an onClick and a form htmlType="submit").

Agent-authored — requires human review; do not self-merge.

…tile type composed on the text‑

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@lordspline lordspline added the capy Generated by capy.ai label Jun 17, 2026 — with Capy AI
@capy-ai capy-ai Bot changed the title feat(dashboards): Add Section header tile type feat(dashboards): add section header tile to the add menu Jun 17, 2026

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Added 4 comments

Comment thread frontend/src/lib/components/Cards/SectionHeader/sectionHeaderModalLogic.ts Outdated
Comment thread frontend/src/lib/components/Cards/SectionHeader/sectionHeaderMarkdown.ts Outdated
lordspline and others added 2 commits June 17, 2026 23:51
…-trip safely

- await the dashboard update via its success/failure actions so a failed save keeps the modal open and toasts, instead of closing optimistically
- reset the new-section form after a successful save so the shared keyed logic reopens empty
- preserve inline markdown in title/description across edits by serializing marks back to source
- reject descriptions that would parse as block markdown (lists, headings, quotes, thematic breaks) instead of corrupting them, and stop stripping non-block characters like #growth
- require the canonical signature (h2 + optional paragraph + trailing divider) so ordinary transparent text cards no longer route through the section editor

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Added 1 comment

Comment thread frontend/src/lib/components/Cards/SectionHeader/sectionHeaderModalLogic.ts Outdated
Replace the global update-action bridge with a request-specific api.update
await so the form lifecycle can't be settled by a concurrent dashboard update
(layout save, sharing toggle). On failure it rejects and keeps the modal open;
on success it syncs dashboardsModel exactly as the loader would.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capy Generated by capy.ai

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant