Skip to content

Commit

Permalink
feat(datatable): explicitly enable features per query (#17667)
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusandra authored Sep 28, 2023
1 parent e5f54a2 commit 51aebe1
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 46 deletions.
101 changes: 60 additions & 41 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, isPersonsNode, taxonomicFilterToHogQl } from '~/queries/utils'
import { isEventsQuery, isHogQlAggregation, isHogQLQuery, taxonomicFilterToHogQl } 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 @@ -42,6 +42,7 @@ import { InsightEmptyState, InsightErrorState } from 'scenes/insights/EmptyState
import { EventType } from '~/types'
import { SavedQueries } from '~/queries/nodes/DataTable/SavedQueries'
import { HogQLQueryEditor } from '~/queries/nodes/HogQLQuery/HogQLQueryEditor'
import { QueryFeature } from '~/queries/nodes/DataTable/queryFeatures'

interface DataTableProps {
uniqueKey?: string | number
Expand Down Expand Up @@ -88,7 +89,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
} = useValues(builtDataNodeLogic)

const dataTableLogicProps: DataTableLogicProps = { query, vizKey: vizKey, dataKey: dataKey, context }
const { dataTableRows, columnsInQuery, columnsInResponse, queryWithDefaults, canSort } = useValues(
const { dataTableRows, columnsInQuery, columnsInResponse, queryWithDefaults, canSort, sourceFeatures } = useValues(
dataTableLogic(dataTableLogicProps)
)

Expand All @@ -114,8 +115,11 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }

const isReadOnly = setQuery === undefined

const actionsColumnShown = showActions && isEventsQuery(query.source) && columnsInResponse?.includes('*')
const columnsInLemonTable = isHogQLQuery(query.source) ? columnsInResponse ?? columnsInQuery : columnsInQuery
const eventActionsColumnShown =
showActions && sourceFeatures.has(QueryFeature.eventActionsColumn) && columnsInResponse?.includes('*')
const columnsInLemonTable = sourceFeatures.has(QueryFeature.columnsInResponse)
? columnsInResponse ?? columnsInQuery
: columnsInQuery

const lemonColumns: LemonTableColumn<DataTableRow, any>[] = [
...columnsInLemonTable.map((key, index) => ({
Expand All @@ -126,21 +130,21 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
if (index === (expandable ? 1 : 0)) {
return {
children: label,
props: { colSpan: columnsInLemonTable.length + (actionsColumnShown ? 1 : 0) },
props: { colSpan: columnsInLemonTable.length + (eventActionsColumnShown ? 1 : 0) },
}
} else {
return { props: { colSpan: 0 } }
}
} else if (result) {
if (isEventsQuery(query.source) || isHogQLQuery(query.source)) {
if (sourceFeatures.has(QueryFeature.resultIsArrayOfArrays)) {
return renderColumn(key, result[index], result, query, setQuery, context)
}
return renderColumn(key, result[key], result, query, setQuery, context)
}
},
sorter: undefined, // using custom sorting code
more:
!isReadOnly && showActions && isEventsQuery(query.source) ? (
!isReadOnly && showActions && sourceFeatures.has(QueryFeature.eventActionsColumn) ? (
<>
<div className="px-2 py-1">
<div className="font-mono font-bold">{extractExpressionComment(key)}</div>
Expand All @@ -157,21 +161,24 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
if (hogQl && isEventsQuery(query.source)) {
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.
const source = query.source as EventsQuery
const isAggregation = isHogQlAggregation(hogQl)
const isOrderBy = query.source?.orderBy?.[0] === key
const isDescOrderBy = query.source?.orderBy?.[0] === `${key} DESC`
setQuery?.({
const isOrderBy = source.orderBy?.[0] === key
const isDescOrderBy = source.orderBy?.[0] === `${key} DESC`
setQuery({
...query,
source: {
...query.source,
select: query.source.select
...source,
select: source.select
.map((s, i) => (i === index ? hogQl : s))
.filter((c) => (isAggregation ? c !== '*' : true)),
orderBy:
isOrderBy || isDescOrderBy
? [isDescOrderBy ? `${hogQl} DESC` : hogQl]
: query.source?.orderBy,
: source.orderBy,
},
})
}
Expand All @@ -183,7 +190,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
<>
<LemonButton
fullWidth
status={query.source?.orderBy?.[0] === key ? 'primary' : 'stealth'}
status={(query.source as EventsQuery)?.orderBy?.[0] === key ? 'primary' : 'stealth'}
data-attr="datatable-sort-asc"
onClick={() => {
setQuery?.({
Expand All @@ -199,7 +206,11 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
</LemonButton>
<LemonButton
fullWidth
status={query.source?.orderBy?.[0] === `${key} DESC` ? 'primary' : 'stealth'}
status={
(query.source as EventsQuery)?.orderBy?.[0] === `${key} DESC`
? 'primary'
: 'stealth'
}
data-attr="datatable-sort-desc"
onClick={() => {
setQuery?.({
Expand All @@ -225,16 +236,17 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
if (hogQl && isEventsQuery(query.source)) {
if (setQuery && hogQl && sourceFeatures.has(QueryFeature.selectAndOrderByColumns)) {
const isAggregation = isHogQlAggregation(hogQl)
setQuery?.({
const source = query.source as EventsQuery
setQuery({
...query,
source: {
...query.source,
...source,
select: [
...(query.source.select || []).slice(0, index),
...(source.select || []).slice(0, index),
hogQl,
...(query.source.select || []).slice(index),
...(source.select || []).slice(index),
].filter((c) => (isAggregation ? c !== '*' : true)),
} as EventsQuery,
})
Expand All @@ -251,16 +263,17 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
fullWidth
onChange={(v, g) => {
const hogQl = taxonomicFilterToHogQl(g, v)
if (hogQl && isEventsQuery(query.source)) {
if (setQuery && hogQl && sourceFeatures.has(QueryFeature.selectAndOrderByColumns)) {
const isAggregation = isHogQlAggregation(hogQl)
const source = query.source as EventsQuery
setQuery?.({
...query,
source: {
...query.source,
...source,
select: [
...(query.source.select || []).slice(0, index + 1),
...(source.select || []).slice(0, index + 1),
hogQl,
...(query.source.select || []).slice(index + 1),
...(source.select || []).slice(index + 1),
].filter((c) => (isAggregation ? c !== '*' : true)),
} as EventsQuery,
})
Expand Down Expand Up @@ -302,7 +315,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
</>
) : undefined,
})),
...(actionsColumnShown
...(eventActionsColumnShown
? [
{
dataIndex: '__more' as any,
Expand All @@ -311,7 +324,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
if (label) {
return { props: { colSpan: 0 } }
}
if (result && isEventsQuery(query.source) && columnsInResponse?.includes('*')) {
if (result && columnsInResponse?.includes('*')) {
return <EventRowActions event={result[columnsInResponse.indexOf('*')]} />
}
return null
Expand All @@ -328,25 +341,27 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
)

const firstRowLeft = [
showDateRange && (isEventsQuery(query.source) || isHogQLQuery(query.source)) ? (
showDateRange && sourceFeatures.has(QueryFeature.dateRangePicker) ? (
<DateRange query={query.source} setQuery={setQuerySource} />
) : null,
showEventFilter && isEventsQuery(query.source) ? (
<EventName query={query.source} setQuery={setQuerySource} />
showEventFilter && sourceFeatures.has(QueryFeature.eventNameFilter) ? (
<EventName query={query.source as EventsQuery} setQuery={setQuerySource} />
) : null,
showSearch && isPersonsNode(query.source) ? (
<PersonsSearch query={query.source} setQuery={setQuerySource} />
showSearch && sourceFeatures.has(QueryFeature.personsSearch) ? (
<PersonsSearch query={query.source as PersonsNode} setQuery={setQuerySource} />
) : null,
showPropertyFilter && (isEventsQuery(query.source) || isHogQLQuery(query.source)) ? (
<EventPropertyFilters query={query.source} setQuery={setQuerySource} />
showPropertyFilter && sourceFeatures.has(QueryFeature.eventPropertyFilters) ? (
<EventPropertyFilters query={query.source as EventsQuery} setQuery={setQuerySource} />
) : null,
showPropertyFilter && isPersonsNode(query.source) ? (
<PersonPropertyFilters query={query.source} setQuery={setQuerySource} />
showPropertyFilter && sourceFeatures.has(QueryFeature.personPropertyFilters) ? (
<PersonPropertyFilters query={query.source as PersonsNode} setQuery={setQuerySource} />
) : null,
].filter((x) => !!x)

const firstRowRight = [
showSavedQueries && isEventsQuery(query.source) ? <SavedQueries query={query} setQuery={setQuery} /> : null,
showSavedQueries && sourceFeatures.has(QueryFeature.savedEventsQueries) ? (
<SavedQueries query={query} setQuery={setQuery} />
) : null,
].filter((x) => !!x)

const secondRowLeft = [
Expand All @@ -356,7 +371,8 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
].filter((x) => !!x)

const secondRowRight = [
(showColumnConfigurator || showPersistentColumnConfigurator) && isEventsQuery(query.source) ? (
(showColumnConfigurator || showPersistentColumnConfigurator) &&
sourceFeatures.has(QueryFeature.columnConfigurator) ? (
<ColumnConfigurator query={query} setQuery={setQuery} />
) : null,
showExport ? <DataTableExport query={query} setQuery={setQuery} /> : null,
Expand Down Expand Up @@ -413,7 +429,10 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
dataSource={(dataTableRows ?? []) as DataTableRow[]}
rowKey={({ result }: DataTableRow, rowIndex) => {
if (result) {
if (isEventsQuery(query.source)) {
if (
sourceFeatures.has(QueryFeature.resultIsArrayOfArrays) &&
sourceFeatures.has(QueryFeature.columnsInResponse)
) {
if (columnsInResponse?.includes('*')) {
return result[columnsInResponse.indexOf('*')].uuid
} else if (columnsInResponse?.includes('uuid')) {
Expand All @@ -434,7 +453,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
useURLForSorting={false}
emptyState={
responseError ? (
isHogQLQuery(query.source) || isEventsQuery(query.source) ? (
sourceFeatures.has(QueryFeature.displayResponseError) ? (
<InsightErrorState
excludeDetail
title={
Expand All @@ -456,7 +475,7 @@ export function DataTable({ uniqueKey, query, setQuery, context, cachedResults }
)
}
expandable={
expandable && isEventsQuery(query.source) && columnsInResponse?.includes('*')
expandable && columnsInResponse?.includes('*')
? {
expandedRowRender: function renderExpand({ result }) {
if (isEventsQuery(query.source) && Array.isArray(result)) {
Expand Down
21 changes: 16 additions & 5 deletions frontend/src/queries/nodes/DataTable/dataTableLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { FEATURE_FLAGS } from 'lib/constants'
import { dataNodeLogic } from '~/queries/nodes/DataNode/dataNodeLogic'
import { dayjs } from 'lib/dayjs'
import equal from 'fast-deep-equal'
import { getQueryFeatures, QueryFeature } from '~/queries/nodes/DataTable/queryFeatures'

export interface DataTableLogicProps {
vizKey: string
Expand Down Expand Up @@ -61,10 +62,17 @@ export const dataTableLogic = kea<dataTableLogicType>([
})),
selectors({
sourceKind: [(_, p) => [p.query], (query): NodeKind | null => query.source?.kind],
sourceFeatures: [(_, p) => [p.query], (query): Set<QueryFeature> => getQueryFeatures(query.source)],
orderBy: [
(_, p) => [p.query],
(query): string[] | null =>
isEventsQuery(query.source) ? query.source.orderBy || ['timestamp DESC'] : null,
(s, p) => [p.query, s.sourceFeatures],
(query, sourceFeatures): string[] | null =>
sourceFeatures.has(QueryFeature.selectAndOrderByColumns)
? 'orderBy' in query.source // might not be EventsQuery, but something else with orderBy
? (query.source as EventsQuery).orderBy ?? null
: isEventsQuery(query.source)
? ['timestamp DESC']
: null
: null,
{ resultEqualityCheck: objectsEqual },
],
columnsInResponse: [
Expand Down Expand Up @@ -150,6 +158,8 @@ export const dataTableLogic = kea<dataTableLogicType>([
...sortedKeys({
...rest,
full: query.full ?? false,

// The settings under features.tsx override some of these
expandable: query.expandable ?? true,
embedded: query.embedded ?? false,
propertiesViaUrl: query.propertiesViaUrl ?? false,
Expand Down Expand Up @@ -180,8 +190,9 @@ export const dataTableLogic = kea<dataTableLogicType>([
},
],
canSort: [
(s) => [s.queryWithDefaults],
(query: DataTableNode): boolean => isEventsQuery(query.source) && !!query.allowSorting,
(s) => [s.queryWithDefaults, s.sourceFeatures],
(query: DataTableNode, sourceFeatures): boolean =>
sourceFeatures.has(QueryFeature.selectAndOrderByColumns) && !!query.allowSorting,
],
}),
propsChanged(({ actions, props }, oldProps) => {
Expand Down
Loading

0 comments on commit 51aebe1

Please sign in to comment.