Skip to content

Commit

Permalink
feat: Testing of hog transformations (#28050)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Jan 30, 2025
1 parent b71f538 commit 224788a
Show file tree
Hide file tree
Showing 27 changed files with 1,029 additions and 830 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
HogFunctionStatus,
HogFunctionSubTemplateIdType,
HogFunctionTemplateType,
HogFunctionTestInvocationResult,
HogFunctionType,
HogFunctionTypeType,
InsightModel,
Expand Down Expand Up @@ -1908,11 +1909,11 @@ const api = {
async createTestInvocation(
id: HogFunctionType['id'],
data: {
configuration: Partial<HogFunctionType>
configuration: Record<string, any>
mock_async_functions: boolean
globals: any
}
): Promise<any> {
): Promise<HogFunctionTestInvocationResult> {
return await new ApiRequest().hogFunction(id).withAction('invocations').create({ data })
},

Expand Down
18 changes: 11 additions & 7 deletions frontend/src/lib/monaco/CodeEditor.scss
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents {
display: block !important;
.monaco-editor,
.monaco-diff-editor {
.suggest-widget .monaco-list .monaco-list-row > .contents {
display: block !important;
}

.suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label {
width: 100%;
text-align: right;
}
}

.editor-wrapper .monaco-editor,
.editor-wrapper .monaco-diff-editor,
.editor-wrapper .overflow-guard {
border-radius: 0;
}

.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label {
width: 100%;
text-align: right;
}

.CodeEditorResizeable,
.CodeEditorInline {
.monaco-editor {
Expand Down
145 changes: 83 additions & 62 deletions frontend/src/lib/monaco/CodeEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './CodeEditor.scss'

import MonacoEditor, { type EditorProps, loader, Monaco } from '@monaco-editor/react'
import MonacoEditor, { DiffEditor as MonacoDiffEditor, type EditorProps, loader, Monaco } from '@monaco-editor/react'
import { BuiltLogic, useMountedLogic, useValues } from 'kea'
import { Spinner } from 'lib/lemon-ui/Spinner'
import { codeEditorLogic } from 'lib/monaco/codeEditorLogic'
Expand Down Expand Up @@ -35,6 +35,8 @@ export interface CodeEditorProps extends Omit<EditorProps, 'loading' | 'theme'>
onMetadata?: (metadata: HogQLMetadataResponse | null) => void
onMetadataLoading?: (loading: boolean) => void
onError?: (error: string | null, isValidView: boolean) => void
/** The original value to compare against - renders it in diff mode */
originalValue?: string
}
let codeEditorIndex = 0

Expand Down Expand Up @@ -124,6 +126,7 @@ export function CodeEditor({
onError,
onMetadata,
onMetadataLoading,
originalValue,
...editorProps
}: CodeEditorProps): JSX.Element {
const { isDarkModeOn } = useValues(themeLogic)
Expand Down Expand Up @@ -202,73 +205,91 @@ export function CodeEditor({
}
}, [])

const editorOptions: editor.IStandaloneEditorConstructionOptions = {
minimap: {
enabled: false,
},
scrollBeyondLastLine: false,
automaticLayout: true,
fixedOverflowWidgets: true,
glyphMargin: false,
folding: true,
wordWrap: 'off',
lineNumbers: 'on',
tabFocusMode: false,
overviewRulerBorder: true,
hideCursorInOverviewRuler: false,
overviewRulerLanes: 3,
overflowWidgetsDomNode: monacoRoot,
...options,
padding: { bottom: 8, top: 8 },
scrollbar: {
vertical: scrollbarRendering,
horizontal: scrollbarRendering,
...options?.scrollbar,
},
}

const editorOnMount = (editor: importedEditor.IStandaloneCodeEditor, monaco: Monaco): void => {
setMonacoAndEditor([monaco, editor])
initEditor(monaco, editor, editorProps, options ?? {}, builtCodeEditorLogic)
if (onPressCmdEnter) {
monacoDisposables.current.push(
editor.addAction({
id: 'saveAndRunPostHog',
label: 'Save and run query',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
run: () => {
const selection = editor.getSelection()
const model = editor.getModel()
if (selection && model) {
const highlightedText = model.getValueInRange(selection)
onPressCmdEnter(highlightedText, 'selection')
return
}

onPressCmdEnter(editor.getValue(), 'full')
},
})
)
}
if (autoFocus) {
editor.focus()
const model = editor.getModel()
if (model) {
editor.setPosition({
column: model.getLineContent(model.getLineCount()).length + 1,
lineNumber: model.getLineCount(),
})
}
}

onMount?.(editor, monaco)
}

if (originalValue) {
// If originalValue is provided, we render a diff editor instead
return (
<MonacoDiffEditor
key={queryKey}
theme={isDarkModeOn ? 'vs-dark' : 'vs-light'}
loading={<Spinner />}
original={originalValue}
modified={value}
options={editorOptions}
{...editorProps}
/>
)
}

return (
<MonacoEditor // eslint-disable-line react/forbid-elements
key={queryKey}
theme={isDarkModeOn ? 'vs-dark' : 'vs-light'}
loading={<Spinner />}
options={{
// :TRICKY: We need to declare all options here, as omitting something will carry its value from one <CodeEditor> to another.
minimap: {
enabled: false,
},
scrollBeyondLastLine: false,
automaticLayout: true,
fixedOverflowWidgets: true,
glyphMargin: false,
folding: true,
wordWrap: 'off',
lineNumbers: 'on',
tabFocusMode: false,
overviewRulerBorder: true,
hideCursorInOverviewRuler: false,
overviewRulerLanes: 3,
overflowWidgetsDomNode: monacoRoot,
...options,
padding: { bottom: 8, top: 8 },
scrollbar: {
vertical: scrollbarRendering,
horizontal: scrollbarRendering,
...options?.scrollbar,
},
}}
value={value}
onMount={(editor, monaco) => {
setMonacoAndEditor([monaco, editor])
initEditor(monaco, editor, editorProps, options ?? {}, builtCodeEditorLogic)
if (onPressCmdEnter) {
monacoDisposables.current.push(
editor.addAction({
id: 'saveAndRunPostHog',
label: 'Save and run query',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter],
run: () => {
const selection = editor.getSelection()
const model = editor.getModel()
if (selection && model) {
const highlightedText = model.getValueInRange(selection)
onPressCmdEnter(highlightedText, 'selection')
return
}

onPressCmdEnter(editor.getValue(), 'full')
},
})
)
}
if (autoFocus) {
editor.focus()
const model = editor.getModel()
if (model) {
editor.setPosition({
column: model.getLineContent(model.getLineCount()).length + 1,
lineNumber: model.getLineCount(),
})
}
}

onMount?.(editor, monaco)
}}
options={editorOptions}
onMount={editorOnMount}
{...editorProps}
/>
)
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/scenes/feature-flags/JSONEditorInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
.border {
border-radius: var(--radius);

.monaco-editor {
.monaco-editor,
.monaco-diff-editor {
border-radius: inherit;

.overflow-guard {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { hogFunctionConfigurationLogic } from './hogFunctionConfigurationLogic'
import { HogFunctionIconEditable } from './HogFunctionIcon'
import { HogFunctionInputs } from './HogFunctionInputs'
import { HogFunctionStatusIndicator } from './HogFunctionStatusIndicator'
import { HogFunctionTest, HogFunctionTestPlaceholder } from './HogFunctionTest'
import { HogFunctionTest } from './HogFunctionTest'
import { HogFunctionMappings } from './mapping/HogFunctionMappings'
import { HogFunctionEventEstimates } from './metrics/HogFunctionEventEstimates'

Expand Down Expand Up @@ -178,12 +178,11 @@ export function HogFunctionConfiguration({
)
const canEditSource =
displayOptions.canEditSource ??
(['destination', 'email', 'site_destination', 'site_app', 'transformation'].includes(type) && !isLegacyPlugin)
(['destination', 'email', 'site_destination', 'site_app'].includes(type) && !isLegacyPlugin)
const showPersonsCount = displayOptions.showPersonsCount ?? ['broadcast'].includes(type)
const showTesting =
displayOptions.showTesting ??
(['destination', 'internal_destination', 'transformation', 'broadcast', 'email'].includes(type) &&
!isLegacyPlugin)
['destination', 'internal_destination', 'transformation', 'broadcast', 'email'].includes(type)

return (
<div className="space-y-3">
Expand All @@ -197,14 +196,6 @@ export function HogFunctionConfiguration({
}
/>

{type === 'destination' ? (
<LemonBanner type="info">
Hog Functions are in <b>beta</b> and are the next generation of our data pipeline destinations.
You can use pre-existing templates or modify the source Hog code to create your own custom
functions.
</LemonBanner>
) : null}

{hogFunction?.filters?.bytecode_error ? (
<div>
<LemonBanner type="error">
Expand Down Expand Up @@ -469,13 +460,7 @@ export function HogFunctionConfiguration({
) : null}
</div>
)}
{showTesting ? (
!id || id === 'new' ? (
<HogFunctionTestPlaceholder />
) : (
<HogFunctionTest id={id} />
)
) : null}
{showTesting ? <HogFunctionTest /> : null}
<div className="flex justify-end gap-2">{saveButtons}</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 224788a

Please sign in to comment.