2
0

feat(engine): ️ Accept variables as webhook data path

This commit is contained in:
Baptiste Arnaud
2022-05-31 11:06:58 +02:00
parent b65d153bf0
commit 26cf38fb21
4 changed files with 61 additions and 11 deletions

View File

@ -25,6 +25,7 @@ export const DataVariableInputs = ({
onValueChange={handleBodyPathChange} onValueChange={handleBodyPathChange}
placeholder="Select the data" placeholder="Select the data"
debounceTimeout={debounceTimeout} debounceTimeout={debounceTimeout}
withVariableButton
/> />
</FormControl> </FormControl>
<FormControl> <FormControl>

View File

@ -8,25 +8,31 @@ import {
PopoverContent, PopoverContent,
Button, Button,
InputProps, InputProps,
HStack,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { Variable } from 'models'
import { useState, useRef, useEffect, ChangeEvent } from 'react' import { useState, useRef, useEffect, ChangeEvent } from 'react'
import { useDebouncedCallback } from 'use-debounce' import { useDebouncedCallback } from 'use-debounce'
import { isEmpty } from 'utils' import { isEmpty } from 'utils'
import { VariablesButton } from './buttons/VariablesButton'
type Props = { type Props = {
selectedItem?: string selectedItem?: string
items: string[] items: string[]
debounceTimeout?: number debounceTimeout?: number
withVariableButton?: boolean
onValueChange?: (value: string) => void onValueChange?: (value: string) => void
} & InputProps } & InputProps
export const SearchableDropdown = ({ export const SearchableDropdown = ({
selectedItem, selectedItem,
items, items,
withVariableButton = false,
debounceTimeout = 1000, debounceTimeout = 1000,
onValueChange, onValueChange,
...inputProps ...inputProps
}: Props) => { }: Props) => {
const [carretPosition, setCarretPosition] = useState<number>(0)
const { onOpen, onClose, isOpen } = useDisclosure() const { onOpen, onClose, isOpen } = useDisclosure()
const [inputValue, setInputValue] = useState(selectedItem ?? '') const [inputValue, setInputValue] = useState(selectedItem ?? '')
const debounced = useDebouncedCallback( const debounced = useDebouncedCallback(
@ -42,7 +48,7 @@ export const SearchableDropdown = ({
.slice(0, 50), .slice(0, 50),
]) ])
const dropdownRef = useRef(null) const dropdownRef = useRef(null)
const inputRef = useRef(null) const inputRef = useRef<HTMLInputElement>(null)
useEffect( useEffect(
() => () => { () => () => {
@ -93,6 +99,37 @@ export const SearchableDropdown = ({
onClose() onClose()
} }
const handleVariableSelected = (variable?: Variable) => {
if (!inputRef.current || !variable) return
const cursorPosition = carretPosition
const textBeforeCursorPosition = inputRef.current.value.substring(
0,
cursorPosition
)
const textAfterCursorPosition = inputRef.current.value.substring(
cursorPosition,
inputRef.current.value.length
)
const newValue =
textBeforeCursorPosition +
`{{${variable.name}}}` +
textAfterCursorPosition
setInputValue(newValue)
debounced(newValue)
inputRef.current.focus()
setTimeout(() => {
if (!inputRef.current) return
inputRef.current.selectionStart = inputRef.current.selectionEnd =
carretPosition + `{{${variable.name}}}`.length
setCarretPosition(inputRef.current.selectionStart)
}, 100)
}
const handleKeyUp = () => {
if (!inputRef.current?.selectionStart) return
setCarretPosition(inputRef.current.selectionStart)
}
return ( return (
<Flex ref={dropdownRef} w="full"> <Flex ref={dropdownRef} w="full">
<Popover <Popover
@ -103,14 +140,23 @@ export const SearchableDropdown = ({
isLazy isLazy
> >
<PopoverTrigger> <PopoverTrigger>
<HStack spacing={0} align={'flex-end'}>
<Input <Input
ref={inputRef} ref={inputRef}
value={inputValue} value={inputValue}
onChange={onInputChange} onChange={onInputChange}
onClick={onOpen} onClick={onOpen}
type="text" type="text"
onKeyUp={handleKeyUp}
{...inputProps} {...inputProps}
/> />
{withVariableButton && (
<VariablesButton
onSelectVariable={handleVariableSelected}
onClick={onClose}
/>
)}
</HStack>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <PopoverContent
maxH="35vh" maxH="35vh"

View File

@ -20,7 +20,7 @@ type Props = {
export const VariablesButton = ({ onSelectVariable, ...props }: Props) => { export const VariablesButton = ({ onSelectVariable, ...props }: Props) => {
return ( return (
<Popover isLazy placement="bottom-end"> <Popover isLazy placement="bottom-end" gutter={0}>
<PopoverTrigger> <PopoverTrigger>
<Flex> <Flex>
<Tooltip label="Insert a variable"> <Tooltip label="Insert a variable">

View File

@ -258,7 +258,10 @@ const executeWebhook = async (
if (!varMapping?.bodyPath || !varMapping.variableId) return newVariables if (!varMapping?.bodyPath || !varMapping.variableId) return newVariables
const existingVariable = variables.find(byId(varMapping.variableId)) const existingVariable = variables.find(byId(varMapping.variableId))
if (!existingVariable) return newVariables if (!existingVariable) return newVariables
const func = Function('data', `return data.${varMapping?.bodyPath}`) const func = Function(
'data',
`return data.${parseVariables(variables)(varMapping?.bodyPath)}`
)
try { try {
const value = func(data) const value = func(data)
updateVariableValue(existingVariable?.id, value) updateVariableValue(existingVariable?.id, value)