Skip to content

feat(canvas): templates, rename, Quill component pass, and showcase#2603

Merged
adamleithp merged 2 commits into
feat/canvasfrom
feat/canvas-templates
Jun 11, 2026
Merged

feat(canvas): templates, rename, Quill component pass, and showcase#2603
adamleithp merged 2 commits into
feat/canvasfrom
feat/canvas-templates

Conversation

@adamleithp

@adamleithp adamleithp commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Ports feat/canvases-rename onto the post-refactor package graph (on top of feat/canvas) and extends it with a Quill component pass + a built-in showcase.

What's in it

image Screenshot 2026-06-11 at 14 21 30 image image image
  • Rename user-facing "dashboards" → "canvases" (strings, breadcrumbs, empty states).
  • TemplatesCanvasTemplatesService + schemas in @posthog/core, a canvas-templates host-router, per-template system prompt + component allow-list, and a New-canvas template picker (Dashboard / Blank).
  • canvas-gen now takes templateId + currentSpec; the system prompt is built in main from the template, and the working spec is re-seeded from the renderer each turn (fixes reopen-edit wiping a board).
  • Charts via @posthog/quill-charts: Line/Bar/Sparkline + PieChart; plus a Progress bar.
  • Phase-2 palette (Hero/Markdown/Button/Section) and declarative interactivity (state/bindings/visible/actions, TextInput/Checkbox).
  • Quill rendering — catalog components now render with @posthog/quill primitives (Card/Badge/Checkbox/Input/Table/Progress/Separator/Text). Bumps @posthog/quill0.3.0-beta.14 (+ a @base-ui/react override for that package's broken catalog: dep).
  • Toolbar gating — the data toolbar (filter + refresh) shows only on dashboard-template canvases, not Blank.
  • Showcase — seeds a built-in "Dashboard component Showcase" canvas into a channel on first visit (deduped by name).
  • Created by — stamps the creator at create time and shows it on canvas cards.

Verification

  • pnpm typecheck — 22/22
  • node scripts/check-host-boundaries.mjs — no new violations
  • npx react-doctor@0.4.2 . --blocking error — 0 errors (90/100)
  • pnpm biome check (canvas dirs) — clean

Notes

  • Base is feat/canvas, not main — this is the incremental port on top of the canvas MVP branch.
  • "Created by" applies to newly created canvases (stamped in meta); pre-existing canvases stay blank until recreated.
  • Per-channel showcase seeding (one per channel on first visit).

🤖 Generated with Claude Code

Port feat/canvases-rename onto the new package graph and extend it.

- Rename user-facing "dashboards" -> "canvases" (strings, breadcrumbs).
- Templates: CanvasTemplatesService + schemas in @posthog/core, a
  canvas-templates host-router, per-template system prompt + component
  allow-list, and a New-canvas template picker.
- canvas-gen now takes templateId + currentSpec; the system prompt is
  built in main from the template, and the working spec is re-seeded
  from the renderer each turn.
- Charts via @posthog/quill-charts: Line/Bar/Sparkline + PieChart; plus
  a Progress bar.
- Phase-2 palette (Hero/Markdown/Button/Section) and declarative
  interactivity (state/bindings/visible/actions, TextInput/Checkbox).
- Render catalog components with @posthog/quill primitives
  (Card/Badge/Checkbox/Input/Table/Progress/Separator/Text); bump
  @posthog/quill to 0.3.0-beta.14 (+ base-ui override).
- Gate the data toolbar (filter + refresh) to dashboard-template canvases.
- Seed a built-in "Dashboard component Showcase" canvas into a channel
  on first visit (deduped by name).
- Stamp creator at create time and show "Created by" on canvas cards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (2)

  1. packages/core/src/canvas/canvasTemplates.ts, line 274-308 (link)

    P1 Internal test chips shipped in production templates

    INTERACTIVITY_TESTS and ALLOW_LIST_TEST are explicitly described in comments as capability-verification chips ("Interactivity test chips (Phase 2.5): each label names the capability under test", "Same prompt on both templates verifies the allow-list"). Their labels ($bindState + {$state}, on.click setState + visible, validateForm, pushState + clear, Allow-list (Hero/Markdown)) use internal developer jargon that is meaningless and confusing to end users opening a new canvas. These will appear in the live suggestions panel the moment any user opens a new Blank or Dashboard canvas.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/core/src/canvas/canvasTemplates.ts
    Line: 274-308
    
    Comment:
    **Internal test chips shipped in production templates**
    
    `INTERACTIVITY_TESTS` and `ALLOW_LIST_TEST` are explicitly described in comments as capability-verification chips ("Interactivity test chips (Phase 2.5): each label names the capability under test", "Same prompt on both templates verifies the allow-list"). Their labels (`$bindState + {$state}`, `on.click setState + visible`, `validateForm`, `pushState + clear`, `Allow-list (Hero/Markdown)`) use internal developer jargon that is meaningless and confusing to end users opening a new canvas. These will appear in the live suggestions panel the moment any user opens a new Blank or Dashboard canvas.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. packages/core/src/canvas/canvasSchema.ts, line 113-120 (link)

    P2 Manually-mirrored schema will silently drift

    The comment says this is an identical copy of @json-render/react's element-tree schema and must be kept in sync manually. There is no enforcement at build time — a bump to @json-render/core or @json-render/react that changes the upstream schema will compile cleanly while the generated system prompt diverges from what the renderer actually accepts. Consider at minimum a snapshot test that serialises both schemas and fails if they differ, so the lockstep requirement is machine-checked rather than prose-only.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/core/src/canvas/canvasSchema.ts
    Line: 113-120
    
    Comment:
    **Manually-mirrored schema will silently drift**
    
    The comment says this is an identical copy of `@json-render/react`'s element-tree `schema` and must be kept in sync manually. There is no enforcement at build time — a bump to `@json-render/core` or `@json-render/react` that changes the upstream schema will compile cleanly while the generated system prompt diverges from what the renderer actually accepts. Consider at minimum a snapshot test that serialises both schemas and fails if they differ, so the lockstep requirement is machine-checked rather than prose-only.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/core/src/canvas/canvasTemplates.ts:274-308
**Internal test chips shipped in production templates**

`INTERACTIVITY_TESTS` and `ALLOW_LIST_TEST` are explicitly described in comments as capability-verification chips ("Interactivity test chips (Phase 2.5): each label names the capability under test", "Same prompt on both templates verifies the allow-list"). Their labels (`$bindState + {$state}`, `on.click setState + visible`, `validateForm`, `pushState + clear`, `Allow-list (Hero/Markdown)`) use internal developer jargon that is meaningless and confusing to end users opening a new canvas. These will appear in the live suggestions panel the moment any user opens a new Blank or Dashboard canvas.

### Issue 2 of 3
packages/ui/src/features/canvas/hooks/useSeedShowcase.ts:22-40
**`createDashboard` reference changes on every render, causing the effect to re-run needlessly**

`createDashboard` is a new arrow-function reference on every call to `useDashboardMutations()` (it wraps `create.mutateAsync` inline). Including it in the `useEffect` dependency array means the callback fires on every render of `WebsiteDashboardsIndex`, not just when the channel or loading state changes. The claim guard prevents double-seeding, but the effect still walks the full `dashboards` array each time. Removing `createDashboard` from the deps and capturing it inside the effect (or memoising it upstream) would limit the effect to the semantically meaningful changes.

### Issue 3 of 3
packages/core/src/canvas/canvasSchema.ts:113-120
**Manually-mirrored schema will silently drift**

The comment says this is an identical copy of `@json-render/react`'s element-tree `schema` and must be kept in sync manually. There is no enforcement at build time — a bump to `@json-render/core` or `@json-render/react` that changes the upstream schema will compile cleanly while the generated system prompt diverges from what the renderer actually accepts. Consider at minimum a snapshot test that serialises both schemas and fails if they differ, so the lockstep requirement is machine-checked rather than prose-only.

Reviews (1): Last reviewed commit: "feat(canvas): templates, rename, Quill c..." | Re-trigger Greptile

Comment on lines +22 to +40
const claimed = useRef(new Set<string>());

useEffect(() => {
if (!channelId || isLoading || claimed.current.has(channelId)) return;
if (dashboards.some((d) => d.name === SHOWCASE_CANVAS_NAME)) {
claimed.current.add(channelId);
return;
}
// Claim before the async create so a re-render mid-flight can't double-seed.
claimed.current.add(channelId);
createDashboard(
channelId,
SHOWCASE_CANVAS_NAME,
SHOWCASE_SPEC,
"dashboard",
).catch(() => {
// Creation failed — release the claim so a later render can retry.
claimed.current.delete(channelId);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 createDashboard reference changes on every render, causing the effect to re-run needlessly

createDashboard is a new arrow-function reference on every call to useDashboardMutations() (it wraps create.mutateAsync inline). Including it in the useEffect dependency array means the callback fires on every render of WebsiteDashboardsIndex, not just when the channel or loading state changes. The claim guard prevents double-seeding, but the effect still walks the full dashboards array each time. Removing createDashboard from the deps and capturing it inside the effect (or memoising it upstream) would limit the effect to the semantically meaningful changes.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/canvas/hooks/useSeedShowcase.ts
Line: 22-40

Comment:
**`createDashboard` reference changes on every render, causing the effect to re-run needlessly**

`createDashboard` is a new arrow-function reference on every call to `useDashboardMutations()` (it wraps `create.mutateAsync` inline). Including it in the `useEffect` dependency array means the callback fires on every render of `WebsiteDashboardsIndex`, not just when the channel or loading state changes. The claim guard prevents double-seeding, but the effect still walks the full `dashboards` array each time. Removing `createDashboard` from the deps and capturing it inside the effect (or memoising it upstream) would limit the effect to the semantically meaningful changes.

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

Address PR review:
- Replace the internal capability-test chips (INTERACTIVITY_TESTS /
  ALLOW_LIST_TEST) with real user-facing Blank-canvas suggestions
  (landing page, pricing, changelog, feedback form). They were dev
  jargon shown live in the empty-chat suggestions panel.
- useSeedShowcase: hold createDashboard in a ref so it isn't an effect
  dependency, so the seed effect only re-runs on channel/loading/list
  changes instead of every render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adamleithp

Copy link
Copy Markdown
Contributor Author

Thanks @greptile-apps — addressed in 1b5b981:

  • P1 — internal test chips in production templates ✅ Replaced INTERACTIVITY_TESTS / ALLOW_LIST_TEST (dev jargon like $bindState + {$state}, validateForm) with real user-facing Blank-canvas suggestions: Landing page, Pricing page, Changelog, Feedback form. Dropped the allow-list test chip from the Dashboard template too.
  • P2 — createDashboard effect churn (useSeedShowcase) ✅ Held createDashboard in a ref so it's no longer an effect dependency; the seed effect now re-runs only on channel / loading / list changes.
  • P2 — manually-mirrored canvasSchema can drift — intentional and documented: importing @json-render/react's schema would drag React into @posthog/core (a hard host-boundary violation). The version is pinned at @json-render/* 0.19.0, and the file comment calls out the lockstep requirement. A runtime guard isn't feasible without the React import; leaving as-is by design.

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

All three fixes look good — thanks for the thorough follow-up.

  • Blank suggestions are now genuinely user-facing (Landing page, Pricing page, Changelog, Feedback form) — no internal jargon leaking into the suggestions panel.
  • useSeedShowcase — the createRef pattern is the right call here. Effect deps are [channelId, isLoading, dashboards] exactly as intended, and the comment explaining why createDashboard is in a ref will save the next reader a "why isn't this in deps?" question.
  • canvasSchema drift — the design rationale is sound. Dragging React into @posthog/core to get a runtime guard would be a worse trade-off than the lock-step pin + comment. Noted.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@adamleithp adamleithp merged commit e77d5f4 into feat/canvas Jun 11, 2026
14 of 15 checks passed
@adamleithp adamleithp deleted the feat/canvas-templates branch June 11, 2026 14:35
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.

1 participant