Skip to content

feat(data-warehouse): improve person-property custom property UX - #72607

Merged
talyn-app[bot] merged 6 commits into
masterfrom
tom/dwh-person-property-ux
Jul 21, 2026
Merged

feat(data-warehouse): improve person-property custom property UX#72607
talyn-app[bot] merged 6 commits into
masterfrom
tom/dwh-person-property-ux

Conversation

@Gilbert09

Copy link
Copy Markdown
Member

Problem

The warehouse-backed person custom properties feature (mapping warehouse table columns onto persons, from #70090) shipped with rough edges in the "New custom property" modal:

  • The warehouse-table dropdown only ever showed the first 100 tables (DRF default page size) and search was client-side only, so tables past the first page were unreachable.
  • The distinct-ID column and the column mappings were free-text inputs — you had to know and type exact column names.
  • Tables were labelled by their raw storage identifier (e.g. slack_c0b3he1pv53) instead of the dotted name they're queried by.
  • The account-only "Type" control (plus big-number / options) showed on the person form, where it does nothing — a person property is written as a raw $set value.

There was also no way to see or manage these person mappings from project settings, and the accounts config table gave no indication of whether a property attaches to a person or an account.

Changes

  • Warehouse-table picker now lists every synced table (drops the 100-row cap; requests include_columns=false so the list endpoint skips the expensive per-table HogQL column serialization) and labels each by its dotted HogQL name (e.g. stripe.charges).
  • Distinct-ID column and mapping columns are now dropdowns of the selected table's real columns, fetched on selection. Free-typing stays allowed (allowCustomValues) so a column auto-detection misses can still be entered.
  • Person form cleanup: the account-only Type / big-number / options controls are hidden for person-target properties, and display_type is forced to text on save.
  • Accounts config table gains an "Attach to" (Person / Account) column.
  • Project settings: new "Person properties from the warehouse" entry under Settings → Project → Product analytics (gated on the WAREHOUSE_PERSON_PROPERTIES flag) with a table of the mappings and add / edit / delete, opening the modal straight into Person.
  • Backend: TableSerializer gains a hogql_name field and honors include_columns=false (skipping both column serialization and the HogQL database build).

How did you test this code?

  • Added test_list_tables_exposes_hogql_name_and_honors_include_columns (data-warehouse table API). It asserts the list response exposes the dotted hogql_name and that include_columns=false returns tables with an empty columns array — guarding both the picker's label source and the cheap-list path, neither of which an existing test covered. Passes locally.
  • Ran ruff check / ruff format on the backend files and oxlint / oxfmt on the changed frontend files — all clean.
  • Regenerated OpenAPI/frontend types with hogli build:openapi on a current-master base: the only generated change is hogql_name in the data-warehouse api.schemas.ts.

I did not run the app or exercise the modal in a browser, so there are no screenshots — the frontend changes are covered by the kea logic and typing only.

Automatic notifications

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

Docs update

No user-facing docs under docs/ cover this modal; nothing to update.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Tool: Claude Code. Skills invoked: /improving-drf-endpoints (the TableSerializer change) and /writing-tests (the new backend test).
  • Key decisions: fetch the selected table's columns on demand rather than serializing columns for every table in the list (keeps the list cheap via include_columns=false); use LemonInputSelect with allowCustomValues for the column fields so undetected columns can still be typed; reuse the existing customPropertyDefinitionsLogic + modal for the settings surface, adding an optional target to openCreateModal so the settings entry opens straight into Person; force display_type to text for person targets since it only drives account-property rendering.
  • The hogql_name addition to the generated api.schemas.ts was verified against a full hogli build:openapi run — the canonical build produces no further data-warehouse/MCP/zod drift.

- List all synced warehouse tables in the picker (drop the 100-row cap and
  skip per-table column serialization via include_columns=false), and label
  them by their dotted HogQL name instead of the raw storage identifier
- Drive the distinct-ID and column-mapping fields from the selected table's
  columns instead of free-text inputs
- Hide the account-only Type / big-number / options controls for
  person-target properties
- Add an "Attach to" (Person / Account) column to the accounts config table
- Surface person-target properties in project settings with add/edit/delete
@Gilbert09 Gilbert09 self-assigned this Jul 21, 2026
@github-actions
github-actions Bot requested a deployment to preview-pr-72607 July 21, 2026 14:44 In progress
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🦔 Hogbox preview · ✅ ready

▶ 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 f0283fc · box box-5d4dbdba5218 · ready in 772s (push → usable) · build log · rebuilds on every push, torn down on close

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested review from a team, MattBro, fercgomes and rafaeelaudibert and removed request for a team July 21, 2026 14:44
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

⚠️ Bundle size — 🔺 +5.7 KiB (+0.0%)

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

Total: 64.47 MiB · 🔺 +5.7 KiB (+0.0%)

File Size Δ vs base
exporter/src/exporter/scenes/ExporterNotebookScene.js 3.11 MiB 🔺 +4.5 KiB (+0.1%)

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.23 MiB · 22 files no change ███░░░░░░░ 28.6% of 4.29 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.19 MiB · 2,999 files 🔺 +659 B (+0.0%) █████████░ 88.5% 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.3 KiB ../node_modules/.pnpm/posthog-js@1.404.1/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.8 KiB src/taxonomy/core-filter-definitions-by-group.json
223.4 KiB ../node_modules/.pnpm/posthog-js@1.404.1/node_modules/posthog-js/dist/module.js
167.1 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.0 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
93.2 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 — 🔺 +112.7 KiB (+0.0%)

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

Total: 1353.14 MiB · 🔺 +112.7 KiB (+0.0%)

Playwright — all passed

All tests passed.

View test results →

@posthog

posthog Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Visual changes approved by @Gilbert09 — baseline updated in f0283fc.

View this run in PostHog

6 changed.

The "New custom property" button passed the kea action directly to onClick, so the MouseEvent was bound to the action's optional targetType arg, tripping tsgo's MouseEventHandler check. Wrap it so the action is called with no arguments.

Generated-By: PostHog Code
Task-Id: 01d564d7-2825-462b-8b59-cf420e756364
Generated-By: PostHog Code
Task-Id: 01d564d7-2825-462b-8b59-cf420e756364
…rty logic

The committed inline logic types were stale relative to kea-typegen output, so the CI "schema.json and validators.js up to date" step (which runs after typegen) failed on the leftover diff. Regenerate them.

Generated-By: PostHog Code
Task-Id: 01d564d7-2825-462b-8b59-cf420e756364
6 updated
Run: 48092bcd-7a75-48ed-86a6-10db480e9f2e

Co-authored-by: Gilbert09 <1459269+Gilbert09@users.noreply.github.com>

@arthurdedeus arthurdedeus 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.

lgtm!

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.

should this be in CustomerAnalyticsConfigurationScene/person/WarehousePersonPropertiesSetting.tsx instead?

@talyn-app
talyn-app Bot merged commit c3b8000 into master Jul 21, 2026
255 checks passed
@talyn-app
talyn-app Bot deleted the tom/dwh-person-property-ux branch July 21, 2026 16:42
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 21, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-21 17:31 UTC Run
prod-us ✅ Deployed 2026-07-21 17:52 UTC Run
prod-eu ✅ Deployed 2026-07-21 17:50 UTC Run

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.

3 participants