Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(experiments): Properly translate event and action filters #28662

Merged

Conversation

danielbachhuber
Copy link
Contributor

Merges into #28347

Changes

Properly translates event and action filters into their corresponding metric config objects.

Event

CleanShot.2025-02-13.at.05.12.49.mp4

Action

CleanShot.2025-02-13.at.05.14.44.mp4

Shared metric

CleanShot.2025-02-13.at.05.19.25.mp4

How did you test this code?

I added an event and an action to an experiment and verified they saved as expected.

I also created a shared metric for an action and a shared metric for a filter and verified they saved as expected.

@danielbachhuber danielbachhuber requested a review from a team February 13, 2025 13:20
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This PR adds functionality to properly translate event and action filters into metric configuration objects for experiments in PostHog. Here are the key changes:

  • Added new ExperimentActionMetricConfig type and interface in schema-general.ts to support action-based metrics in experiments
  • Introduced filterToMetricConfig utility function to convert event/action filters into metric configurations, preserving properties like math operations and HogQL expressions
  • Added metricConfigToFilter utility function for the reverse conversion from metric configs back to filter format
  • Updated ExperimentMetricForm and SharedExperimentMetricForm components to use the new conversion utilities instead of direct metric construction
  • Added comprehensive test coverage for the new filter translation functions, including property preservation and type safety checks

The changes improve type safety and maintainability by centralizing the conversion logic in dedicated utility functions.

5 file(s) reviewed, 7 comment(s)
Edit PR Review Bot Settings | Greptile

Comment on lines 53 to 54
const entity = events?.[0] || actions?.[0]
if (entity) {
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Type assertion to EventsNode | ActionsNode could fail if entity is undefined - consider adding null check

Suggested change
const entity = events?.[0] || actions?.[0]
if (entity) {
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)
const entity = events?.[0] || actions?.[0]
if (!entity) return
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)

math_property: undefined,
math_hogql: undefined,
properties: [{ key: '$lib', type: 'event', value: ['python'], operator: 'exact' }],
kind: NodeKind.EventsNode,
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: kind is set to EventsNode for an action type filter - this seems incorrect and inconsistent with the type declaration

const action = {
id: '8',
name: 'jan-16-running payment action',
kind: 'EventsNode',
Copy link
Contributor

Choose a reason for hiding this comment

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

style: kind is set to 'EventsNode' as string instead of using NodeKind.EventsNode enum

Suggested change
kind: 'EventsNode',
kind: NodeKind.EventsNode,

Comment on lines 48 to 49
const entity = events?.[0] || actions?.[0]
if (entity) {
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Type assertion on line 49 could fail if entity is undefined since line 48 doesn't check for null/undefined

Suggested change
const entity = events?.[0] || actions?.[0]
if (entity) {
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)
const entity = events?.[0] || actions?.[0]
if (!entity) return
const metricConfig = filterToMetricConfig(entity as EventsNode | ActionsNode)

},
id: metric_config.action,
name: metric_config.name,
kind: NodeKind.EventsNode,
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: incorrect node kind for actions - should be NodeKind.ActionsNode instead of NodeKind.EventsNode

Suggested change
kind: NodeKind.EventsNode,
kind: NodeKind.ActionsNode,

Comment on lines +370 to 408
export function metricConfigToFilter(
metric_config: ExperimentEventMetricConfig | ExperimentActionMetricConfig | ExperimentDataWarehouseMetricConfig
): FilterType {
if (metric_config.kind === NodeKind.ExperimentEventMetricConfig) {
return {
events: [
{
id: '$pageview',
name: '$pageview',
id: metric_config.event,
name: metric_config.event,
kind: NodeKind.EventsNode,
type: 'events',
math: 'total',
math_property: null,
math_hogql: null,
},
math: metric_config.math,
math_property: metric_config.math_property,
math_hogql: metric_config.math_hogql,
properties: metric_config.properties,
} as EventsNode,
],
actions: [],
}
}

const config = metric.metric_config
if (config.kind === NodeKind.ExperimentEventMetricConfig) {
} else if (metric_config.kind === NodeKind.ExperimentActionMetricConfig) {
return {
events: [
events: [],
actions: [
{
id: config.event,
name: config.event,
type: 'events',
math: config.math,
math_property: config.math_property,
math_hogql: config.math_hogql,
},
id: metric_config.action,
name: metric_config.name,
kind: NodeKind.EventsNode,
type: 'actions',
math: metric_config.math,
math_property: metric_config.math_property,
math_hogql: metric_config.math_hogql,
properties: metric_config.properties,
} as EventsNode,
],
actions: [],
}
}

return {}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: missing handling for ExperimentDataWarehouseMetricConfig case despite being in the function signature

return undefined
}

if (entity.kind === NodeKind.EventsNode) {
Copy link
Contributor

Choose a reason for hiding this comment

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

style: consider adding a type guard here instead of using Record<string, any>

Copy link
Contributor

@andehen andehen left a comment

Choose a reason for hiding this comment

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

Awesome! Tested locally and stores metrics as expected 👍

properties?: AnyPropertyFilter[]
}

export interface ExperimentActionMetricConfig {
Copy link
Contributor

Choose a reason for hiding this comment

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

One thought: We could remove event / action from these two schemas, and add id and type: 'events' | 'action. It will match what we get from the form then. We will get away with one schema and simplify metricConfigToFilter logic. Not a strong opinion, but it will be less code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@andehen Potentially! I think I'd like to keep them separate for now, as there's some value in having them explicitly defined as such.

@danielbachhuber danielbachhuber merged commit 382fb93 into init-new-experiment-query-runner Feb 13, 2025
98 of 99 checks passed
@danielbachhuber danielbachhuber deleted the assign-events-actions branch February 13, 2025 18:11
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.

2 participants