Skip to content

feat(workflows): show code-managed email templates read-only - #127179

Draft
Silthus wants to merge 26 commits into
email-v2/05-template-sendfrom
email-v2/06-template-editor
Draft

Silthus wants to merge 26 commits into
email-v2/05-template-sendfrom
email-v2/06-template-editor

Conversation

@Silthus

@Silthus Silthus commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Moved from Silthus#575.

Part of the code-first rebuild of the email send stack; replaces parts of #118924 (the read-only view of code-managed templates).

Problem

  • A PostHog user who opens a template that a repository manages sees the full editor. Their edits are refused with 403 immutable, and the page doesn't say why or where the template lives.
  • They need to see that code manages it, where its file is, who it sends as, and how to take it back into PostHog.

Impact

Pays into Grow Workflows by keeping code-managed templates usable for the whole team, which keeps code sends going. In scope: Workflows, the email template library.

Merge Danger

Note

🟢 Merge risk: low · two-way door: a revert brings back the editor for every template

  • The read-only view shows only for templates the server returns with managed_by: code, which only a flag-gated upload creates.
  • The API example on the template page switches to send/email/ only with workflows-email-from-code on.
  • Not behind the flag: GitMetadataParser and the library card frame change for everyone. That covers error-tracking release and stack-frame links (Releases.tsx, ReleasesPopoverContent.tsx, framesCodeSourceLogic.ts) and every card preview.

Changes

Kind Files Lines
Production 23 +970 −202
Tests 4 +603 −4
Stories 2 +98 −0
  • A template managed by code opens read-only. It shows a "Managed by code" tag, its key with copy, and a link to its file at the uploaded ref.
  • The preview shows the From and Reply-to the template sends with, in a read-only row.
  • The menu offers Duplicate and "Stop managing in code", which asks first and names the file. Delete is disabled.
  • Duplicate drops the empty design of an uploaded template, so the copy saves. The create API refuses design: null with 400.
  • Edits the server refuses stay in a banner with "Duplicate with my changes", so nothing typed is lost. The banner has no close button: it leaves through Duplicate with my changes, Stop managing in code, or a confirmed navigation. Leaving the page asks first. The banner is the only notice: the app-wide "Save template failed" toast skips this refusal (initKea.ts), and every other save failure still toasts.
  • A failed "Stop managing in code" shows one toast with the reason, such as "You need editor access to this template's transactional email workflow."
  • A refused publish is not reported to error tracking, because the banner handles it.
  • The library marks code-managed templates with the same tag.
  • The quill view behind today-rail-nav gets the same actions.
  • The git link parser reads a file and ref on any known git host, which the source link needs.
  • The From row says when the sender could not load, in place of a skeleton that never ends.
  • A ref is shortened and linked as a commit only when it is a full 40 or 64 character hash.
  • Outside the template view: GitMetadataParser changes for every caller, error tracking included:
    • Bitbucket commit links use /commits/ and branch links use /src/.
    • GitLab HTTPS remotes in subgroups resolve to the group and the subgroup path.
    • Remotes without a scheme, such as github.com/org/repo, now parse and get links.
    • Branch names are URL-encoded.
  • Every library card's preview renders through EmailHtmlFrame. The HTML is parsed and serialized again, so comments outside <html> drop, and links open in a new tab.

Mechanical: the sender display moves from EmailSenderSummary into EmailSenderDetails, shared by the editor and the read-only row.

Before After
Library before: no tag Library after: Managed by code tag
Template before: full editor Template after: read-only view with key, source link and sender row
Menu Stop managing in code Refused edits
Menu: Duplicate, Stop managing in code, Delete disabled Confirm dialog naming the file Banner with Duplicate with my changes
At 520px Quill view (today-rail-nav) API tab with the flag on
Read-only view at 520px Quill actions API tab using send/email with template.key
Sender could not load After "Stop managing in code" Short hex ref
From row: Couldn't load the sender Editor after release, no draft tag Source row with abc1234 as a ref

Storybook at 1440px and 520px, mocked data, at 4117342. Later commits change only what Duplicate sends, shown in the running-app walk below. The other views are pixel-identical to the earlier walk at b7e93f2. After a release, the view is the normal editor with no unsaved-draft marker. The short ref abc1234 links to /tree/abc1234, and a full hash links to /commit/. All captures are saved with fleet proof.

How did you test this code?

Test seams: messageTemplateLogic through expectLogic, and rendered tests of the menu, the HTML frame and the read-only preview.

Test rationale:

  • messageTemplateLogic.test.ts: an upload that claims the template back while edits wait, and refused edits lost on release or discard.
  • MessageTemplateMenu.test.tsx: release, Cancel and Duplicate paths of the menu.
  • ReadOnlyTemplatePreview.test.tsx: the template's own sender fields losing to the sender's defaults, no message when there is no sender, and a failed integrations request that left the From row loading.
  • messageTemplateLogic.test.ts: a refused publish that shows the generic "Save template failed" toast next to the banner, and another 403 on save that no longer toasts.
  • messageTemplateLogic.test.ts: a Duplicate of an uploaded template that sent design: null; the create mocks now refuse it as the serializer does.
  • messageTemplateLogic.test.ts: tells the person once when the release fails, a failed release that showed two toasts.
  • messageTemplateLogic.test.ts: the refused-publish rows, a refused publish reported to error tracking.
  • messageTemplateLogic.test.ts: a release whose content an upload changed, which showed a false unsaved draft, and a hex-looking tag shown as a short commit.

Proofs on this head d9bdbd8 (saved with fleet proof):

  • UI walk and live run on a production build of this head, signed in on the seeded demo project, the flag on. An upload by key from code, the code-managed view, the menu, the release dialog, a release, an edit, a second upload that takes the template back, a refused Publish, and a refused release. The API saw only the two intended 403s.

  • The refused release is simulated: the walk answers the release PATCH with 403 permission_denied in the browser, because the seeded user is an admin.

    Refused edits: no close button Refused release: one toast
    Banner with Duplicate with my changes and no close button One toast: You need editor access to this template's transactional email workflow
  • Prod shape: a gap, accepted by the standing rule until read-only production access exists on 2026-11-02.

  • Lane gate on this head: ruff, the IDOR check, the migration checks, repo-wide mypy, and the messaging and workflows tests pass, and so do the frontend typecheck, lint, format check and the changed jest tests.

Earlier proofs, at 7b2198c, 4117342, d321dd8 and 2332fd3
  • Running app at 7b2198c, a production build on a seeded demo project with real uploads: library tag, read-only view, menu, Duplicate of an uploaded template, release, a re-upload that takes the template back, and the API tab with the flag on and off. 12 captures saved with fleet proof, no failed API calls.

    Duplicate of an uploaded template Re-upload from GitLab takes it back API tab with the flag off
    Welcome (copy) opens in the editor Read-only again, source on gitlab.com at main API tab names the template by template.id
  • UI walk in Storybook at 4117342, 1440px and 520px, shown above (saved with fleet proof).

  • Signed-in walk in the running app at d321dd8, with a production frontend build and real uploads from GitHub and GitLab sources, in both the LemonUI view and the today-rail-nav quill view (saved with fleet proof). All 15 steps match the Storybook captures, the narrow 547px scene included.

  • Refused edit, step 9 again at 2332fd3: an upload took the template back while it was being edited, and Publish was refused (403). Only the warning banner and "Duplicate with my changes" show. No toast fired: a watcher on the toast container recorded nothing. The walk before this fix showed a second, generic "Save template failed" toast.

    Refused edit: warning banner with Duplicate with my changes, no toast
  • The "…" button on a library card overlaps the first line of its preview. Master shows the same overlap, so it is not from this PR (master left, this PR right).

Release status

  • This change is behind a feature flag and is not available to users
  • The read-only view appears only for templates a flag-gated upload made. The git link parser and the card preview frame change for everyone.

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5 (claude-opus-5-5)

Question Answer Who Where
Does the read-only view show the sender? Yes, a read-only From and Reply-to row from EmailSenderSummary 👤 Human map Silthus#461, lane brief of 2026-10-25
May the code carry comments? No; names carry the reasons 👤 Human map Silthus#461, 2026-10-25
Does the info banner stay while refused edits wait? Yes, without its Duplicate (the earlier review's UW-1 call, kept) 👤 Human map Silthus#461, lane brief of 2026-10-25
Can a person dismiss the refused-edits banner? No; it leaves only through an action that keeps or drops the edits on purpose 🤖 Agent QA swarm 2026-11-01

Involvement: one brief from Michael with decisions; one review round (GPT-6.1 Sol: review, design, Michael's lens and UI; Opus fresh eyes) with its fixes; QA swarm on 2026-11-01 with two panel rounds (GPT-6.1 Sol review and UI, Opus 5.5 fresh eyes) and two final reads: 4 findings fixed, none rejected; UI walk and live run captured.

🤖 Generated with Claude Code

Silthus and others added 18 commits October 31, 2026 15:54
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A template uploaded from code opens as a read-only preview with its key
and source. Edits refused by an upload wait in a banner that offers a
duplicate, and the menu can stop managing the template in code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te source

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…izer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e edit

A publish refused because an upload took the template back over already
shows the warning banner with "Duplicate with my changes". The global
loader toast also showed the server message, so the user saw two errors.
messageTemplateLogic now owns the `immutable` refusal of saveTemplate.
Every other saveTemplate failure keeps the toast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…edits until the person acts

A failed release toasts once, a publish an upload refused is no longer reported
as an exception, and the refused-edits banner has no close button that drops
the edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Trunk lane — backend Python lane

This PR is assigned to the backend Python lane. It runs backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 4 functions above the limit (max 77)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
MessageTemplate products/workflows/frontend/TemplateLibrary/MessageTemplate.tsx:65 77 10
onFailure frontend/src/initKea.ts:283 47 10
MessageTemplateCard products/workflows/frontend/TemplateLibrary/MessageTemplateCard.tsx:12 13 10
templateSource products/workflows/frontend/TemplateLibrary/codeManagedTemplate.ts:18 11 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

⚠️ Duplication (TypeScript) — 8 new duplicated blocks (worst 226 tokens)

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

First copy Second copy Lines Tokens
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:439 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:482 43 226
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:106 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:137 24 114
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:382 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:404 21 113
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:254 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:439 21 112
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:254 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:275 21 111
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:439 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:460 21 111
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:106 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:382 22 109
products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:107 products/workflows/frontend/TemplateLibrary/messageTemplateLogic.ts:254 21 108
⚠️ Bundle size — 🔺 +9.2 KiB (+0.0%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 75.14 MiB · 🔺 +9.2 KiB (+0.0%)

File Size Δ vs base
posthog-app/_parent/products/workflows/frontend/TemplateLibrary/MessageTemplate.js 48.8 KiB 🔺 +7.4 KiB (+18.0%)
render-query/src/render-query/render-query.js 21.28 MiB 🔺 +1.2 KiB (+0.0%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

✅ Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.02 MiB · 25 files 🔺 +49 B (+0.0%) █████████░ 88.8% of 1.14 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
2.99 MiB · 622 files 🔺 +294 B (+0.0%) ██████████ 98.5% of 3.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
6.46 MiB · 2,235 files 🔺 +103 B (+0.0%) ██████████ 95.5% of 6.77 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.97 MiB · 3,728 files 🔺 +103 B (+0.0%) ██████████ 99.5% of 10.01 MiB
today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
6.71 MiB · 2,337 files 🔺 +103 B (+0.0%) ██████████ 96.4% of 6.96 MiB
AI-first home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
7.28 MiB · 2,426 files 🔺 +103 B (+0.0%) ██████████ 96.7% of 7.53 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.40 MiB · 3,500 files 🔺 +103 B (+0.0%) ██████████ 98.0% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.36 MiB · 3,767 files 🔺 +103 B (+0.0%) ██████████ 95.6% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
7.99 MiB · 2,968 files 🔺 +1.1 KiB (+0.0%) ████████░░ 84.4% of 9.47 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/zod/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/billing/billingLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/ProductEmptyState/productSetupPreloadLogic.ts stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/wizard/frontend/runs/WizardRunDetailsDrawer.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayShell.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayContextPanelFloating.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodaySidePanel.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayTopBar.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/todayRailItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 packages/quill/packages/charts/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/VisualizationWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/RecordingsWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/api/primitives.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/notebooks/Notebook/notebookLogic.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/LiveMetricsDashboard/LiveWebAnalyticsMetrics.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 products/product_analytics/frontend/insights/trends/WorldMap/countryVectors.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/settings/SettingsMap.tsx stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 @jspm/core/nodelibs/browser/fs stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.7 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
4.0 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.7 KiB src/index.tsx
1.7 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.7 KiB src/lib/utils/bootTiming.ts
1.2 KiB src/RootErrorBoundary.tsx
949 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
86.6 KiB src/lib/api.ts
67.9 KiB src/lib/lemon-ui/icons/icons.tsx
41.9 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
36.4 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
27.0 KiB ../node_modules/.pnpm/tailwind-merge@2.2.2/node_modules/tailwind-merge/dist/bundle-mjs.mjs
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.6 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.6 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/web-analytics/WebAnalyticsScene.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
187.9 KiB src/queries/validators.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
325.0 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
316.5 KiB ../node_modules/.pnpm/posthog-js@1.443.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
102.9 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

✅ Toolbar bundle — eager 2.33 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.33 MiB · 19 files 🔺 +103 B (+0.0%) ████░░░░░░ 40.8% of 5.72 MiB
Deferred (lazy) 2.11 MiB · 42 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
941.7 KiB dist/toolbar/toolbar-app-W74SKLOR.css
695.9 KiB dist/toolbar/chunk-chunk-IBKAF5PN.js
261.2 KiB dist/toolbar/chunk-chunk-T5DKNJQU.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-KRXYRWIK.js
75.7 KiB dist/toolbar/toolbar-app-4GQPRREL.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
33.8 KiB dist/toolbar/chunk-chunk-FR2SFTP5.js
21.7 KiB dist/toolbar/chunk-chunk-KZFTEGG4.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🔺 +117.3 KiB (+0.0%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 966.46 MiB · 🔺 +117.3 KiB (+0.0%)

@Silthus
Silthus added this pull request to stack #127190 November 2, 2026 08:54

@posthog posthog Bot left a comment

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.

PostHog Review · Standard · reviewed 395cd6c: 1 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

Comment on lines +1163 to +1169
if (keepEdits && !values.refusedEdits) {
actions.setRefusedEdits(values.template)
}
actions.setExternallyEdited(false)
actions.setDraftState(null, published)
actions.setOriginalTemplate(claimed)
actions.resetTemplate(claimed)

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 · Flush pending canvas edits before capturing refused changes

When an autosave returns immutable during designUpdated's 500 ms debounce, values.template lacks the latest canvas edit. claimedByUpload captures this stale value, then switches to read-only and unmounts EmailTemplater, clearing its editor ref before the pending export. “Duplicate with my changes” loses that edit; flush the canvas before capturing changes and switching views.

@posthog

posthog Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

👋 Visual changes detected for this PR.

Review and approve in PostHog Visual Review

If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix.

Install the Visual Review Chrome extension to see visual review results at the top of your pull requests.

Silthus and others added 6 commits November 6, 2026 12:16
…e-editor

# Conflicts:
#	frontend/src/initKea.ts
#	posthog/plugins/plugin_server_api.py
#	products/messaging/backend/facade/contracts.py
#	products/messaging/backend/facade/templates.py
#	products/messaging/backend/facade/transactional_email.py
#	products/messaging/backend/migrations/max_migration.txt
#	products/messaging/backend/models/message_template.py
#	products/messaging/backend/models/transactional_email_key.py
#	products/messaging/backend/presentation/views/message_templates.py
#	products/messaging/backend/services/html_text.py
#	products/messaging/backend/services/transactional_email.py
#	products/messaging/backend/tests/api/test_transactional_email.py
#	products/messaging/backend/tests/test_html_text.py
#	products/messaging/frontend/generated/api.schemas.ts
#	products/messaging/frontend/generated/api.ts
#	products/messaging/frontend/generated/api.zod.ts
#	products/workflows/backend/facade/transactional_emails.py
#	products/workflows/backend/services/transactional_email_workflows.py
#	products/workflows/frontend/TemplateLibrary/TransactionalEmailApiExample.tsx
#	products/workflows/frontend/generated/api.zod.ts
#	products/workflows/mcp/email_templates.yaml
#	services/mcp/schema/generated-tool-definitions.json
#	services/mcp/schema/tool-definitions-all.json
#	services/mcp/src/api/generated.ts
#	services/mcp/src/generated/email_templates/api.ts
#	services/mcp/src/generated/workflows/api.ts
#	services/mcp/src/tools/generated/email_templates.ts
#	services/mcp/tests/unit/__snapshots__/tool-schemas/broadcasts-create.json
#	services/mcp/tests/unit/__snapshots__/tool-schemas/workflows-create.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

1 participant