+ HTTP overhead
{(elapsedTime / 1000 - timings[timings.length - 1].t).toFixed(3)}s
diff --git a/frontend/src/scenes/debug/DebugScene.tsx b/frontend/src/scenes/debug/DebugScene.tsx
index fffbe0dc4e5211..91d189f97ead47 100644
--- a/frontend/src/scenes/debug/DebugScene.tsx
+++ b/frontend/src/scenes/debug/DebugScene.tsx
@@ -1,20 +1,17 @@
import { useActions, useValues } from 'kea'
-import { CodeEditor } from 'lib/components/CodeEditors'
import { PageHeader } from 'lib/components/PageHeader'
import { LemonButton } from 'lib/lemon-ui/LemonButton'
-import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel'
import { LemonSelect } from 'lib/lemon-ui/LemonSelect'
import { HogQLDebug } from 'scenes/debug/HogQLDebug'
import { Modifiers } from 'scenes/debug/Modifiers'
+import { QueryTabs } from 'scenes/debug/QueryTabs'
import { SceneExport } from 'scenes/sceneTypes'
import { stringifiedExamples } from '~/queries/examples'
import { dataNodeLogic, DataNodeLogicProps } from '~/queries/nodes/DataNode/dataNodeLogic'
-import { Query } from '~/queries/Query/Query'
import { QueryEditor } from '~/queries/QueryEditor/QueryEditor'
import { DataNode, HogQLQuery, Node } from '~/queries/schema'
-import { isDataTableNode, isInsightVizNode } from '~/queries/utils'
import { debugSceneLogic } from './debugSceneLogic'
@@ -48,28 +45,27 @@ function QueryDebug({ query, setQuery, queryKey }: QueryDebugProps): JSX.Element
/>
) : (
-
- setQuery(JSON.stringify({ ...parsed, source: query }, null, 2))
- : (query) => setQuery(JSON.stringify(query, null, 2))
- }
- query={parsed?.source ?? parsed}
- response={response}
- />
-
- setQuery(JSON.stringify(query, null, 2))}
+ setQuery={setQuery}
+ aboveButton={
+ setQuery(JSON.stringify({ ...parsed, source: query }, null, 2))
+ : (query) => setQuery(JSON.stringify(query, null, 2))
+ }
+ query={parsed?.source ?? parsed}
+ response={response}
+ />
+ }
/>
- {response && parsed && (isDataTableNode(parsed as Node) || isInsightVizNode(parsed as Node)) ? (
- setQuery(JSON.stringify(query, null, 2))}
/>
) : null}
diff --git a/frontend/src/scenes/debug/HogQLDebug.tsx b/frontend/src/scenes/debug/HogQLDebug.tsx
index d42f4af5d56640..99be6f2c02d962 100644
--- a/frontend/src/scenes/debug/HogQLDebug.tsx
+++ b/frontend/src/scenes/debug/HogQLDebug.tsx
@@ -1,67 +1,39 @@
import { BindLogic, useValues } from 'kea'
-import { CodeEditor } from 'lib/components/CodeEditors'
-import { CodeSnippet, Language } from 'lib/components/CodeSnippet'
-import { LemonTable } from 'lib/lemon-ui/LemonTable'
+import { LemonDivider } from 'lib/lemon-ui/LemonDivider'
import { Modifiers } from 'scenes/debug/Modifiers'
import { dataNodeLogic, DataNodeLogicProps } from '~/queries/nodes/DataNode/dataNodeLogic'
import { DateRange } from '~/queries/nodes/DataNode/DateRange'
-import { ElapsedTime, Timings } from '~/queries/nodes/DataNode/ElapsedTime'
+import { ElapsedTime } from '~/queries/nodes/DataNode/ElapsedTime'
import { Reload } from '~/queries/nodes/DataNode/Reload'
import { EventPropertyFilters } from '~/queries/nodes/EventsNode/EventPropertyFilters'
import { HogQLQueryEditor } from '~/queries/nodes/HogQLQuery/HogQLQueryEditor'
import { DataNode, HogQLQuery, HogQLQueryResponse } from '~/queries/schema'
+import { QueryTabs } from './QueryTabs'
+
interface HogQLDebugProps {
queryKey: string
query: HogQLQuery
setQuery: (query: DataNode) => void
}
-function toLineColumn(hogql: string, position: number): { line: number; column: number } {
- const lines = hogql.split('\n')
- let line = 0
- let column = 0
- for (let i = 0; i < lines.length; i++) {
- if (position < lines[i].length) {
- line = i + 1
- column = position + 1
- break
- }
- position -= lines[i].length + 1
- }
- return { line, column }
-}
-
-function toLine(hogql: string, position: number): number {
- return toLineColumn(hogql, position).line
-}
-
-function toColumn(hogql: string, position: number): number {
- return toLineColumn(hogql, position).column
-}
-
export function HogQLDebug({ query, setQuery, queryKey }: HogQLDebugProps): JSX.Element {
const dataNodeLogicProps: DataNodeLogicProps = { query, key: queryKey, dataNodeCollectionId: queryKey }
- const {
- dataLoading,
- response: _response,
- responseErrorObject,
- elapsedTime,
- } = useValues(dataNodeLogic(dataNodeLogicProps))
+ const { dataLoading, response: _response } = useValues(dataNodeLogic(dataNodeLogicProps))
const response = _response as HogQLQueryResponse | null
- const clickHouseTime = response?.timings?.find(({ k }) => k === './clickhouse_execute')?.t
return (
+
+
-
{dataLoading ? (
<>
Running query...
@@ -71,87 +43,7 @@ export function HogQLDebug({ query, setQuery, queryKey }: HogQLDebugProps): JSX.
>
) : (
<>
- {response?.error ? (
- <>
-
Error Running Query!
-
- {response.error}
-
- >
- ) : null}
- {response?.hogql ? (
- <>
-
Executed HogQL
-
- {response.hogql}
-
- >
- ) : null}
- {response?.clickhouse ? (
- <>
-
- Executed ClickHouse SQL
- {clickHouseTime !== undefined
- ? ` (${Math.floor(clickHouseTime * 1000) / 1000}s)`
- : ''}
-
-
- {response.clickhouse}
-
- >
- ) : null}
- {response?.metadata ? (
- <>
-
Metadata
-
({
- type: 'error',
- line: toLine(response.hogql ?? '', error.start ?? 0),
- column: toColumn(response.hogql ?? '', error.start ?? 0),
- ...error,
- })),
- ...response.metadata.warnings.map((warn) => ({
- type: 'warning',
- line: toLine(response.hogql ?? '', warn.start ?? 0),
- column: toColumn(response.hogql ?? '', warn.start ?? 0),
- ...warn,
- })),
- ...response.metadata.notices.map((notice) => ({
- type: 'notice',
- line: toLine(response.hogql ?? '', notice.start ?? 0),
- column: toColumn(response.hogql ?? '', notice.start ?? 0),
- ...notice,
- })),
- ].sort((a, b) => (a.start ?? 0) - (b.start ?? 0))}
- columns={[
- { title: 'Line', dataIndex: 'line', key: 'line', width: '40px' },
- { title: 'Column', dataIndex: 'column', key: 'column', width: '40px' },
- { title: 'Type', dataIndex: 'type', key: 'type', width: '80px' },
- { title: 'Message', dataIndex: 'message', key: 'message' },
- ]}
- />
- >
- ) : null}
- {response?.explain ? (
- <>
- Explained ClickHouseSQL
- {response.explain.join('\n')}
- >
- ) : null}
- {response?.timings && elapsedTime !== null ? (
- <>
- Time spent
-
- >
- ) : null}
- Raw response
-
+
>
)}
diff --git a/frontend/src/scenes/debug/Modifiers.tsx b/frontend/src/scenes/debug/Modifiers.tsx
index ea6551ef65f6c7..4b1e2792c9171a 100644
--- a/frontend/src/scenes/debug/Modifiers.tsx
+++ b/frontend/src/scenes/debug/Modifiers.tsx
@@ -13,10 +13,11 @@ export function Modifiers({ setQuery, query, response = null }: ModifiersProps):
if (query === null) {
return null
}
+ const labelClassName = 'flex flex-col gap-1 items-start'
return (
-
- POE:
+
+ POE:
-
- Persons ArgMax:
+
+ Persons ArgMax:
-
- In Cohort Via:
+
+ In Cohort Via:
-
- Materialization Mode:
+
+ Materialization Mode:
| null
+ setQuery: (query: DataNode) => void
+}
+export function QueryTabs({ query, queryKey, setQuery, response }: QueryTabsProps): JSX.Element {
+ const [tab, setTab] = useState(null)
+ const clickHouseTime = (response?.timings as QueryTiming[])?.find(({ k }) => k === './clickhouse_execute')?.t ?? 0
+ const explainTime = (response?.timings as QueryTiming[])?.find(({ k }) => k === './explain')?.t ?? 0
+ const totalTime = (response?.timings as QueryTiming[])?.find(({ k }) => k === '.')?.t ?? 0
+ const hogQLTime = totalTime - explainTime - clickHouseTime
+ const tabs = query
+ ? [
+ response?.error && {
+ key: 'error',
+ label: 'Error',
+ content: (
+ <>
+ Error Running Query!
+
+ {response.error}
+
+ >
+ ),
+ },
+ isInsightVizNode(query) && {
+ key: 'viz',
+ label: 'Visualization',
+ content: setQuery(query)} />,
+ },
+ isInsightQueryNode(query) && {
+ key: 'insight',
+ label: 'Insight',
+ content: (
+ setQuery(query)}
+ />
+ ),
+ },
+ isDataTableNode(query) && {
+ key: 'table',
+ label: 'Data Table',
+ content: setQuery(query)} />,
+ },
+
+ (response?.result || response?.results) && {
+ key: 'result',
+ label: 'Result JSON',
+ content: (
+
+ ),
+ },
+ response?.hogql && {
+ key: 'hogql',
+ label: `HogQL${hogQLTime ? ` (${Math.floor(hogQLTime * 10) / 10}s)` : ''}`,
+ content: (
+
+ ),
+ },
+ response?.clickhouse && {
+ key: 'clickhouse',
+ label: `ClickHouse${clickHouseTime ? ` (${Math.floor(clickHouseTime * 10) / 10}s)` : ''}`,
+ content: (
+
+ ),
+ },
+ response?.explain && {
+ key: 'explain',
+ label: 'Explain',
+ content: {response.explain.join('\n')},
+ },
+ response?.timings && {
+ key: 'timings',
+ label: 'Timings',
+ content: ,
+ },
+ response && {
+ key: 'response',
+ label: 'Full response',
+ content: (
+
+ ),
+ },
+ response?.metadata && {
+ key: 'metadata',
+ label: 'Metadata',
+ content: (
+ ({
+ type: 'error',
+ line: toLine(response.hogql ?? '', error.start ?? 0),
+ column: toColumn(response.hogql ?? '', error.start ?? 0),
+ ...error,
+ })),
+ ...(response.metadata as HogQLMetadataResponse).warnings.map((warn) => ({
+ type: 'warning',
+ line: toLine(response.hogql ?? '', warn.start ?? 0),
+ column: toColumn(response.hogql ?? '', warn.start ?? 0),
+ ...warn,
+ })),
+ ...(response.metadata as HogQLMetadataResponse).notices.map((notice) => ({
+ type: 'notice',
+ line: toLine(response.hogql ?? '', notice.start ?? 0),
+ column: toColumn(response.hogql ?? '', notice.start ?? 0),
+ ...notice,
+ })),
+ ].sort((a, b) => (a.start ?? 0) - (b.start ?? 0))}
+ columns={[
+ { title: 'Line', dataIndex: 'line', key: 'line', width: '40px' },
+ { title: 'Column', dataIndex: 'column', key: 'column', width: '40px' },
+ { title: 'Type', dataIndex: 'type', key: 'type', width: '80px' },
+ { title: 'Message', dataIndex: 'message', key: 'message' },
+ ]}
+ />
+ ),
+ },
+ ]
+ .filter(Boolean)
+ .map((tab) => ({ ...tab, content: {tab.content} }))
+ : []
+
+ return (
+
+ setTab(t)} tabs={tabs} />
+
+ )
+}