fix(webhook): 🐛 Sample result w/ multi input blocks
This commit is contained in:
@ -2,9 +2,10 @@
|
||||
/* eslint-disable react/jsx-key */
|
||||
import { Button, chakra, Checkbox, Flex, HStack, Text } from '@chakra-ui/react'
|
||||
import { AlignLeftTextIcon } from 'assets/icons'
|
||||
import { ResultHeaderCell } from 'models'
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { Hooks, useRowSelect, useTable } from 'react-table'
|
||||
import { parseSubmissionsColumns, ResultHeaderCell } from 'services/typebots'
|
||||
import { parseSubmissionsColumns } from 'services/typebots'
|
||||
import { LoadingRows } from './LoadingRows'
|
||||
|
||||
type SubmissionsTableProps = {
|
||||
|
@ -7,14 +7,13 @@ import {
|
||||
deleteAllResults,
|
||||
deleteResults,
|
||||
getAllResults,
|
||||
parseResultHeader,
|
||||
useResults,
|
||||
} from 'services/typebots'
|
||||
import { unparse } from 'papaparse'
|
||||
import { UnlockProPlanInfo } from 'components/shared/Info'
|
||||
import { LogsModal } from './LogsModal'
|
||||
import { useTypebot } from 'contexts/TypebotContext'
|
||||
import { isDefined } from 'utils'
|
||||
import { isDefined, parseResultHeader } from 'utils'
|
||||
|
||||
type Props = {
|
||||
typebotId: string
|
||||
|
@ -0,0 +1,182 @@
|
||||
{
|
||||
"id": "cl10u677f0075a01a6xgl6phe",
|
||||
"createdAt": "2022-03-21T15:01:46.107Z",
|
||||
"updatedAt": "2022-03-21T15:03:07.312Z",
|
||||
"name": "My typebot",
|
||||
"ownerId": "cl10hgjy90000lm1a1gyccuqj",
|
||||
"publishedTypebotId": null,
|
||||
"folderId": null,
|
||||
"blocks": [
|
||||
{
|
||||
"id": "cl10u677d0000a01aa4g4aazg",
|
||||
"steps": [
|
||||
{
|
||||
"id": "cl10u677d0001a01a0xfo3d11",
|
||||
"type": "start",
|
||||
"label": "Start",
|
||||
"blockId": "cl10u677d0000a01aa4g4aazg",
|
||||
"outgoingEdgeId": "cl10u6cw500052e6dq284zju3"
|
||||
}
|
||||
],
|
||||
"title": "Start",
|
||||
"graphCoordinates": { "x": 0, "y": 0 }
|
||||
},
|
||||
{
|
||||
"id": "cl10u68pw00032e6depze2oiy",
|
||||
"graphCoordinates": { "x": 353, "y": 121 },
|
||||
"title": "Block #1",
|
||||
"steps": [
|
||||
{
|
||||
"id": "cl10u68q000042e6dhdipu2wg",
|
||||
"blockId": "cl10u68pw00032e6depze2oiy",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Hi how are you?</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Hi how are you?" }] }
|
||||
],
|
||||
"plainText": "Hi how are you?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl10u6ey300062e6dea9ikpko",
|
||||
"blockId": "cl10u68pw00032e6depze2oiy",
|
||||
"type": "text input",
|
||||
"options": {
|
||||
"isLong": false,
|
||||
"labels": { "button": "Send", "placeholder": "Type your answer..." }
|
||||
},
|
||||
"outgoingEdgeId": "cl10u7ax4000g2e6dkqoq18kp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"graphCoordinates": { "x": 691, "y": 127 },
|
||||
"title": "Block #2",
|
||||
"steps": [
|
||||
{
|
||||
"id": "cl10u6jzt00082e6dgw1piz0q",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>How old are you?</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "How old are you?" }] }
|
||||
],
|
||||
"plainText": "How old are you?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl10u6qa300092e6dh5izz7ig",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "number input",
|
||||
"options": {
|
||||
"labels": { "button": "Send", "placeholder": "Type a number..." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl10u6vbo000a2e6davz2hfw7",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Do you like cookies?</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Do you like cookies?" }] }
|
||||
],
|
||||
"plainText": "Do you like cookies?"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl10u6zk0000b2e6dvabq067r",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "choice input",
|
||||
"options": { "buttonLabel": "Send", "isMultipleChoice": false },
|
||||
"items": [
|
||||
{
|
||||
"id": "cl10u6zk1000c2e6d0d4ivgcl",
|
||||
"stepId": "cl10u6zk0000b2e6dvabq067r",
|
||||
"type": 0,
|
||||
"content": "Yes"
|
||||
},
|
||||
{
|
||||
"stepId": "cl10u6zk0000b2e6dvabq067r",
|
||||
"type": 0,
|
||||
"id": "cl10u70gi000d2e6d924ywjsb",
|
||||
"content": "No"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cl10u759h000f2e6d0rhfwep4",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "text",
|
||||
"content": {
|
||||
"html": "<div>Alright, cheers!</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Alright, cheers!" }] }
|
||||
],
|
||||
"plainText": "Alright, cheers!"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl10u7i6n000h2e6d537h38pg",
|
||||
"blockId": "cl10u6jzd00072e6dvo0zwy0s",
|
||||
"type": "Webhook",
|
||||
"options": {
|
||||
"responseVariableMapping": [],
|
||||
"variablesForTest": [],
|
||||
"isAdvancedConfig": false,
|
||||
"isCustomBody": false
|
||||
},
|
||||
"webhookId": "webhook1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"variables": [],
|
||||
"edges": [
|
||||
{
|
||||
"from": {
|
||||
"blockId": "cl10u677d0000a01aa4g4aazg",
|
||||
"stepId": "cl10u677d0001a01a0xfo3d11"
|
||||
},
|
||||
"to": { "blockId": "cl10u68pw00032e6depze2oiy" },
|
||||
"id": "cl10u6cw500052e6dq284zju3"
|
||||
},
|
||||
{
|
||||
"from": {
|
||||
"blockId": "cl10u68pw00032e6depze2oiy",
|
||||
"stepId": "cl10u6ey300062e6dea9ikpko"
|
||||
},
|
||||
"to": { "blockId": "cl10u6jzd00072e6dvo0zwy0s" },
|
||||
"id": "cl10u7ax4000g2e6dkqoq18kp"
|
||||
}
|
||||
],
|
||||
"theme": {
|
||||
"chat": {
|
||||
"inputs": {
|
||||
"color": "#303235",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"placeholderColor": "#9095A0"
|
||||
},
|
||||
"buttons": { "color": "#FFFFFF", "backgroundColor": "#0042DA" },
|
||||
"hostBubbles": { "color": "#303235", "backgroundColor": "#F7F8FF" },
|
||||
"guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }
|
||||
},
|
||||
"general": { "font": "Open Sans", "background": { "type": "None" } }
|
||||
},
|
||||
"settings": {
|
||||
"general": {
|
||||
"isBrandingEnabled": true,
|
||||
"isInputPrefillEnabled": true,
|
||||
"isNewResultOnRefreshEnabled": false
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form."
|
||||
},
|
||||
"typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 }
|
||||
},
|
||||
"publicId": null,
|
||||
"customDomain": null
|
||||
}
|
@ -8,7 +8,10 @@ test.describe('Webhook step', () => {
|
||||
test('easy configuration should work', async ({ page }) => {
|
||||
const typebotId = cuid()
|
||||
await importTypebotInDatabase(
|
||||
path.join(__dirname, '../../fixtures/typebots/integrations/webhook.json'),
|
||||
path.join(
|
||||
__dirname,
|
||||
'../../fixtures/typebots/integrations/easyConfigWebhook.json'
|
||||
),
|
||||
{
|
||||
id: typebotId,
|
||||
}
|
||||
@ -22,7 +25,7 @@ test.describe('Webhook step', () => {
|
||||
)
|
||||
await page.click('text=Test the request')
|
||||
await expect(page.locator('div[role="textbox"] >> nth=-1')).toContainText(
|
||||
'"statusCode": 200'
|
||||
`"Block #1": "answer value", "Block #2": "20", "Block #2 (1)": "Yes"`
|
||||
)
|
||||
})
|
||||
test('Generated body should work', async ({ page }) => {
|
||||
|
@ -1,15 +1,8 @@
|
||||
import {
|
||||
Block,
|
||||
InputStep,
|
||||
InputStepType,
|
||||
ResultWithAnswers,
|
||||
Variable,
|
||||
VariableWithValue,
|
||||
} from 'models'
|
||||
import { ResultWithAnswers, VariableWithValue, ResultHeaderCell } from 'models'
|
||||
import useSWRInfinite from 'swr/infinite'
|
||||
import { stringify } from 'qs'
|
||||
import { Answer } from 'db'
|
||||
import { byId, isDefined, isInputStep, sendRequest } from 'utils'
|
||||
import { isDefined, sendRequest } from 'utils'
|
||||
import { fetcher } from 'services/utils'
|
||||
import { HStack, Text } from '@chakra-ui/react'
|
||||
import { CodeIcon, CalendarIcon } from 'assets/icons'
|
||||
@ -110,14 +103,6 @@ type HeaderCell = {
|
||||
accessor: string
|
||||
}
|
||||
|
||||
export type ResultHeaderCell = {
|
||||
label: string
|
||||
stepId?: string
|
||||
stepType?: InputStepType
|
||||
isLong?: boolean
|
||||
variableId?: string
|
||||
}
|
||||
|
||||
export const parseSubmissionsColumns = (
|
||||
resultHeader: ResultHeaderCell[]
|
||||
): HeaderCell[] =>
|
||||
@ -140,83 +125,6 @@ const HeaderIcon = ({ header }: { header: ResultHeaderCell }) =>
|
||||
<CalendarIcon />
|
||||
)
|
||||
|
||||
export const parseResultHeader = ({
|
||||
blocks,
|
||||
variables,
|
||||
}: {
|
||||
blocks: Block[]
|
||||
variables: Variable[]
|
||||
}): ResultHeaderCell[] => {
|
||||
const parsedBlocks = parseInputsResultHeader({ blocks, variables })
|
||||
return [
|
||||
{ label: 'Submitted at' },
|
||||
...parsedBlocks,
|
||||
...parseVariablesHeaders(variables, parsedBlocks),
|
||||
]
|
||||
}
|
||||
|
||||
const parseInputsResultHeader = ({
|
||||
blocks,
|
||||
variables,
|
||||
}: {
|
||||
blocks: Block[]
|
||||
variables: Variable[]
|
||||
}): ResultHeaderCell[] =>
|
||||
(
|
||||
blocks
|
||||
.flatMap((b) =>
|
||||
b.steps.map((s) => ({
|
||||
...s,
|
||||
blockTitle: b.title,
|
||||
}))
|
||||
)
|
||||
.filter((step) => isInputStep(step)) as (InputStep & {
|
||||
blockTitle: string
|
||||
})[]
|
||||
).reduce<ResultHeaderCell[]>((headers, inputStep) => {
|
||||
if (
|
||||
headers.find(
|
||||
(h) =>
|
||||
isDefined(h.variableId) &&
|
||||
h.variableId ===
|
||||
variables.find(byId(inputStep.options.variableId))?.id
|
||||
)
|
||||
)
|
||||
return headers
|
||||
const matchedVariableName =
|
||||
inputStep.options.variableId &&
|
||||
variables.find(byId(inputStep.options.variableId))?.name
|
||||
|
||||
let label = matchedVariableName ?? inputStep.blockTitle
|
||||
const totalPrevious = headers.filter((h) => h.label.includes(label)).length
|
||||
if (totalPrevious > 0) label = label + ` (${totalPrevious})`
|
||||
return [
|
||||
...headers,
|
||||
{
|
||||
stepType: inputStep.type,
|
||||
stepId: inputStep.id,
|
||||
variableId: inputStep.options.variableId,
|
||||
label,
|
||||
isLong: 'isLong' in inputStep.options && inputStep.options.isLong,
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
|
||||
const parseVariablesHeaders = (
|
||||
variables: Variable[],
|
||||
stepResultHeader: ResultHeaderCell[]
|
||||
) =>
|
||||
variables.reduce<ResultHeaderCell[]>((headers, v) => {
|
||||
if (stepResultHeader.find((h) => h.variableId === v.id)) return headers
|
||||
return [
|
||||
...headers,
|
||||
{
|
||||
label: v.name,
|
||||
variableId: v.id,
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
|
||||
export const convertResultsToTableData = (
|
||||
results: ResultWithAnswers[] | undefined,
|
||||
header: ResultHeaderCell[]
|
||||
|
Reference in New Issue
Block a user