Repository navigation
feat(workflows): show workflows read-only to users with view access - #127180
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Guard the workflow edit listeners, disable step settings while keeping collapsible sections openable, and hide title editing and the auto-save switch from viewers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…viewers A disabled fieldset also disabled collapse headers inside step settings, so viewers could not open nested sections. Lock edit controls with a view-only area that leaves collapse headers clickable. Offer Duplicate only to users who can create workflows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ings Pointer blocking alone left step controls reachable by keyboard, and some of them call APIs directly. The view-only area now stops clicks, key presses, paste and drop on everything except collapse headers and links. 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>
# Conflicts: # products/workflows/frontend/Workflows/WorkflowScene.tsx
…wers The switch came in from master outside the step panel's view-only area, so viewers saw it as an active control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
😎 Merged successfully - details. |
|
Decision record for this PR, from the agent session and the design review round.
|
🤖 CI report
|
| Function | Location | Complexity | Limit |
|---|---|---|---|
onDrop |
products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx:2552 |
51 | 10 |
saveWorkflowSuccess |
products/workflows/frontend/Workflows/workflowLogic.ts:4742 |
45 | 10 |
runSave |
products/workflows/frontend/Workflows/workflowLogic.ts:3608 |
42 | 10 |
<anonymous> |
products/workflows/frontend/Workflows/workflowLogic.ts:4163 |
42 | 10 |
WorkflowScene |
products/workflows/frontend/Workflows/WorkflowScene.tsx:69 |
37 | 10 |
HogFlowEditorPanelBuildDetail |
products/workflows/frontend/Workflows/hogflows/panel/HogFlowEditorPanelBuildDetail.tsx:49 |
36 | 10 |
PropertyFilterButton |
frontend/src/lib/components/PropertyFilters/components/PropertyFilterButton.tsx:42 |
27 | 10 |
WorkflowStatusBar |
products/workflows/frontend/Workflows/WorkflowStatusBar.tsx:15 |
21 | 10 |
HogFlowEditorPanel |
products/workflows/frontend/Workflows/hogflows/panel/HogFlowEditorPanel.tsx:31 |
21 | 10 |
TileStepNode |
products/workflows/frontend/Workflows/hogflows/editor/tile-canvas/TileStepNode.tsx:25 |
20 | 10 |
AiTaskInstructionsCompare |
products/workflows/frontend/Workflows/hogflows/steps/components/AiTaskInstructionsCompare.tsx:15 |
19 | 10 |
NativeEmailTemplaterForm |
frontend/src/scenes/hog-functions/email-templater/EmailTemplater.tsx:555 |
15 | 10 |
NativeEmailIntegrationChoice |
frontend/src/scenes/hog-functions/email-templater/EmailTemplater.tsx:249 |
13 | 10 |
TileEdge |
products/workflows/frontend/Workflows/hogflows/editor/tile-canvas/TileEdge.tsx:18 |
12 | 10 |
submit |
products/workflows/frontend/Workflows/workflowLogic.ts:3802 |
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) — clean
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.
⚠️ Bundle size — 🔺 +34.6 KiB (+0.0%)
Uncompressed size of every built .js bundle, compared against the base branch.
Total: 79.08 MiB · 🔺 +34.6 KiB (+0.0%)
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
22.19 MiB | 🔺 +15.0 KiB (+0.1%) |
exporter/src/queries/nodes/InsightViz/InsightViz.js |
414.2 KiB | 🔺 +9.9 KiB (+2.5%) |
exporter/_parent/products/workflows/frontend/Workflows/Workflow.js |
204.8 KiB | 🔺 +2.9 KiB (+1.4%) |
posthog-app/_parent/products/workflows/frontend/Broadcasts/BroadcastScene.js |
152.1 KiB | 🔺 +1.7 KiB (+1.1%) |
posthog-app/_parent/products/workflows/frontend/Transactional/TransactionalScene.js |
84.3 KiB | 🔺 +1.5 KiB (+1.9%) |
posthog-app/_parent/products/autoresearch/frontend/AutoresearchPipelineScene.js |
137.9 KiB | 🔺 +1.4 KiB (+1.0%) |
posthog-app/_parent/products/workflows/frontend/WorkflowsScene.js |
78.4 KiB | 🔺 +1.2 KiB (+1.6%) |
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.05 MiB · 25 files | 🔺 +412 B (+0.0%) | █████████░ 91.6% 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.86 MiB · 538 files | 🔺 +1.3 KiB (+0.0%) | ██████████ 99.0% of 2.89 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
3.89 MiB · 1,237 files | 🔺 +3.1 KiB (+0.1%) | ██████████ 99.4% of 3.91 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
7.84 MiB · 3,023 files | 🔺 +5.7 KiB (+0.1%) | ██████████ 99.0% of 7.92 MiB |
today home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx |
4.88 MiB · 1,872 files | 🔺 +3.3 KiB (+0.1%) | ██████████ 99.9% of 4.88 MiB |
AI-first home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx |
6.10 MiB · 2,297 files | 🔺 +3.7 KiB (+0.1%) | ██████████ 99.5% of 6.13 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
6.82 MiB · 2,565 files | 🔺 +3.7 KiB (+0.1%) | ██████████ 98.8% of 6.91 MiB |
web analytics scenesrc/scenes/web-analytics/WebAnalyticsScene.tsx |
7.91 MiB · 2,970 files | 🔺 +3.7 KiB (+0.0%) | ██████████ 99.5% of 7.96 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
7.01 MiB · 2,622 files | 🔺 +4.9 KiB (+0.1%) | ██████████ 98.9% of 7.09 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 products/product_analytics/frontend/insights/activityDescriptions 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/lib/lemon-ui/LemonTable/LemonTable.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/@dnd-kit/ 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/lib/logic/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/kea-test-utils/ 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
🟢 products/product_analytics/frontend/insights/activityDescriptions stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/kea-test-utils/ 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
🟢 src/layout/panel-layout/ProjectTree/menus/SessionReplayMenuItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/navigation/projectNoticeLogic.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/navigation/ImpersonationNotice/ImpersonationNotice.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/cohorts/cohortSavedToast.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
🟢 products/subscriptions/frontend/components/Subscriptions/exportNudge/exportNudgeLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/billing/paymentEntryLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/conversations/frontend/components/SidePanel/sidepanelTicketsLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/zod/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/authentication/auth/loginLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/authentication/shared/passkeyLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/cohorts/CohortFilters/constants.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/persons/frontend/logics/personsLogic.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/surveys/constants.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/re2js/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/react-markdown/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/Command/Command.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 packages/quill/packages/ 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
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/marked/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/dashboard/Dashboard.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/queries/web-analytics-validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/re2js/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.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
🟢 packages/quill/packages/quill/dist/ 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/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
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/marked/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/activity/explore/EventsScene.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/queries/web-analytics-validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/re2js/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/InsightViz/InsightViz.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/DataVisualization/DataVisualization.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/WebOverview/WebOverview.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/marked/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/web-analytics/WebAnalyticsScene.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/queries/validators.js stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/re2js/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/marked/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.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
🟢 node_modules/re2js/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/d3/src/ 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.8 KiB | src/lib/utils/bootTiming.ts |
| 1.7 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.7 KiB | src/index.tsx |
| 1.2 KiB | src/RootErrorBoundary.tsx |
| 1.1 KiB | src/lib/utils/deferredAppContext.ts |
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 107.5 KiB | src/products.tsx |
| 93.2 KiB | src/lib/api.ts |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 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 |
| 29.4 KiB | src/lib/constants.tsx |
| 24.8 KiB | ../node_modules/.pnpm/fuse.js@7.3.0/node_modules/fuse.js/dist/fuse.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 |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 107.5 KiB | src/products.tsx |
| 93.2 KiB | src/lib/api.ts |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 40.3 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.3.0_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 |
| 32.6 KiB | src/lib/utils/eventUsageLogic.ts |
| 29.4 KiB | src/lib/constants.tsx |
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 116.4 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/surveys-preview.js |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 98.2 KiB | ../packages/quill/packages/components/dist/index.js |
| 93.2 KiB | src/lib/api.ts |
| 78.8 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 93.2 KiB | src/lib/api.ts |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.5 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
| 40.3 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.3.0_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 |
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 |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 93.2 KiB | src/lib/api.ts |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.5 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
| 41.7 KiB | src/scenes/hog-functions/sub-templates/sub-templates.ts |
| 40.3 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.3.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 98.2 KiB | ../packages/quill/packages/components/dist/index.js |
| 93.2 KiB | src/lib/api.ts |
| 78.8 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.5 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
Largest files eagerly shipped from src/scenes/web-analytics/WebAnalyticsScene.tsx
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 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 |
| 116.4 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/surveys-preview.js |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 98.2 KiB | ../packages/quill/packages/components/dist/index.js |
| 93.2 KiB | src/lib/api.ts |
| 78.8 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
| Size | File |
|---|---|
| 363.5 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 329.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.13_@types+react@18.3.31_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 224.1 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 |
| 112.7 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 107.5 KiB | src/products.tsx |
| 98.2 KiB | ../packages/quill/packages/components/dist/index.js |
| 93.2 KiB | src/lib/api.ts |
| 69.0 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.5 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Frontend layers — no new upward imports, 0 removed
Static imports from a lower frontend layer into a higher one (layers, lowest first: kernel, shell, query, features). Compared with the base branch, so an import that a PR also adds to layer-baseline.txt still shows here. Sizes are the source bytes on the eager path of every logged-in page.
| Layer | Eager source bytes | Δ vs base |
|---|---|---|
| kernel | 3.01 MiB | 🔺 +28 B (+0.0%) |
| shell | 2.42 MiB | 🔺 +3.6 KiB (+0.1%) |
| query | 56.9 KiB | no change |
| features | 274.3 KiB | no change |
Download the interactive layer graph for this PR.
Posted automatically by check-layers
✅ Toolbar bundle — eager 2.45 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.45 MiB · 19 files | 🔺 +824 B (+0.0%) | ████░░░░░░ 42.8% of 5.72 MiB |
| Deferred (lazy) | 2.64 MiB · 43 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 |
|---|---|
| 985.3 KiB | dist/toolbar/toolbar-app-WRRY4DD6.css |
| 739.3 KiB | dist/toolbar/chunk-chunk-LGE363UN.js |
| 290.5 KiB | dist/toolbar/chunk-chunk-SR2GGBU2.js |
| 137.6 KiB | dist/toolbar/chunk-chunk-TOZ3VEQK.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FQJO25M6.js |
| 75.7 KiB | dist/toolbar/toolbar-app-AFUYBY2K.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-BFAXZMC5.js |
| 33.8 KiB | dist/toolbar/chunk-chunk-VTCOB6FJ.js |
| 21.9 KiB | dist/toolbar/chunk-chunk-ZDW6T6RW.js |
| 6.8 KiB | dist/toolbar/chunk-chunk-RVLGRPCH.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +552.5 KiB (+0.1%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1011.99 MiB · 🔺 +552.5 KiB (+0.1%)
⚠️ Playwright — 1 flaky
🎭 Playwright report · View test results →
- Creating a SQL insight with a variable and overriding it on a dashboard (chromium)
These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!
✅ Hogbox preview — ready, open the preview
▶ Open the preview
| 🔑 Login | test@posthog.com / 12345678 (demo data) |
| 🧩 Running | this PR's backend and frontend, on the PostHog :master base |
| 🔗 Link | stable across rebuilds: a re-push swaps the box underneath, the URL stays |
| 🔒 Access | tailnet only (PostHog VPN) |
| 🛠️ Admin | inspect & debug state in hogland |
| 💤 Idle | sleeps after ~30 min idle (snapshot to S3, zero node cost) and wakes on your next visit in ~30s, behind a brief "waking up" screen |
commit 465a3af · box box-4b42e138cb4c · ready in 2551s (push → usable) · build log · rebuilds on every push, torn down on close
There was a problem hiding this comment.
PostHog Review · Standard · reviewed e8865db: 3 Should fix.
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.
HostHog preview —
|
View-only step settings cancelled the copy button on code snippets and removed pointer events from text fields, so viewers could not copy a webhook URL or select text. Copy buttons now pass through, and text fields and the code editor keep pointer events. Cut, the context menu and native beforeinput events are blocked so that the new pointer paths cannot edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An email with only a plain-text body previewed as a blank frame, and a viewer could not open the editor to read it. The preview now shows the plain-text body when the email has no HTML. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a step's settings failed to render for a viewer, the error fallback sat inside the view-only area. Its retry, support and copy buttons were blocked. The error boundary now wraps the view-only area, so the fallback stays usable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native and destination email forms rendered the same content preview block. Both now use one EmailContentPreview component. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
✅ Visual changes approved by @Silthus — baseline updated in 2 new. Install the Visual Review Chrome extension to see visual review results at the top of your pull requests. |
2 updated Run: dcf6881b-3338-4106-ac8a-275a9e6e5e6e
The email preview overlay covered the whole preview, even while invisible, so nobody could select or copy a plain-text body, and viewers saw an edit button the view-only area blocks. Mouse input now passes through the overlay to the preview, and only its buttons take it. Inside the view-only area the overlay is hidden. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Not approved — this change needs a human reviewer.
Re-adding the stamphog label gives the same result unless the changed files change.
Two gates refused this pull request. The deny-list gate matched deps_toolchain, most likely because pnpm-lock.yaml and products/workflows/package.json changed (a new @testing-library/dom dependency). The tier gate classified it as T2-never: 1510 lines across 30 files, touching two areas (workflows plus shared components such as PropertyFilterButton and EmailTemplater).
The size gate passed, so size is not the blocker on its own. Please ask a human reviewer to look at it. Splitting the dependency change and the shared-component changes into separate pull requests would also make each one easier to review.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: deps_toolchain |
| size | ✓ | 849L, 25F substantive, 1510L/30F incl. docs/generated/snapshots — within ceiling |
| tier | ✗ | classified as T2-never: T2-never (1510L, 30F, two-areas, feat) |
| stamphog 2.7.0 | .stamphog/policy.yml @ unknown · reviewed head 9662cea |
|
✅ Visual changes approved by @Silthus — baseline updated in 2 changed. Install the Visual Review Chrome extension to see visual review results at the top of your pull requests. |
2 updated Run: 6023d9d2-60c8-4e63-8674-a4f783fcbfb6
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>
Copy tests read the text a clipboard fake received instead of asserting the copy helper was called. The code editor Tab tests drive a real keyboard with user-event and check where focus lands and that the code is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each code editor key case also runs for a user with edit access, so the stand-in editor's own Tab and find handling is proven to act and the view-only guard is what stops it for a viewer. The find case checks for a visible find box. Drops the duplicate peer entry for @testing-library/dom that the master merge kept, matching master's package.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guard tests now edit stand-in controls and a code editor for real and compare a viewer with an editor, the reading keys check the caret, the selection, the clipboard and focus, and the Duplicate failure test reads the rendered toast. Explanatory comments are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
/trunk merge |
Deploy status
This table shows the |
Note
Just needs a stamp. Shows workflows read-only to users with view access. StampHog can't approve it: it changes dependencies in
products/workflows/package.json.Problem
Impact
workflow view only banner shownandworkflow view only duplicatedevents track it.Warning
🟡 Merge risk: medium · two-way door (merge-risk rubric)
28c57707aa1covers the editor's step edits, auto-save, and tile canvas copy, move, delete, drag and add.today-rail-nav), and the plain-text email preview in email editors outside workflows. A fault there shows a wrong or missing tooltip, or a wrong plain-text preview. Both only display, and no save path changes. A unit test renders the plain-text preview; no test covers the quill tooltip.Rollout
workflow view only banner shownagainst editors' saves. No alert pages on a drop in editor saves.Changes
workflowLogicdrops viewer edits in the four listeners every layout writes through, and skips auto-save.tileCanvasLogicignores add, drag, drop and menu actions from a viewer.hog_flowaccess control already rejects viewer saves.Review fixes, each with its proof
20364cff4c5. The live walk at that commit passed every viewer and editor row.c35e5bbdee1, and the live walk shows focus moving on.8c9ec4836a1.fb5f0b94d00.57f0d7acbfb, and3e1f4ecbd45sends the request through the generatedhogFlowsCreateclient.Screenshots at earlier heads (
c134a1559e5,6cf29edece4, fork #126468)How did you test this code?
Test rationale: existing editor tests never load a viewer. Logic tests check that viewer edits never save and that the tile canvas ignores viewer edits.
workflowViewOnly.test.tsxedits stand-in controls and a stand-in code editor for real, once as a viewer and once as an editor, and checks the field, the code, the caret, focus, the clipboard and the rendered toast. Breaking a guard inViewOnlyArea, the tile canvas or the Duplicate toast fails a test. The push switch has two guards, and breaking both fails its test.465a3af3c4b, which changes one test assertion, on the worktree box: frozen install, workspace build, formatter check, kea typegen, typecheck, and the Workflows Jest suite plus the chip test (2,369 tests). Strict preflight passed on push.40b09efb13eon the worktree box: frozen install, workspace build, formatter check, kea typegen, typecheck, and the Workflows Jest suite plus the chip test (2,369 tests). Strict preflight passed with 0 failures.28c57707aa1: 17 of 17 rows passed, including the shifted shortcuts, the HogQL chip tooltip, the Duplicate error, and the editor's tile canvas copy, move, delete, drag and add. The viewer sent one write, the Duplicate POST.40b09efb13echanges tests and removes comments only.6087167756b(the master merge with fix(workflows): accept a transactional email step without a category #132950, the transactional email step without a category) on the worktree box: install, workspace build, formatter check, kea typegen, typecheck, and the Workflows Jest suite plus the chip test (2,227 tests). The pre-pushhogli ci:preflight --strictpassed with 0 failures. The merge keeps this PR's UTM controls and master's "Transactional, no category" placeholder on the category select, and takes master's@testing-library/dom10.4.2 in the lockfile.cd65d1bfd71(the master merge with feat(product-analytics): quill property filters in the insight editor #131676): the same checks (2,172 tests). The merge keeps the full HogQL expression in the chip title and gives the quill chip the same text in its tooltip.5a548348cf3, which masks the plaintext email preview in recordings: the email templater Jest suites (91 tests), the formatter check, and strict preflight.9662cea6b46(2,171 tests) andc053239771b(2,084 tests): the same checks. At3e1f4ecbd45: typecheck,workflowViewOnly.test.tsx, and strict preflight.6f88479e459(after the master merge that made the tile canvas the editor), with invented workflows and a project-level viewer rule: 25 of 25 behaviors passed. The viewer made no write tohog_flowsor schedules, a direct viewer save got 403, and the owner's edit saved.c35e5bbdee1and20364cff4c5: Tab moves focus, and every tile canvas row above passed for viewer and editor. The viewer sent no write request.CI report warnings, all accepted:
@testing-library/dompeer entry inproducts/workflows/package.jsoncounts as a contract file. No Python changed.WorkflowScene,WorkflowStatusBar,HogFlowEditorPanel,TileStepNodeandTileEdgeeach gain view-only render conditions; the tile canvas fix adds one each toTileStepNode(20) andTileEdge(12). The HogQL tooltip adds three conditions toPropertyFilterButton(27, with master's quill chip branch), which was already over the limit.AiTaskInstructionsCompareappears only for added class names. The other functions were already over the limit.40b09efb13ethe report shows +33.3 KiB in total. This PR's part is the exporter'sWorkflow.jsat +2.9 KiB. The other listed files (render-query,InsightViz, Autoresearch, Broadcasts, Transactional) are untouched here and changed on master after this branch's last master merge, such as feat(autoresearch): stop a live training run #134198, feat(workflows): show who a broadcast run reached and who is still waiting #133991 and fix(workflows): load transactional templates without their content #134268. An earlier report at the same commit showed +4.0 KiB. A build of9662cea6b46against its base on a box measured about 3 KiB forWorkflow.jsand about 4.7 KiB for the app.40b09efb13e: password reset and deleting a person property, neither of which this PR touches. Both passed on retry.👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Release status
Docs update
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, claude-opus-5-5
Skills:
/full-stop,/impact,/tdd,/qa-swarm,/merge-risk,/pr-description,/writing-pr-descriptions,/writing-tests,/writing-code-comments,/leaving-pr-commentshog_flowworkflowLogiclisteners plus blocked input eventstileCanvasLogicignores viewer editsInvolvement: one design review, repeated GPT-6.1 Sol review reads, the latest with no findings, GPT-6.1 Sol proof judges with their findings fixed, eight PostHog Review findings fixed, UI walks and live runs captured.
More context for AI agents
isDeletableStepkeeps step deletion off for viewers there, andtileCanvasLogicguards its own edit actions.ViewOnlyArea, its styles and the email preview moved here, because the names carry the code:workflowLogicis not the only guard.onBeforeInputmisses deletions and undo, so the area listens to the nativebeforeinput.visibility: hiddenhides it for viewers.readOnlycode editors, which ends the one-shortcut-at-a-time review findings and unblocks opening the email editor for viewers.workflowLogic.tslistener guards,tileCanvasLogic.tsviewer guards,ViewOnlyArea.tsxandViewOnlyArea.scss,EmailContentPreviewinEmailTemplater.tsx.🤖 Generated with Claude Code