Skip to content

Commit

Permalink
chore(query-nodes): camel case paths filter (#19795)
Browse files Browse the repository at this point in the history
  • Loading branch information
thmsobrmlr authored Jan 19, 2024
1 parent 81e70e6 commit 1a6e53d
Show file tree
Hide file tree
Showing 28 changed files with 340 additions and 206 deletions.
2 changes: 1 addition & 1 deletion frontend/src/queries/nodes/InsightQuery/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const retentionQueryDefault: RetentionQuery = {
const pathsQueryDefault: PathsQuery = {
kind: NodeKind.PathsQuery,
pathsFilter: {
include_event_types: [PathType.PageView],
includeEventTypes: [PathType.PageView],
},
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,6 @@ describe('filtersToQueryNode', () => {
it('converts all properties', () => {
const filters: Partial<PathsFilterType> = {
insight: InsightType.PATHS,
path_type: PathType.Screen,
include_event_types: [PathType.Screen, PathType.PageView],
start_point: 'a',
end_point: 'b',
Expand All @@ -463,20 +462,19 @@ describe('filtersToQueryNode', () => {
const query: PathsQuery = {
kind: NodeKind.PathsQuery,
pathsFilter: {
path_type: PathType.Screen,
include_event_types: [PathType.Screen, PathType.PageView],
start_point: 'a',
end_point: 'b',
path_groupings: ['c', 'd'],
funnel_paths: FunnelPathType.between,
funnel_filter: { a: 1 },
exclude_events: ['e', 'f'],
step_limit: 1,
path_replacements: true,
local_path_cleaning_filters: [{ alias: 'home' }],
edge_limit: 1,
min_edge_weight: 1,
max_edge_weight: 1,
includeEventTypes: [PathType.Screen, PathType.PageView],
startPoint: 'a',
endPoint: 'b',
pathGroupings: ['c', 'd'],
funnelPaths: FunnelPathType.between,
funnelFilter: { a: 1 },
excludeEvents: ['e', 'f'],
stepLimit: 1,
pathReplacements: true,
localPathCleaningFilters: [{ alias: 'home' }],
edgeLimit: 1,
minEdgeWeight: 1,
maxEdgeWeight: 1,
},
}
expect(result).toEqual(query)
Expand Down Expand Up @@ -1332,11 +1330,11 @@ describe('filtersToQueryNode', () => {
date_to: null,
},
pathsFilter: {
start_point: 'https://hedgebox.net/',
step_limit: 5,
include_event_types: [PathType.PageView],
path_groupings: ['/files/*'],
edge_limit: 50,
startPoint: 'https://hedgebox.net/',
stepLimit: 5,
includeEventTypes: [PathType.PageView],
pathGroupings: ['/files/*'],
edgeLimit: 50,
},
properties: {
type: FilterLogicalOperator.And,
Expand Down
29 changes: 14 additions & 15 deletions frontend/src/queries/nodes/InsightQuery/utils/filtersToQueryNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,21 +310,20 @@ export const filtersToQueryNode = (filters: Partial<FilterType>): InsightQueryNo
// paths filter
if (isPathsFilter(filters) && isPathsQuery(query)) {
query.pathsFilter = objectCleanWithEmpty({
path_type: filters.path_type,
paths_hogql_expression: filters.paths_hogql_expression,
include_event_types: filters.include_event_types,
start_point: filters.start_point,
end_point: filters.end_point,
path_groupings: filters.path_groupings,
funnel_paths: filters.funnel_paths,
funnel_filter: filters.funnel_filter,
exclude_events: filters.exclude_events,
step_limit: filters.step_limit,
path_replacements: filters.path_replacements,
local_path_cleaning_filters: filters.local_path_cleaning_filters,
edge_limit: filters.edge_limit,
min_edge_weight: filters.min_edge_weight,
max_edge_weight: filters.max_edge_weight,
pathsHogQLExpression: filters.paths_hogql_expression,
includeEventTypes: filters.include_event_types,
startPoint: filters.start_point,
endPoint: filters.end_point,
pathGroupings: filters.path_groupings,
funnelPaths: filters.funnel_paths,
funnelFilter: filters.funnel_filter,
excludeEvents: filters.exclude_events,
stepLimit: filters.step_limit,
pathReplacements: filters.path_replacements,
localPathCleaningFilters: filters.local_path_cleaning_filters,
edgeLimit: filters.edge_limit,
minEdgeWeight: filters.min_edge_weight,
maxEdgeWeight: filters.max_edge_weight,
})
}

Expand Down
106 changes: 74 additions & 32 deletions frontend/src/queries/nodes/InsightQuery/utils/queryNodeToFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
EventsNode,
InsightNodeKind,
InsightQueryNode,
LifecycleFilterLegacy,
NodeKind,
PathsFilterLegacy,
StickinessFilterLegacy,
TrendsFilterLegacy,
} from '~/queries/schema'
import {
Expand Down Expand Up @@ -146,39 +149,78 @@ export const queryNodeToFilter = (query: InsightQueryNode): Partial<FilterType>
filters.toggledLifecycles = query.lifecycleFilter?.toggledLifecycles
}

// get node specific filter properties e.g. trendsFilter, funnelsFilter, ...
const insightFilter = JSON.parse(JSON.stringify(query[filterMap[query.kind]] || {}))
const legacyProps: TrendsFilterLegacy = {}
if (isTrendsQuery(query)) {
legacyProps.smoothing_intervals = insightFilter.smoothingIntervals
legacyProps.decimal_places = insightFilter.decimalPlaces
legacyProps.aggregation_axis_format = insightFilter.aggregationAxisFormat
legacyProps.aggregation_axis_postfix = insightFilter.aggregationAxisPostfix
legacyProps.aggregation_axis_prefix = insightFilter.aggregationAxisPrefix
legacyProps.show_labels_on_series = insightFilter.showLabelsOnSeries
legacyProps.show_percent_stack_view = insightFilter.showPercentStackView
legacyProps.show_legend = insightFilter.showLegend
legacyProps.show_values_on_series = insightFilter.showValuesOnSeries
delete insightFilter.smoothingIntervals
delete insightFilter.decimalPlaces
delete insightFilter.aggregationAxisFormat
delete insightFilter.aggregationAxisPostfix
delete insightFilter.aggregationAxisPrefix
delete insightFilter.showLabelsOnSeries
delete insightFilter.showPercentStackView
delete insightFilter.showLegend
delete insightFilter.showValuesOnSeries
} else if (isStickinessQuery(query)) {
legacyProps.show_legend = insightFilter.showLegend
legacyProps.show_values_on_series = insightFilter.showValuesOnSeries
delete insightFilter.showLegend
delete insightFilter.showValuesOnSeries
} else if (isLifecycleQuery(query)) {
legacyProps.show_values_on_series = insightFilter.showValuesOnSeries
delete insightFilter.showValuesOnSeries
// we don't want to mutate the original query
const queryCopy = JSON.parse(JSON.stringify(query))

// replace camel cased props with the snake cased variant
const camelCasedTrendsProps: TrendsFilterLegacy = {}
const camelCasedPathsProps: PathsFilterLegacy = {}
const camelCasedStickinessProps: StickinessFilterLegacy = {}
const camelCasedLifecycleProps: LifecycleFilterLegacy = {}
if (isTrendsQuery(queryCopy)) {
camelCasedTrendsProps.smoothing_intervals = queryCopy.trendsFilter?.smoothingIntervals
camelCasedTrendsProps.decimal_places = queryCopy.trendsFilter?.decimalPlaces
camelCasedTrendsProps.aggregation_axis_format = queryCopy.trendsFilter?.aggregationAxisFormat
camelCasedTrendsProps.aggregation_axis_postfix = queryCopy.trendsFilter?.aggregationAxisPostfix
camelCasedTrendsProps.aggregation_axis_prefix = queryCopy.trendsFilter?.aggregationAxisPrefix
camelCasedTrendsProps.show_labels_on_series = queryCopy.trendsFilter?.showLabelsOnSeries
camelCasedTrendsProps.show_percent_stack_view = queryCopy.trendsFilter?.showPercentStackView
camelCasedTrendsProps.show_legend = queryCopy.trendsFilter?.showLegend
camelCasedTrendsProps.show_values_on_series = queryCopy.trendsFilter?.showValuesOnSeries
delete queryCopy.trendsFilter?.smoothingIntervals
delete queryCopy.trendsFilter?.decimalPlaces
delete queryCopy.trendsFilter?.aggregationAxisFormat
delete queryCopy.trendsFilter?.aggregationAxisPostfix
delete queryCopy.trendsFilter?.aggregationAxisPrefix
delete queryCopy.trendsFilter?.showLabelsOnSeries
delete queryCopy.trendsFilter?.showPercentStackView
delete queryCopy.trendsFilter?.showLegend
delete queryCopy.trendsFilter?.showValuesOnSeries
} else if (isPathsQuery(queryCopy)) {
camelCasedPathsProps.edge_limit = queryCopy.pathsFilter?.edgeLimit
camelCasedPathsProps.paths_hogql_expression = queryCopy.pathsFilter?.pathsHogQLExpression
camelCasedPathsProps.include_event_types = queryCopy.pathsFilter?.includeEventTypes
camelCasedPathsProps.start_point = queryCopy.pathsFilter?.startPoint
camelCasedPathsProps.end_point = queryCopy.pathsFilter?.endPoint
camelCasedPathsProps.path_groupings = queryCopy.pathsFilter?.pathGroupings
camelCasedPathsProps.exclude_events = queryCopy.pathsFilter?.excludeEvents
camelCasedPathsProps.step_limit = queryCopy.pathsFilter?.stepLimit
camelCasedPathsProps.path_replacements = queryCopy.pathsFilter?.pathReplacements
camelCasedPathsProps.local_path_cleaning_filters = queryCopy.pathsFilter?.localPathCleaningFilters
camelCasedPathsProps.min_edge_weight = queryCopy.pathsFilter?.minEdgeWeight
camelCasedPathsProps.max_edge_weight = queryCopy.pathsFilter?.maxEdgeWeight
camelCasedPathsProps.funnel_paths = queryCopy.pathsFilter?.funnelPaths
camelCasedPathsProps.funnel_filter = queryCopy.pathsFilter?.funnelFilter
delete queryCopy.pathsFilter?.edgeLimit
delete queryCopy.pathsFilter?.pathsHogQLExpression
delete queryCopy.pathsFilter?.includeEventTypes
delete queryCopy.pathsFilter?.startPoint
delete queryCopy.pathsFilter?.endPoint
delete queryCopy.pathsFilter?.pathGroupings
delete queryCopy.pathsFilter?.excludeEvents
delete queryCopy.pathsFilter?.stepLimit
delete queryCopy.pathsFilter?.pathReplacements
delete queryCopy.pathsFilter?.localPathCleaningFilters
delete queryCopy.pathsFilter?.minEdgeWeight
delete queryCopy.pathsFilter?.maxEdgeWeight
delete queryCopy.pathsFilter?.funnelPaths
delete queryCopy.pathsFilter?.funnelFilter
} else if (isStickinessQuery(queryCopy)) {
camelCasedStickinessProps.show_legend = queryCopy.stickinessFilter?.showLegend
camelCasedStickinessProps.show_values_on_series = queryCopy.stickinessFilter?.showValuesOnSeries
delete queryCopy.stickinessFilter?.showLegend
delete queryCopy.stickinessFilter?.showValuesOnSeries
} else if (isLifecycleQuery(queryCopy)) {
camelCasedLifecycleProps.show_values_on_series = queryCopy.lifecycleFilter?.showValuesOnSeries
delete queryCopy.lifecycleFilter?.showValuesOnSeries
}
Object.assign(filters, insightFilter)
Object.assign(filters, legacyProps)
Object.assign(filters, camelCasedTrendsProps)
Object.assign(filters, camelCasedPathsProps)
Object.assign(filters, camelCasedStickinessProps)
Object.assign(filters, camelCasedLifecycleProps)

// add the remaining node specific filter properties
Object.assign(filters, queryCopy[filterMap[query.kind]])

return filters
}
2 changes: 1 addition & 1 deletion frontend/src/queries/nodes/InsightViz/EditorFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export function EditorFilters({ query, showing, embedded }: EditorFiltersProps):
isTrendsFunnel
const hasPathsAdvanced = availableFeatures.includes(AvailableFeature.PATHS_ADVANCED)
const hasAttribution = isStepsFunnel
const hasPathsHogQL = isPaths && pathsFilter?.include_event_types?.includes(PathType.HogQL)
const hasPathsHogQL = isPaths && pathsFilter?.includeEventTypes?.includes(PathType.HogQL)

const editorFilters: InsightEditorFilterGroup[] = [
{
Expand Down
60 changes: 60 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2192,6 +2192,66 @@
"type": "string"
},
"PathsFilter": {
"additionalProperties": false,
"properties": {
"edgeLimit": {
"type": "number"
},
"endPoint": {
"type": "string"
},
"excludeEvents": {
"items": {
"type": "string"
},
"type": "array"
},
"funnelFilter": {
"type": "object"
},
"funnelPaths": {
"$ref": "#/definitions/FunnelPathType"
},
"includeEventTypes": {
"items": {
"$ref": "#/definitions/PathType"
},
"type": "array"
},
"localPathCleaningFilters": {
"items": {
"$ref": "#/definitions/PathCleaningFilter"
},
"type": "array"
},
"maxEdgeWeight": {
"type": "number"
},
"minEdgeWeight": {
"type": "number"
},
"pathGroupings": {
"items": {
"type": "string"
},
"type": "array"
},
"pathReplacements": {
"type": "boolean"
},
"pathsHogQLExpression": {
"type": "string"
},
"startPoint": {
"type": "string"
},
"stepLimit": {
"type": "number"
}
},
"type": "object"
},
"PathsFilterLegacy": {
"additionalProperties": false,
"description": "`PathsFilterType` minus everything inherited from `FilterType` and persons modal related params",
"properties": {
Expand Down
20 changes: 19 additions & 1 deletion frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -599,10 +599,28 @@ export interface RetentionQuery extends InsightsQueryBase {
}

/** `PathsFilterType` minus everything inherited from `FilterType` and persons modal related params */
export type PathsFilter = Omit<
export type PathsFilterLegacy = Omit<
PathsFilterType,
keyof FilterType | 'path_start_key' | 'path_end_key' | 'path_dropoff_key'
>

export type PathsFilter = {
edgeLimit?: PathsFilterLegacy['edge_limit']
pathsHogQLExpression?: PathsFilterLegacy['paths_hogql_expression']
includeEventTypes?: PathsFilterLegacy['include_event_types']
startPoint?: PathsFilterLegacy['start_point']
endPoint?: PathsFilterLegacy['end_point']
pathGroupings?: PathsFilterLegacy['path_groupings']
excludeEvents?: PathsFilterLegacy['exclude_events']
stepLimit?: PathsFilterLegacy['step_limit']
pathReplacements?: PathsFilterLegacy['path_replacements']
localPathCleaningFilters?: PathsFilterLegacy['local_path_cleaning_filters']
minEdgeWeight?: PathsFilterLegacy['min_edge_weight']
maxEdgeWeight?: PathsFilterLegacy['max_edge_weight']
funnelPaths?: PathsFilterLegacy['funnel_paths']
funnelFilter?: PathsFilterLegacy['funnel_filter']
}

export interface PathsQuery extends InsightsQueryBase {
kind: NodeKind.PathsQuery
/** Properties specific to the paths insight */
Expand Down
20 changes: 10 additions & 10 deletions frontend/src/scenes/insights/EditorFilters/PathsAdvanced.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ export function PathsAdvanced({ insightProps, ...rest }: EditorFilterProps): JSX
const { pathsFilter } = useValues(pathsDataLogic(insightProps))
const { updateInsightFilter } = useActions(pathsDataLogic(insightProps))

const { edge_limit, min_edge_weight, max_edge_weight } = pathsFilter || {}
const { edgeLimit, minEdgeWeight, maxEdgeWeight } = pathsFilter || {}

const [localEdgeParameters, setLocalEdgeParameters] = useState<PathEdgeParameters>({
edge_limit: edge_limit,
min_edge_weight: min_edge_weight,
max_edge_weight: max_edge_weight,
edgeLimit,
minEdgeWeight,
maxEdgeWeight,
})

const updateEdgeParameters = (): void => {
if (
localEdgeParameters.edge_limit !== edge_limit ||
localEdgeParameters.min_edge_weight !== min_edge_weight ||
localEdgeParameters.max_edge_weight !== max_edge_weight
localEdgeParameters.edgeLimit !== edgeLimit ||
localEdgeParameters.minEdgeWeight !== minEdgeWeight ||
localEdgeParameters.maxEdgeWeight !== maxEdgeWeight
) {
updateInsightFilter({ ...localEdgeParameters })
}
Expand All @@ -49,7 +49,7 @@ export function PathsAdvanced({ insightProps, ...rest }: EditorFilterProps): JSX
onChange={(value): void =>
setLocalEdgeParameters((state) => ({
...state,
edge_limit: Number(value),
edgeLimit: Number(value),
}))
}
onBlur={updateEdgeParameters}
Expand All @@ -70,7 +70,7 @@ export function PathsAdvanced({ insightProps, ...rest }: EditorFilterProps): JSX
onChange={(value): void =>
setLocalEdgeParameters((state) => ({
...state,
min_edge_weight: Number(value),
minEdgeWeight: Number(value),
}))
}
onBlur={updateEdgeParameters}
Expand All @@ -82,7 +82,7 @@ export function PathsAdvanced({ insightProps, ...rest }: EditorFilterProps): JSX
onChange={(value): void =>
setLocalEdgeParameters((state) => ({
...state,
max_edge_weight: Number(value),
maxEdgeWeight: Number(value),
}))
}
min={0}
Expand Down
Loading

0 comments on commit 1a6e53d

Please sign in to comment.