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(hogql): edit hogql expressions for tables other than 'events' #17736

Merged
merged 2 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions frontend/src/lib/components/HogQLEditor/HogQLEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { hogQLEditorLogic } from './hogQLEditorLogic'
export interface HogQLEditorProps {
onChange: (value: string) => void
value: string | undefined
hogQLTable?: string
disablePersonProperties?: boolean
disableAutoFocus?: boolean
disableCmdEnter?: boolean
Expand All @@ -20,6 +21,7 @@ let uniqueNode = 0
export function HogQLEditor({
onChange,
value,
hogQLTable,
disablePersonProperties,
disableAutoFocus,
disableCmdEnter,
Expand All @@ -28,7 +30,7 @@ export function HogQLEditor({
}: HogQLEditorProps): JSX.Element {
const [key] = useState(() => `HogQLEditor.${uniqueNode++}`)
const textareaRef = useRef<HTMLTextAreaElement | null>(null)
const logic = hogQLEditorLogic({ key, value, onChange, textareaRef })
const logic = hogQLEditorLogic({ key, value, onChange, hogQLTable, textareaRef })
const { localValue, error, responseLoading } = useValues(logic)
const { setLocalValue, submit } = useActions(logic)

Expand All @@ -53,7 +55,9 @@ export function HogQLEditor({
maxRows={6}
placeholder={
placeholder ??
(disablePersonProperties
(hogQLTable === 'persons'
? "Enter HogQL expression, such as:\n- properties.$geoip_country_name\n- toInt(properties.$browser_version) * 10\n- concat(properties.name, ' <', properties.email, '>')\n- is_identified ? 'user' : 'anon'"
: disablePersonProperties
? "Enter HogQL expression, such as:\n- properties.$current_url\n- toInt(properties.`Long Field Name`) * 10\n- concat(event, ' ', distinct_id)\n- if(1 < 2, 'small', 'large')"
: "Enter HogQL Expression, such as:\n- properties.$current_url\n- person.properties.$geoip_country_name\n- toInt(properties.`Long Field Name`) * 10\n- concat(event, ' ', distinct_id)\n- if(1 < 2, 'small', 'large')")
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lib/components/HogQLEditor/hogQLEditorLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import React from 'react'
export interface HogQLEditorLogicProps {
key: string
value: string | undefined
hogQLTable?: string
onChange: (value: string) => void
textareaRef?: React.MutableRefObject<HTMLTextAreaElement | null>
}
Expand All @@ -32,6 +33,7 @@ export const hogQLEditorLogic = kea<hogQLEditorLogicType>([
const response = await query<HogQLMetadata>({
kind: NodeKind.HogQLMetadata,
expr: values.localValue,
table: props.hogQLTable || 'events',
})
breakpoint()
if (response && Array.isArray(response.errors) && response.errors.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface PropertyFiltersProps {
disablePopover?: boolean
style?: CSSProperties
taxonomicGroupTypes?: TaxonomicFilterGroupType[]
hogQLTable?: string
showNestedArrow?: boolean
eventNames?: string[]
logicalRowDivider?: boolean
Expand All @@ -36,6 +37,7 @@ export function PropertyFilters({
showConditionBadge = false,
disablePopover = false, // use bare PropertyFilter without popover
taxonomicGroupTypes,
hogQLTable,
style = {},
showNestedArrow = false,
eventNames = [],
Expand Down Expand Up @@ -88,6 +90,7 @@ export function PropertyFilters({
onComplete={onComplete}
orFiltering={orFiltering}
taxonomicGroupTypes={taxonomicGroupTypes}
hogQLTable={hogQLTable}
eventNames={eventNames}
propertyGroupType={propertyGroupType}
disablePopover={disablePopover || orFiltering}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function TaxonomicPropertyFilter({
orFiltering,
addText = 'Add filter',
hasRowOperator,
hogQLTable,
}: PropertyFilterInternalProps): JSX.Element {
const pageKey = useMemo(() => pageKeyInput || `filter-${uniqueMemoizedIndex++}`, [pageKeyInput])
const groupTypes = taxonomicGroupTypes || [
Expand Down Expand Up @@ -98,6 +99,7 @@ export function TaxonomicPropertyFilter({
value={cohortOrOtherValue}
onChange={taxonomicOnChange}
taxonomicGroupTypes={groupTypes}
hogQLTable={hogQLTable}
eventNames={eventNames}
/>
)
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/components/PropertyFilters/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ export interface PropertyFilterInternalProps {
orFiltering?: boolean
addText?: string | null
hasRowOperator?: boolean
hogQLTable?: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ export function InfiniteSelectResults({
const RenderComponent = activeTaxonomicGroup?.render

const listComponent = RenderComponent ? (
<RenderComponent value={value} onChange={(newValue) => selectItem(activeTaxonomicGroup, newValue, newValue)} />
<RenderComponent
{...(activeTaxonomicGroup?.componentProps ?? {})}
value={value}
onChange={(newValue) => selectItem(activeTaxonomicGroup, newValue, newValue)}
/>
) : (
<InfiniteList />
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { HogQLEditor } from 'lib/components/HogQLEditor/HogQLEditor'
export interface InlineHogQLEditorProps {
value?: TaxonomicFilterValue
onChange: (value: TaxonomicFilterValue) => void
hogQLTable?: string
}

export function InlineHogQLEditor({ value, onChange }: InlineHogQLEditorProps): JSX.Element {
export function InlineHogQLEditor({ value, onChange, hogQLTable }: InlineHogQLEditorProps): JSX.Element {
return (
<div className="px-2">
<HogQLEditor
onChange={onChange}
value={String(value ?? '')}
hogQLTable={hogQLTable}
submitText={value ? 'Update HogQL expression' : 'Add HogQL expression'}
disableAutoFocus // :TRICKY: No autofocus here. It's controlled in the TaxonomicFilter.
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function TaxonomicFilter({
onClose,
taxonomicGroupTypes,
optionsFromProp,
hogQLTable,
eventNames,
height,
width,
Expand Down Expand Up @@ -50,6 +51,7 @@ export function TaxonomicFilter({
popoverEnabled,
selectFirstItem,
excludedProperties,
hogQLTable,
}

const logic = taxonomicFilterLogic(taxonomicFilterLogicProps)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>({
(taxonomicFilterLogicKey) => taxonomicFilterLogicKey,
],
eventNames: [() => [(_, props) => props.eventNames], (eventNames) => eventNames ?? []],
hogQLTable: [() => [(_, props) => props.hogQLTable], (hogQLTable) => hogQLTable ?? 'events'],
excludedProperties: [
() => [(_, props) => props.excludedProperties],
(excludedProperties) => excludedProperties ?? {},
Expand All @@ -146,16 +147,18 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>({
s.groupAnalyticsTaxonomicGroups,
s.groupAnalyticsTaxonomicGroupNames,
s.eventNames,
s.hogQLTable,
s.excludedProperties,
],
(
teamId,
groupAnalyticsTaxonomicGroups,
groupAnalyticsTaxonomicGroupNames,
eventNames,
hogQLTable,
excludedProperties
): TaxonomicFilterGroup[] => {
const groups = [
const groups: TaxonomicFilterGroup[] = [
{
name: 'Events',
searchPlaceholder: 'events',
Expand Down Expand Up @@ -429,6 +432,7 @@ export const taxonomicFilterLogic = kea<taxonomicFilterLogicType>({
type: TaxonomicFilterGroupType.HogQLExpression,
render: InlineHogQLEditor,
getPopoverHeader: () => 'HogQL',
componentProps: { hogQLTable },
},
...groupAnalyticsTaxonomicGroups,
...groupAnalyticsTaxonomicGroupNames,
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/lib/components/TaxonomicFilter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface TaxonomicFilterProps {
selectFirstItem?: boolean
/** use to filter results in a group by name, currently only working for EventProperties */
excludedProperties?: { [key in TaxonomicFilterGroupType]?: TaxonomicFilterValue[] }
hogQLTable?: string
}

export interface TaxonomicFilterLogicProps extends TaxonomicFilterProps {
Expand Down Expand Up @@ -56,6 +57,8 @@ export interface TaxonomicFilterGroup {
groupTypeIndex?: number
getFullDetailUrl?: (instance: any) => string
excludedProperties?: string[]
/** Passed to the component specified via the `render` key */
componentProps?: Record<string, any>
}

export enum TaxonomicFilterGroupType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface TaxonomicPopoverProps<ValueType extends TaxonomicFilterValue =
allowClear?: boolean
style?: React.CSSProperties
excludedProperties?: { [key in TaxonomicFilterGroupType]?: TaxonomicFilterValue[] }
hogQLTable?: string
}

/** Like TaxonomicPopover, but convenient when you know you will only use string values */
Expand All @@ -45,6 +46,7 @@ export function TaxonomicPopover<ValueType extends TaxonomicFilterValue = Taxono
placeholderClass = 'text-muted',
allowClear = false,
excludedProperties,
hogQLTable,
...buttonPropsRest
}: TaxonomicPopoverProps<ValueType>): JSX.Element {
const [localValue, setLocalValue] = useState<ValueType>(value || ('' as ValueType))
Expand Down Expand Up @@ -85,6 +87,7 @@ export function TaxonomicPopover<ValueType extends TaxonomicFilterValue = Taxono
}}
taxonomicGroupTypes={groupTypes ?? [groupType]}
eventNames={eventNames}
hogQLTable={hogQLTable}
excludedProperties={excludedProperties}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { columnConfiguratorLogic, ColumnConfiguratorLogicProps } from './columnC
import { defaultDataTableColumns, extractExpressionComment, removeExpressionComment } from '../utils'
import { DataTableNode, NodeKind } from '~/queries/schema'
import { LemonModal } from 'lib/lemon-ui/LemonModal'
import { isEventsQuery, taxonomicFilterToHogQl, trimQuotes } from '~/queries/utils'
import { isEventsQuery, taxonomicEventFilterToHogQL, trimQuotes } from '~/queries/utils'
import { TaxonomicFilter } from 'lib/components/TaxonomicFilter/TaxonomicFilter'
import { PropertyKeyInfo } from 'lib/components/PropertyKeyInfo'
import { PropertyFilterIcon } from 'lib/components/PropertyFilters/components/PropertyFilterIcon'
Expand Down Expand Up @@ -166,7 +166,7 @@ function ColumnConfiguratorModal({ query }: ColumnConfiguratorProps): JSX.Elemen
]}
value={undefined}
onChange={(group, value) => {
const column = taxonomicFilterToHogQl(group.type, value)
const column = taxonomicEventFilterToHogQL(group.type, value)
if (column !== null) {
selectColumn(column)
}
Expand Down
24 changes: 15 additions & 9 deletions frontend/src/queries/nodes/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
import clsx from 'clsx'
import { SessionPlayerModal } from 'scenes/session-recordings/player/modal/SessionPlayerModal'
import { OpenEditorButton } from '~/queries/nodes/Node/OpenEditorButton'
import { isEventsQuery, isHogQlAggregation, isHogQLQuery, taxonomicFilterToHogQl } from '~/queries/utils'
import { isEventsQuery, isHogQlAggregation, isHogQLQuery, taxonomicEventFilterToHogQL } from '~/queries/utils'
import { PersonPropertyFilters } from '~/queries/nodes/PersonsNode/PersonPropertyFilters'
import { PersonsSearch } from '~/queries/nodes/PersonsNode/PersonsSearch'
import { PersonDeleteModal } from 'scenes/persons/PersonDeleteModal'
Expand All @@ -55,7 +55,7 @@ interface DataTableProps {
cachedResults?: AnyResponseType
}

const groupTypes = [
const eventGroupTypes = [
TaxonomicFilterGroupType.HogQLExpression,
TaxonomicFilterGroupType.EventProperties,
TaxonomicFilterGroupType.PersonProperties,
Expand Down Expand Up @@ -121,6 +121,9 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
? columnsInResponse ?? columnsInQuery
: columnsInQuery

const groupTypes = eventGroupTypes
const hogQLTable = 'events'

const lemonColumns: LemonTableColumn<DataTableRow, any>[] = [
...columnsInLemonTable.map((key, index) => ({
dataIndex: key as any,
Expand All @@ -144,7 +147,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
},
sorter: undefined, // using custom sorting code
more:
!isReadOnly && showActions && sourceFeatures.has(QueryFeature.eventActionsColumn) ? (
!isReadOnly && showActions && sourceFeatures.has(QueryFeature.selectAndOrderByColumns) ? (
<>
<div className="px-2 py-1">
<div className="font-mono font-bold">{extractExpressionComment(key)}</div>
Expand All @@ -156,11 +159,13 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
<TaxonomicPopover
groupType={TaxonomicFilterGroupType.HogQLExpression}
value={key}
groupTypes={groupTypes}
hogQLTable={hogQLTable}
renderValue={() => <>Edit column</>}
type="tertiary"
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
const hogQl = taxonomicEventFilterToHogQL(g, v)
if (setQuery && hogQl && sourceFeatures.has(QueryFeature.selectAndOrderByColumns)) {
// Typecasting to a query type with select and order_by fields.
// The actual query may or may not be an events query.
Expand All @@ -183,7 +188,6 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
})
}
}}
groupTypes={groupTypes}
/>
<LemonDivider />
{canSort ? (
Expand Down Expand Up @@ -230,12 +234,14 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
<TaxonomicPopover
groupType={TaxonomicFilterGroupType.HogQLExpression}
value={''}
groupTypes={groupTypes}
hogQLTable={hogQLTable}
placeholder={<span className="not-italic">Add column left</span>}
data-attr="datatable-add-column-left"
type="tertiary"
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
const hogQl = taxonomicEventFilterToHogQL(g, v)
if (setQuery && hogQl && sourceFeatures.has(QueryFeature.selectAndOrderByColumns)) {
const isAggregation = isHogQlAggregation(hogQl)
const source = query.source as EventsQuery
Expand All @@ -252,17 +258,18 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
})
}
}}
groupTypes={groupTypes}
/>
<TaxonomicPopover
groupType={TaxonomicFilterGroupType.HogQLExpression}
value={''}
groupTypes={groupTypes}
hogQLTable={hogQLTable}
placeholder={<span className="not-italic">Add column right</span>}
data-attr="datatable-add-column-right"
type="tertiary"
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
const hogQl = taxonomicEventFilterToHogQL(g, v)
if (setQuery && hogQl && sourceFeatures.has(QueryFeature.selectAndOrderByColumns)) {
const isAggregation = isHogQlAggregation(hogQl)
const source = query.source as EventsQuery
Expand All @@ -279,7 +286,6 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
})
}
}}
groupTypes={groupTypes}
/>
{columnsInQuery.filter((c) => c !== '*').length > 1 ? (
<>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/queries/nodes/DataTable/renderColumnMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { QueryContext, DataTableNode } from '~/queries/schema'
import { isEventsQuery, isHogQLQuery, trimQuotes } from '~/queries/utils'
import { extractExpressionComment } from '~/queries/nodes/DataTable/utils'
import { SortingIndicator } from 'lib/lemon-ui/LemonTable/sorting'
import { getQueryFeatures, QueryFeature } from '~/queries/nodes/DataTable/queryFeatures'

export interface ColumnMeta {
title?: JSX.Element | string
Expand All @@ -13,6 +14,7 @@ export interface ColumnMeta {
export function renderColumnMeta(key: string, query: DataTableNode, context?: QueryContext): ColumnMeta {
let width: number | undefined
let title: JSX.Element | string | undefined
const queryFeatures = getQueryFeatures(query.source)

if (isHogQLQuery(query.source)) {
title = key
Expand All @@ -27,8 +29,6 @@ export function renderColumnMeta(key: string, query: DataTableNode, context?: Qu
title = 'Event'
} else if (key === 'person') {
title = 'Person'
} else if (key === 'url') {
title = 'URL / Screen'
} else if (key.startsWith('properties.')) {
title = <PropertyKeyInfo value={trimQuotes(key.substring(11))} type={PropertyFilterType.Event} disableIcon />
} else if (key.startsWith('context.columns.')) {
Expand All @@ -41,7 +41,7 @@ export function renderColumnMeta(key: string, query: DataTableNode, context?: Qu
// NOTE: PropertyFilterType.Event is not a mistake. PropertyKeyInfo only knows events vs elements ¯\_(ツ)_/¯
title = <PropertyKeyInfo value={trimQuotes(key.substring(18))} type={PropertyFilterType.Event} disableIcon />
} else {
title = isEventsQuery(query.source) ? extractExpressionComment(key) : key
title = queryFeatures.has(QueryFeature.selectAndOrderByColumns) ? extractExpressionComment(key) : key
}

if (isEventsQuery(query.source) && !query.allowSorting) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function PersonPropertyFilters({ query, setQuery }: PersonPropertyFilters
onChange={(value: AnyPropertyFilter[]) => setQuery?.({ ...query, properties: value })}
pageKey={`PersonPropertyFilters.${id}`}
taxonomicGroupTypes={[TaxonomicFilterGroupType.PersonProperties]}
hogQLTable="persons"
style={{ marginBottom: 0, marginTop: 0 }}
/>
) : (
Expand Down
Loading
Loading