experiment(widgets): embeddable same-document Query editor widget#71089
experiment(widgets): embeddable same-document Query editor widget#71089mariusandra wants to merge 1 commit into
Conversation
New standalone 'widgets' entry that exposes window.PostHogWidgets.mountQueryEditor: the real editable Query/InsightViz editor (series, taxonomic pickers, breakdown, date range, chart type) mounted into a foreign document with its own React 18 + kea inside a shadow root — the toolbar pattern, but for the insight editor. - frontend/src/widgets/: mount API, shadow-root component (FloatingContainerContext keeps popovers/tooltips/modals inside the shadow root; [theme] attribute drives dark mode), tiny instance store for handle.update(), harness page. - Auth: reuses the standalone OAuth mode in lib/api. setOAuthSessionOverride() seeds an IN-MEMORY session (host apiHost + bearer token, host-provided refresh callback) instead of localStorage, so host tokens never persist. - vite.widgets.config.mts builds dist-widgets/widgets.js (ESM + lazy chunks) and widgets.css, linked into the shadow root at runtime; bin/serve-widgets.mjs serves it with CORS for cross-origin module loading. - __unsafeMockContext option seeds userLogic/teamLogic for credential-less harness testing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🤖 CI report
|
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.22 MiB · 22 files | 🔺 +47 B (+0.0%) | ███░░░░░░░ 28.4% of 4.29 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.15 MiB · 2,979 files | 🔺 +142 B (+0.0%) | █████████░ 88.1% of 9.25 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.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.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.1 KiB | ../node_modules/.pnpm/posthog-js@1.401.0/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.5 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 222.7 KiB | ../node_modules/.pnpm/posthog-js@1.401.0/node_modules/posthog-js/dist/module.js |
| 164.0 KiB | src/queries/validators.js |
| 154.3 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 |
| 106.1 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | ../packages/quill/packages/quill/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
✅ Dist folder size — 🔺 +7.5 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1308.72 MiB · 🔺 +7.5 KiB (+0.0%)
Experiment:
widgetsentry — mount the real Query editor in a foreign appAdds a
widgetsvite entry (toolbar pattern) exposingwindow.PostHogWidgets.mountQueryEditor(el, { query, onQueryChange, apiHost, getAccessToken, theme, onClose })→{ update, unmount }. Internally: shadow root with injected styles, own React 18 + kea copy,FloatingContainerContextpointing popovers/tooltips inside the shadow root, and the full editableQuery/InsightVizeditor (series, math, TaxonomicFilter, breakdown/filters) emitting plain query JSON to the host.lib/api.ts, plus one new seam:setOAuthSessionOverride(session, refreshFn)— an in-memory session (never persisted in the host origin) whose 401 path calls the host's token refresh.userLogic+teamLogicneed explicit mounting; the rest self-mounts via keaconnect.loadUserSuccessseedsApiConfigids in OAuth mode — noPOSTHOG_APP_CONTEXTrequired.onQueryChangeround-trips, live theme flip restyles open popovers. See companion PR for details and the harness.Bundle:
widgets.js2.03 MB (603 KB gz) + CSS 137 KB gz; ~2.7 MB gz eager mount cost; 186 lazy chunks deferred.If this graduates from experiment, the maintainability contract would be: keep the entry building, keep tokens on
:root, :host, keepFloatingContainerContexthonored by portaling primitives, promotesetOAuthSessionOverrideto a first-class embedded-auth API, and add a size budget likecheck-toolbar-size.Screenshots
🤖 Generated with Claude Code