diff --git a/frontend/src/queries/nodes/DataNode/ElapsedTime.tsx b/frontend/src/queries/nodes/DataNode/ElapsedTime.tsx index 3838c6c241006..f09ab068e5f14 100644 --- a/frontend/src/queries/nodes/DataNode/ElapsedTime.tsx +++ b/frontend/src/queries/nodes/DataNode/ElapsedTime.tsx @@ -5,18 +5,13 @@ import { Popover } from 'lib/lemon-ui/Popover' import clsx from 'clsx' import { QueryTiming } from '~/queries/schema' -function ElapsedTimeWithTimings({ - elapsedTime, - hasError, - timings, -}: { - elapsedTime: number - hasError: boolean +export interface TimingsProps { timings: QueryTiming[] -}): JSX.Element | null { - const [popoverVisible, setPopoverVisible] = useState(false) + elapsedTime: number +} - const overlay = ( +export function Timings({ timings, elapsedTime }: TimingsProps): JSX.Element | null { + return (
{timings.map(({ k: key, t: time }) => (
) +} + +function ElapsedTimeWithTimings({ + elapsedTime, + hasError, + timings, +}: { + elapsedTime: number + hasError: boolean + timings: QueryTiming[] +}): JSX.Element | null { + const [popoverVisible, setPopoverVisible] = useState(false) return ( setPopoverVisible(false)} visible={popoverVisible} placement="bottom" - overlay={overlay} + overlay={} >
setPopoverVisible((visible) => !visible)} diff --git a/frontend/src/scenes/appScenes.ts b/frontend/src/scenes/appScenes.ts index 08e3d86ff793a..c72cdcf50a97f 100644 --- a/frontend/src/scenes/appScenes.ts +++ b/frontend/src/scenes/appScenes.ts @@ -73,7 +73,7 @@ export const appScenes: Record any> = { [Scene.Unsubscribe]: () => import('./Unsubscribe/Unsubscribe'), [Scene.IntegrationsRedirect]: () => import('./IntegrationsRedirect/IntegrationsRedirect'), [Scene.IngestionWarnings]: () => import('./data-management/ingestion-warnings/IngestionWarningsView'), - [Scene.DebugQuery]: () => import('./query/QueryScene'), + [Scene.DebugQuery]: () => import('./debug/DebugScene'), [Scene.VerifyEmail]: () => import('./authentication/signup/verify-email/VerifyEmail'), [Scene.Feedback]: () => import('./feedback/Feedback'), [Scene.Notebook]: () => import('./notebooks/NotebookScene'), diff --git a/frontend/src/scenes/debug/DebugScene.tsx b/frontend/src/scenes/debug/DebugScene.tsx new file mode 100644 index 0000000000000..c69aa492dd33f --- /dev/null +++ b/frontend/src/scenes/debug/DebugScene.tsx @@ -0,0 +1,94 @@ +import { debugSceneLogic } from './debugSceneLogic' +import { SceneExport } from 'scenes/sceneTypes' +import { PageHeader } from 'lib/components/PageHeader' +import { Query } from '~/queries/Query/Query' +import { useActions, useValues } from 'kea' +import { stringifiedExamples } from '~/queries/examples' +import { LemonSelect } from 'lib/lemon-ui/LemonSelect' +import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel' +import { LemonButton } from 'lib/lemon-ui/LemonButton' +import { HogQLQuery } from '~/queries/schema' +import { HogQLDebug } from 'scenes/debug/HogQLDebug' + +export function DebugScene(): JSX.Element { + const { query } = useValues(debugSceneLogic) + const { setQuery } = useActions(debugSceneLogic) + + let parsed: Record | undefined + try { + parsed = JSON.parse(query) + } catch (e) { + // do nothing + } + + const showQueryEditor = !( + parsed && + parsed.kind == 'DataTableNode' && + parsed.source.kind == 'HogQLQuery' && + (parsed.full || parsed.showHogQLEditor) + ) + + return ( +
+ + setQuery(stringifiedExamples.HogQLRaw)} + > + HogQL Debug + + setQuery(stringifiedExamples.HogQLTable)} + > + HogQL Table + + setQuery(stringifiedExamples.Events)} + > + Any Query + + + k !== 'HogQLTable' && k !== 'HogQLRaw') + .map(([k, v]) => { + return { label: k, value: v } + })} + onChange={(v) => { + if (v) { + setQuery(v) + } + }} + /> + + + } + /> + {parsed && parsed?.kind === 'HogQLQuery' ? ( + setQuery(JSON.stringify(query, null, 2))} + /> + ) : ( + setQuery(JSON.stringify(query, null, 2))} + context={{ + showQueryEditor: showQueryEditor, + }} + /> + )} +
+ ) +} + +export const scene: SceneExport = { + component: DebugScene, + logic: debugSceneLogic, +} diff --git a/frontend/src/scenes/debug/HogQLDebug.tsx b/frontend/src/scenes/debug/HogQLDebug.tsx new file mode 100644 index 0000000000000..62b495947c04f --- /dev/null +++ b/frontend/src/scenes/debug/HogQLDebug.tsx @@ -0,0 +1,69 @@ +import { HogQLQueryEditor } from '~/queries/nodes/HogQLQuery/HogQLQueryEditor' +import { DataNode, HogQLQuery } from '~/queries/schema' +import { DateRange } from '~/queries/nodes/DataNode/DateRange' +import { EventPropertyFilters } from '~/queries/nodes/EventsNode/EventPropertyFilters' +import { BindLogic, useValues } from 'kea' +import { dataNodeLogic, DataNodeLogicProps } from '~/queries/nodes/DataNode/dataNodeLogic' +import { ElapsedTime, Timings } from '~/queries/nodes/DataNode/ElapsedTime' +import { CodeSnippet, Language } from 'lib/components/CodeSnippet' +import { CodeEditor } from 'lib/components/CodeEditors' + +interface HogQLDebugProps { + query: HogQLQuery + setQuery: (query: DataNode) => void +} +export function HogQLDebug({ query, setQuery }: HogQLDebugProps): JSX.Element { + const dataNodeLogicProps: DataNodeLogicProps = { query, key: 'debug-scene' } + const { dataLoading, response, responseErrorObject, elapsedTime } = useValues(dataNodeLogic(dataNodeLogicProps)) + return ( + +
+ +
+ + +
+ {dataLoading ? ( + <> +

Running query...

+
+ Time elapsed: +
+ + ) : ( + <> + {response?.hogql ? ( + <> +

Executed HogQL

+ + {response.hogql} + + + ) : null} + {response?.clickhouse ? ( + <> +

Executed ClickHouse SQL

+ + {response.clickhouse} + + + ) : null} + {response?.timings && elapsedTime !== null ? ( + <> +

Time spent

+ + + ) : null} +

Raw response

+ + + )} +
+
+ ) +} diff --git a/frontend/src/scenes/query/querySceneLogic.ts b/frontend/src/scenes/debug/debugSceneLogic.ts similarity index 75% rename from frontend/src/scenes/query/querySceneLogic.ts rename to frontend/src/scenes/debug/debugSceneLogic.ts index c53fd3911ec91..aaf975c26ee85 100644 --- a/frontend/src/scenes/query/querySceneLogic.ts +++ b/frontend/src/scenes/debug/debugSceneLogic.ts @@ -1,14 +1,14 @@ import { actions, kea, path, reducers } from 'kea' -import type { querySceneLogicType } from './querySceneLogicType' +import type { debugSceneLogicType } from './debugSceneLogicType' import { actionToUrl, urlToAction } from 'kea-router' import { urls } from 'scenes/urls' import { stringifiedExamples } from '~/queries/examples' -const DEFAULT_QUERY: string = stringifiedExamples['Events'] +const DEFAULT_QUERY: string = stringifiedExamples['HogQLRaw'] -export const querySceneLogic = kea([ - path(['scenes', 'query', 'querySceneLogic']), +export const debugSceneLogic = kea([ + path(['scenes', 'query', 'debugSceneLogic']), actions({ setQuery: (query: string) => ({ query: query }), }), diff --git a/frontend/src/scenes/query/QueryScene.tsx b/frontend/src/scenes/query/QueryScene.tsx deleted file mode 100644 index d0cdf976cec05..0000000000000 --- a/frontend/src/scenes/query/QueryScene.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { querySceneLogic } from './querySceneLogic' -import { SceneExport } from 'scenes/sceneTypes' -import { PageHeader } from 'lib/components/PageHeader' -import { Query } from '~/queries/Query/Query' -import { useActions, useValues } from 'kea' -import { stringifiedExamples } from '~/queries/examples' -import { LemonSelect } from 'lib/lemon-ui/LemonSelect' -import { LemonLabel } from 'lib/lemon-ui/LemonLabel/LemonLabel' - -export function QueryScene(): JSX.Element { - const { query } = useValues(querySceneLogic) - const { setQuery } = useActions(querySceneLogic) - - let showEditor = true - try { - const parsed = JSON.parse(query) - if ( - parsed && - parsed.kind == 'DataTableNode' && - parsed.source.kind == 'HogQLQuery' && - (parsed.full || parsed.showHogQLEditor) - ) { - showEditor = false - } - } catch (e) { - // do nothing - } - - return ( -
- - Example queries:{' '} - { - return { label: k, value: v } - })} - onChange={(v) => { - if (v) { - setQuery(v) - } - }} - /> - - } - /> - - setQuery(JSON.stringify(query, null, 2))} - context={{ - showQueryEditor: showEditor, - }} - /> -
- ) -} - -export const scene: SceneExport = { - component: QueryScene, - logic: querySceneLogic, -}