2
0

chore(editor): ♻️ Revert tables to arrays

Yet another refacto. I improved many many mechanisms on this one including dnd. It is now end 2 end tested 🎉
This commit is contained in:
Baptiste Arnaud
2022-02-04 19:00:08 +01:00
parent 8a350eee6c
commit 524ef0812c
123 changed files with 2998 additions and 3112 deletions

View File

@ -8,13 +8,17 @@ import {
} from '@chakra-ui/react'
import { ExpandIcon } from 'assets/icons'
import {
ConditionItem,
ConditionStep,
InputStepType,
IntegrationStepType,
LogicStepType,
Step,
StepIndices,
StepOptions,
TextBubbleStep,
Webhook,
WebhookStep,
} from 'models'
import { useRef } from 'react'
import {
@ -37,9 +41,9 @@ type Props = {
step: Exclude<Step, TextBubbleStep>
webhook?: Webhook
onExpandClick: () => void
onOptionsChange: (options: StepOptions) => void
onWebhookChange: (updates: Partial<Webhook>) => void
onStepChange: (updates: Partial<Step>) => void
onTestRequestClick: () => void
indices: StepIndices
}
export const SettingsPopoverContent = ({ onExpandClick, ...props }: Props) => {
@ -79,23 +83,35 @@ export const SettingsPopoverContent = ({ onExpandClick, ...props }: Props) => {
export const StepSettings = ({
step,
webhook,
onOptionsChange,
onWebhookChange,
onStepChange,
onTestRequestClick,
indices,
}: {
step: Step
webhook?: Webhook
onOptionsChange: (options: StepOptions) => void
onWebhookChange: (updates: Partial<Webhook>) => void
onStepChange: (step: Partial<Step>) => void
onTestRequestClick: () => void
indices: StepIndices
}) => {
const handleOptionsChange = (options: StepOptions) => {
onStepChange({ options } as Partial<Step>)
}
const handleWebhookChange = (updates: Partial<Webhook>) => {
onStepChange({
webhook: { ...(step as WebhookStep).webhook, ...updates },
} as Partial<Step>)
}
const handleItemChange = (updates: Partial<ConditionItem>) => {
onStepChange({
items: [{ ...(step as ConditionStep).items[0], ...updates }],
} as Partial<Step>)
}
switch (step.type) {
case InputStepType.TEXT: {
return (
<TextInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -103,7 +119,7 @@ export const StepSettings = ({
return (
<NumberInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -111,7 +127,7 @@ export const StepSettings = ({
return (
<EmailInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -119,7 +135,7 @@ export const StepSettings = ({
return (
<UrlInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -127,7 +143,7 @@ export const StepSettings = ({
return (
<DateInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -135,7 +151,7 @@ export const StepSettings = ({
return (
<PhoneNumberSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -143,7 +159,7 @@ export const StepSettings = ({
return (
<ChoiceInputSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -151,23 +167,20 @@ export const StepSettings = ({
return (
<SetVariableSettings
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
case LogicStepType.CONDITION: {
return (
<ConditionSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
/>
<ConditionSettingsBody step={step} onItemChange={handleItemChange} />
)
}
case LogicStepType.REDIRECT: {
return (
<RedirectSettings
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
@ -175,7 +188,7 @@ export const StepSettings = ({
return (
<GoogleSheetsSettingsBody
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
stepId={step.id}
/>
)
@ -184,18 +197,18 @@ export const StepSettings = ({
return (
<GoogleAnalyticsSettings
options={step.options}
onOptionsChange={onOptionsChange}
onOptionsChange={handleOptionsChange}
/>
)
}
case IntegrationStepType.WEBHOOK: {
return (
<WebhookSettings
options={step.options}
webhook={webhook as Webhook}
onOptionsChange={onOptionsChange}
onWebhookChange={onWebhookChange}
step={step}
onOptionsChange={handleOptionsChange}
onWebhookChange={handleWebhookChange}
onTestRequestClick={onTestRequestClick}
indices={indices}
/>
)
}

View File

@ -1,33 +1,40 @@
import { Flex } from '@chakra-ui/react'
import { DropdownList } from 'components/shared/DropdownList'
import { TableList } from 'components/shared/TableList'
import { Comparison, ConditionOptions, LogicalOperator, Table } from 'models'
import {
Comparison,
ConditionItem,
ConditionStep,
LogicalOperator,
} from 'models'
import React from 'react'
import { ComparisonItem } from './ComparisonsItem'
type ConditionSettingsBodyProps = {
options: ConditionOptions
onOptionsChange: (options: ConditionOptions) => void
step: ConditionStep
onItemChange: (updates: Partial<ConditionItem>) => void
}
export const ConditionSettingsBody = ({
options,
onOptionsChange,
step,
onItemChange,
}: ConditionSettingsBodyProps) => {
const handleComparisonsChange = (comparisons: Table<Comparison>) =>
onOptionsChange({ ...options, comparisons })
const itemContent = step.items[0].content
const handleComparisonsChange = (comparisons: Comparison[]) =>
onItemChange({ content: { ...itemContent, comparisons } })
const handleLogicalOperatorChange = (logicalOperator: LogicalOperator) =>
onOptionsChange({ ...options, logicalOperator })
onItemChange({ content: { ...itemContent, logicalOperator } })
return (
<TableList<Comparison>
initialItems={options.comparisons}
initialItems={itemContent.comparisons}
onItemsChange={handleComparisonsChange}
Item={ComparisonItem}
ComponentBetweenItems={() => (
<Flex justify="center">
<DropdownList<LogicalOperator>
currentItem={options.logicalOperator}
currentItem={itemContent.logicalOperator}
onItemSelect={handleLogicalOperatorChange}
items={Object.values(LogicalOperator)}
/>

View File

@ -6,14 +6,12 @@ import { useTypebot } from 'contexts/TypebotContext'
import { CredentialsType } from 'db'
import {
Cell,
defaultTable,
ExtractingCell,
GoogleSheetsAction,
GoogleSheetsGetOptions,
GoogleSheetsInsertRowOptions,
GoogleSheetsOptions,
GoogleSheetsUpdateRowOptions,
Table,
} from 'models'
import React, { useMemo } from 'react'
import {
@ -60,7 +58,7 @@ export const GoogleSheetsSettingsBody = ({
const newOptions: GoogleSheetsGetOptions = {
...options,
action,
cellsToExtract: defaultTable,
cellsToExtract: [],
}
return onOptionsChange({ ...newOptions })
}
@ -68,7 +66,7 @@ export const GoogleSheetsSettingsBody = ({
const newOptions: GoogleSheetsInsertRowOptions = {
...options,
action,
cellsToInsert: defaultTable,
cellsToInsert: [],
}
return onOptionsChange({ ...newOptions })
}
@ -76,7 +74,7 @@ export const GoogleSheetsSettingsBody = ({
const newOptions: GoogleSheetsUpdateRowOptions = {
...options,
action,
cellsToUpsert: defaultTable,
cellsToUpsert: [],
}
return onOptionsChange({ ...newOptions })
}
@ -155,16 +153,16 @@ const ActionOptions = ({
sheet: Sheet
onOptionsChange: (options: GoogleSheetsOptions) => void
}) => {
const handleInsertColumnsChange = (cellsToInsert: Table<Cell>) =>
const handleInsertColumnsChange = (cellsToInsert: Cell[]) =>
onOptionsChange({ ...options, cellsToInsert } as GoogleSheetsOptions)
const handleUpsertColumnsChange = (cellsToUpsert: Table<Cell>) =>
const handleUpsertColumnsChange = (cellsToUpsert: Cell[]) =>
onOptionsChange({ ...options, cellsToUpsert } as GoogleSheetsOptions)
const handleReferenceCellChange = (referenceCell: Cell) =>
onOptionsChange({ ...options, referenceCell } as GoogleSheetsOptions)
const handleExtractingCellsChange = (cellsToExtract: Table<ExtractingCell>) =>
const handleExtractingCellsChange = (cellsToExtract: ExtractingCell[]) =>
onOptionsChange({ ...options, cellsToExtract } as GoogleSheetsOptions)
const UpdatingCellItem = useMemo(
@ -194,9 +192,8 @@ const ActionOptions = ({
<Stack>
<Text>Row to select</Text>
<CellWithValueStack
id={'reference'}
columns={sheet.columns}
item={options.referenceCell ?? {}}
item={options.referenceCell ?? { id: 'reference' }}
onItemChange={handleReferenceCellChange}
/>
<Text>Cells to update</Text>
@ -213,9 +210,8 @@ const ActionOptions = ({
<Stack>
<Text>Row to select</Text>
<CellWithValueStack
id={'reference'}
columns={sheet.columns}
item={options.referenceCell ?? {}}
item={options.referenceCell ?? { id: 'reference' }}
onItemChange={handleReferenceCellChange}
/>
<Text>Cells to extract</Text>

View File

@ -1,5 +1,4 @@
import { FormLabel, Stack } from '@chakra-ui/react'
import { DebouncedInput } from 'components/shared/DebouncedInput'
import { SwitchWithLabel } from 'components/shared/SwitchWithLabel'
import { InputWithVariableButton } from 'components/shared/TextboxWithVariableButton'
import { RedirectOptions } from 'models'

View File

@ -20,7 +20,6 @@ export const HeadersInputs = (props: TableListItemProps<KeyValue>) => (
)
export const KeyValueInputs = ({
id,
item,
onItemChange,
keyPlaceholder,
@ -40,18 +39,18 @@ export const KeyValueInputs = ({
return (
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
<FormControl>
<FormLabel htmlFor={'key' + id}>Key:</FormLabel>
<FormLabel htmlFor={'key' + item.id}>Key:</FormLabel>
<InputWithVariableButton
id={'key' + id}
id={'key' + item.id}
initialValue={item.key ?? ''}
onChange={handleKeyChange}
placeholder={keyPlaceholder}
/>
</FormControl>
<FormControl>
<FormLabel htmlFor={'value' + id}>Value:</FormLabel>
<FormLabel htmlFor={'value' + item.id}>Value:</FormLabel>
<InputWithVariableButton
id={'value' + id}
id={'value' + item.id}
initialValue={item.value ?? ''}
onChange={handleValueChange}
placeholder={valuePlaceholder}

View File

@ -5,7 +5,6 @@ import { VariableSearchInput } from 'components/shared/VariableSearchInput'
import { VariableForTest, Variable } from 'models'
export const VariableForTestInputs = ({
id,
item,
onItemChange,
}: TableListItemProps<VariableForTest>) => {
@ -18,17 +17,17 @@ export const VariableForTestInputs = ({
return (
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
<FormControl>
<FormLabel htmlFor={'name' + id}>Variable name:</FormLabel>
<FormLabel htmlFor={'name' + item.id}>Variable name:</FormLabel>
<VariableSearchInput
id={'name' + id}
id={'name' + item.id}
initialVariableId={item.variableId}
onSelectVariable={handleVariableSelect}
/>
</FormControl>
<FormControl>
<FormLabel htmlFor={'value' + id}>Test value:</FormLabel>
<FormLabel htmlFor={'value' + item.id}>Test value:</FormLabel>
<DebouncedInput
id={'value' + id}
id={'value' + item.id}
initialValue={item.value ?? ''}
onChange={handleValueChange}
/>

View File

@ -15,11 +15,12 @@ import { useTypebot } from 'contexts/TypebotContext'
import {
HttpMethod,
KeyValue,
Table,
WebhookOptions,
VariableForTest,
Webhook,
ResponseVariableMapping,
WebhookStep,
StepIndices,
} from 'models'
import { DropdownList } from 'components/shared/DropdownList'
import { TableList, TableListItemProps } from 'components/shared/TableList'
@ -34,19 +35,19 @@ import { VariableForTestInputs } from './VariableForTestInputs'
import { DataVariableInputs } from './ResponseMappingInputs'
type Props = {
webhook: Webhook
options?: WebhookOptions
step: WebhookStep
onOptionsChange: (options: WebhookOptions) => void
onWebhookChange: (updates: Partial<Webhook>) => void
onTestRequestClick: () => void
indices: StepIndices
}
export const WebhookSettings = ({
options,
step: { webhook, options },
onOptionsChange,
webhook,
onWebhookChange,
onTestRequestClick,
indices,
}: Props) => {
const { typebot, save } = useTypebot()
const [isTestResponseLoading, setIsTestResponseLoading] = useState(false)
@ -62,23 +63,23 @@ export const WebhookSettings = ({
const handleMethodChange = (method: HttpMethod) => onWebhookChange({ method })
const handleQueryParamsChange = (queryParams: Table<KeyValue>) =>
const handleQueryParamsChange = (queryParams: KeyValue[]) =>
onWebhookChange({ queryParams })
const handleHeadersChange = (headers: Table<KeyValue>) =>
const handleHeadersChange = (headers: KeyValue[]) =>
onWebhookChange({ headers })
const handleBodyChange = (body: string) => onWebhookChange({ body })
const handleVariablesChange = (variablesForTest: Table<VariableForTest>) =>
options && onOptionsChange({ ...options, variablesForTest })
const handleVariablesChange = (variablesForTest: VariableForTest[]) =>
onOptionsChange({ ...options, variablesForTest })
const handleResponseMappingChange = (
responseVariableMapping: Table<ResponseVariableMapping>
) => options && onOptionsChange({ ...options, responseVariableMapping })
responseVariableMapping: ResponseVariableMapping[]
) => onOptionsChange({ ...options, responseVariableMapping })
const handleTestRequestClick = async () => {
if (!typebot || !webhook) return
if (!typebot) return
setIsTestResponseLoading(true)
onTestRequestClick()
await save()
@ -86,9 +87,10 @@ export const WebhookSettings = ({
typebot.id,
webhook.id,
convertVariableForTestToVariables(
options?.variablesForTest,
options.variablesForTest,
typebot.variables
)
),
indices
)
if (error) return toast({ title: error.name, description: error.message })
setTestResponse(JSON.stringify(data, undefined, 2))
@ -196,9 +198,7 @@ export const WebhookSettings = ({
</AccordionButton>
<AccordionPanel pb={4} as={Stack} spacing="6">
<TableList<ResponseVariableMapping>
initialItems={
options?.responseVariableMapping ?? { byId: {}, allIds: [] }
}
initialItems={options.responseVariableMapping}
onItemsChange={handleResponseMappingChange}
Item={ResponseMappingInputs}
addLabel="Add an entry"