✨ Introducing The Forge (#1072)
The Forge allows anyone to easily create their own Typebot Block. Closes #380
This commit is contained in:
@@ -43,13 +43,13 @@ test.describe.parallel('Buttons input block', () => {
|
||||
await expect(page.getByTestId('guest-bubble')).toHaveText('Item 3')
|
||||
await page.click('button[aria-label="Close"]')
|
||||
|
||||
await page.click('[data-testid="block2-icon"]')
|
||||
await page.getByTestId('block block2').click({ position: { x: 0, y: 0 } })
|
||||
await page.click('text=Multiple choice?')
|
||||
await page.getByLabel('Button label:').fill('Go')
|
||||
await page.getByPlaceholder('Select a variable').nth(1).click()
|
||||
await page.getByText('var1').click()
|
||||
await expect(page.getByText('Setvar1')).toBeVisible()
|
||||
await page.click('[data-testid="block2-icon"]')
|
||||
await page.getByTestId('block block2').click({ position: { x: 0, y: 0 } })
|
||||
|
||||
await page.locator('text=Item 1').hover()
|
||||
await page.waitForTimeout(1000)
|
||||
@@ -83,7 +83,7 @@ test('Variable buttons should work', async ({ page }) => {
|
||||
await expect(page.locator('text=Ok great!')).toBeVisible()
|
||||
await page.click('text="Item 1"')
|
||||
await page.fill('input[value="Item 1"]', '{{Item 2}}')
|
||||
await page.click('[data-testid="block1-icon"]')
|
||||
await page.getByTestId('block block1').click({ position: { x: 0, y: 0 } })
|
||||
await page.click('text=Multiple choice?')
|
||||
await page.click('text="Restart"')
|
||||
await page
|
||||
|
||||
@@ -75,7 +75,7 @@ test.describe.parallel('Picture choice input block', () => {
|
||||
page.locator('typebot-standard').getByText('Third image')
|
||||
).toBeVisible()
|
||||
|
||||
await page.getByTestId('block2-icon').click()
|
||||
await page.getByTestId('block block2').click({ position: { x: 0, y: 0 } })
|
||||
await page.getByText('Multiple choice?').click()
|
||||
await page.getByLabel('Submit button label:').fill('Go')
|
||||
await page.getByRole('button', { name: 'Restart' }).click()
|
||||
@@ -94,7 +94,7 @@ test.describe.parallel('Picture choice input block', () => {
|
||||
page.locator('typebot-standard').getByText('First image, Second image')
|
||||
).toBeVisible()
|
||||
|
||||
await page.getByTestId('block2-icon').click()
|
||||
await page.getByTestId('block block2').click({ position: { x: 0, y: 0 } })
|
||||
await page.getByText('Is searchable?').click()
|
||||
await page.getByLabel('Input placeholder:').fill('Search...')
|
||||
await page.getByRole('button', { name: 'Restart' }).click()
|
||||
|
||||
@@ -26,7 +26,7 @@ import { SpreadsheetsDropdown } from './SpreadsheetDropdown'
|
||||
import { CellWithValueStack } from './CellWithValueStack'
|
||||
import { CellWithVariableIdStack } from './CellWithVariableIdStack'
|
||||
import { GoogleSheetConnectModal } from './GoogleSheetsConnectModal'
|
||||
import { TableListItemProps, TableList } from '@/components/TableList'
|
||||
import { TableList } from '@/components/TableList'
|
||||
import { CredentialsDropdown } from '@/features/credentials/components/CredentialsDropdown'
|
||||
import { RowsFilterTableList } from './RowsFilterTableList'
|
||||
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
|
||||
@@ -177,33 +177,22 @@ const ActionOptions = ({
|
||||
totalRowsToExtract,
|
||||
} as GoogleSheetsBlock['options'])
|
||||
|
||||
const UpdatingCellItem = useMemo(
|
||||
() =>
|
||||
function Component(props: TableListItemProps<Cell>) {
|
||||
return <CellWithValueStack {...props} columns={sheet?.columns ?? []} />
|
||||
},
|
||||
[sheet?.columns]
|
||||
)
|
||||
|
||||
const ExtractingCellItem = useMemo(
|
||||
() =>
|
||||
function Component(props: TableListItemProps<ExtractingCell>) {
|
||||
return (
|
||||
<CellWithVariableIdStack {...props} columns={sheet?.columns ?? []} />
|
||||
)
|
||||
},
|
||||
[sheet?.columns]
|
||||
)
|
||||
|
||||
switch (options.action) {
|
||||
case GoogleSheetsAction.INSERT_ROW:
|
||||
return (
|
||||
<TableList<Cell>
|
||||
initialItems={options.cellsToInsert}
|
||||
onItemsChange={handleInsertColumnsChange}
|
||||
Item={UpdatingCellItem}
|
||||
addLabel="Add a value"
|
||||
/>
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<CellWithValueStack
|
||||
item={item}
|
||||
onItemChange={onItemChange}
|
||||
columns={sheet?.columns ?? []}
|
||||
/>
|
||||
)}
|
||||
</TableList>
|
||||
)
|
||||
case GoogleSheetsAction.UPDATE_ROW:
|
||||
return (
|
||||
@@ -236,9 +225,16 @@ const ActionOptions = ({
|
||||
<TableList<Cell>
|
||||
initialItems={options.cellsToUpsert}
|
||||
onItemsChange={handleUpsertColumnsChange}
|
||||
Item={UpdatingCellItem}
|
||||
addLabel="Add a value"
|
||||
/>
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<CellWithValueStack
|
||||
item={item}
|
||||
onItemChange={onItemChange}
|
||||
columns={sheet?.columns ?? []}
|
||||
/>
|
||||
)}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
@@ -286,10 +282,17 @@ const ActionOptions = ({
|
||||
<TableList<ExtractingCell>
|
||||
initialItems={options.cellsToExtract}
|
||||
onItemsChange={handleExtractingCellsChange}
|
||||
Item={ExtractingCellItem}
|
||||
addLabel="Add a value"
|
||||
hasDefaultItem
|
||||
/>
|
||||
>
|
||||
{({ item, onItemChange }) => (
|
||||
<CellWithVariableIdStack
|
||||
item={item}
|
||||
onItemChange={onItemChange}
|
||||
columns={sheet?.columns ?? []}
|
||||
/>
|
||||
)}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Stack>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DropdownList } from '@/components/DropdownList'
|
||||
import { TableList, TableListItemProps } from '@/components/TableList'
|
||||
import { TableList } from '@/components/TableList'
|
||||
import { Flex } from '@chakra-ui/react'
|
||||
import {
|
||||
GoogleSheetsGetOptions,
|
||||
RowsFilterComparison,
|
||||
} from '@typebot.io/schemas'
|
||||
import React, { useCallback } from 'react'
|
||||
import React from 'react'
|
||||
import { RowsFilterComparisonItem } from './RowsFilterComparisonItem'
|
||||
import { LogicalOperator } from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
|
||||
@@ -30,18 +30,10 @@ export const RowsFilterTableList = ({
|
||||
const updateLogicalOperator = (logicalOperator: LogicalOperator) =>
|
||||
filter && onFilterChange({ ...filter, logicalOperator })
|
||||
|
||||
const createRowsFilterComparisonItem = useCallback(
|
||||
(props: TableListItemProps<RowsFilterComparison>) => (
|
||||
<RowsFilterComparisonItem {...props} columns={columns} />
|
||||
),
|
||||
[columns]
|
||||
)
|
||||
|
||||
return (
|
||||
<TableList<RowsFilterComparison>
|
||||
initialItems={filter?.comparisons ?? []}
|
||||
onItemsChange={updateComparisons}
|
||||
Item={createRowsFilterComparisonItem}
|
||||
ComponentBetweenItems={() => (
|
||||
<Flex justify="center">
|
||||
<DropdownList
|
||||
@@ -52,6 +44,8 @@ export const RowsFilterTableList = ({
|
||||
</Flex>
|
||||
)}
|
||||
addLabel="Add filter rule"
|
||||
/>
|
||||
>
|
||||
{(props) => <RowsFilterComparisonItem {...props} columns={columns} />}
|
||||
</TableList>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,12 +94,13 @@ export const OpenAIChatCompletionSettings = ({
|
||||
<AccordionPanel pt="4">
|
||||
<TableList
|
||||
initialItems={options.messages}
|
||||
Item={ChatCompletionMessageItem}
|
||||
onItemsChange={updateMessages}
|
||||
isOrdered
|
||||
hasDefaultItem
|
||||
addLabel="Add message"
|
||||
/>
|
||||
>
|
||||
{(props) => <ChatCompletionMessageItem {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
@@ -131,11 +132,12 @@ export const OpenAIChatCompletionSettings = ({
|
||||
<AccordionPanel pt="4">
|
||||
<TableList
|
||||
initialItems={options.responseMapping}
|
||||
Item={ChatCompletionResponseItem}
|
||||
onItemsChange={updateResponseMapping}
|
||||
newItemDefaultProps={{ valueToExtract: 'Message content' }}
|
||||
hasDefaultItem
|
||||
/>
|
||||
>
|
||||
{(props) => <ChatCompletionResponseItem {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DropdownList } from '@/components/DropdownList'
|
||||
import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings'
|
||||
import { TableList, TableListItemProps } from '@/components/TableList'
|
||||
import { TableList } from '@/components/TableList'
|
||||
import { TextLink } from '@/components/TextLink'
|
||||
import { TextInput } from '@/components/inputs'
|
||||
import { CodeEditor } from '@/components/inputs/CodeEditor'
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
pixelEventTypes,
|
||||
pixelObjectProperties,
|
||||
} from '@typebot.io/schemas/features/blocks/integrations/pixel/constants'
|
||||
import React, { useMemo } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
const pixelReferenceUrl =
|
||||
'https://developers.facebook.com/docs/meta-pixel/reference#standard-events'
|
||||
@@ -69,14 +69,6 @@ export const PixelSettings = ({ options, onOptionsChange }: Props) => {
|
||||
})
|
||||
}
|
||||
|
||||
const Item = useMemo(
|
||||
() =>
|
||||
function Component(props: TableListItemProps<Item>) {
|
||||
return <ParamItem {...props} eventType={options?.eventType} />
|
||||
},
|
||||
[options?.eventType]
|
||||
)
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<TextInput
|
||||
@@ -123,10 +115,13 @@ export const PixelSettings = ({ options, onOptionsChange }: Props) => {
|
||||
).length > 0) && (
|
||||
<TableList
|
||||
initialItems={options?.params ?? []}
|
||||
Item={Item}
|
||||
onItemsChange={updateParams}
|
||||
addLabel="Add parameter"
|
||||
/>
|
||||
>
|
||||
{(props) => (
|
||||
<ParamItem {...props} eventType={options?.eventType} />
|
||||
)}
|
||||
</TableList>
|
||||
)}
|
||||
</SwitchWithRelatedSettings>
|
||||
</Stack>
|
||||
|
||||
@@ -154,9 +154,10 @@ export const WebhookAdvancedConfigForm = ({
|
||||
<TableList<KeyValue>
|
||||
initialItems={webhook?.queryParams}
|
||||
onItemsChange={updateQueryParams}
|
||||
Item={QueryParamsInputs}
|
||||
addLabel="Add a param"
|
||||
/>
|
||||
>
|
||||
{(props) => <QueryParamsInputs {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
@@ -168,9 +169,10 @@ export const WebhookAdvancedConfigForm = ({
|
||||
<TableList<KeyValue>
|
||||
initialItems={webhook?.headers}
|
||||
onItemsChange={updateHeaders}
|
||||
Item={HeadersInputs}
|
||||
addLabel="Add a value"
|
||||
/>
|
||||
>
|
||||
{(props) => <HeadersInputs {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
@@ -203,9 +205,10 @@ export const WebhookAdvancedConfigForm = ({
|
||||
<TableList<VariableForTest>
|
||||
initialItems={options?.variablesForTest}
|
||||
onItemsChange={updateVariablesForTest}
|
||||
Item={VariableForTestInputs}
|
||||
addLabel="Add an entry"
|
||||
/>
|
||||
>
|
||||
{(props) => <VariableForTestInputs {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
@@ -235,9 +238,10 @@ export const WebhookAdvancedConfigForm = ({
|
||||
<TableList<ResponseVariableMapping>
|
||||
initialItems={options?.responseVariableMapping}
|
||||
onItemsChange={updateResponseVariableMapping}
|
||||
Item={ResponseMappingInputs}
|
||||
addLabel="Add an entry"
|
||||
/>
|
||||
>
|
||||
{(props) => <ResponseMappingInputs {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
@@ -171,10 +171,11 @@ export const ZemanticAiSettings = ({
|
||||
<AccordionPanel pt="4">
|
||||
<TableList
|
||||
initialItems={options.responseMapping ?? []}
|
||||
Item={SearchResponseItem}
|
||||
onItemsChange={updateResponseMapping}
|
||||
newItemDefaultProps={{ valueToExtract: 'Summary' }}
|
||||
/>
|
||||
>
|
||||
{(props) => <SearchResponseItem {...props} />}
|
||||
</TableList>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
@@ -24,7 +24,6 @@ export const ConditionForm = ({ condition, onConditionChange }: Props) => {
|
||||
<TableList<Comparison>
|
||||
initialItems={condition?.comparisons}
|
||||
onItemsChange={handleComparisonsChange}
|
||||
Item={ComparisonItem}
|
||||
ComponentBetweenItems={() => (
|
||||
<Flex justify="center">
|
||||
<DropdownList
|
||||
@@ -38,6 +37,8 @@ export const ConditionForm = ({ condition, onConditionChange }: Props) => {
|
||||
</Flex>
|
||||
)}
|
||||
addLabel="Add a comparison"
|
||||
/>
|
||||
>
|
||||
{(props) => <ComparisonItem {...props} />}
|
||||
</TableList>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user