Skip to content

Commit

Permalink
✨ (api) Add CRUD typebot endpoints
Browse files Browse the repository at this point in the history
Closes #320, closes #696
  • Loading branch information
baptisteArno committed Aug 17, 2023
1 parent 019f72a commit 454d320
Show file tree
Hide file tree
Showing 78 changed files with 25,262 additions and 1,321 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { TextInput } from '@/components/inputs'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { FormLabel, Stack } from '@chakra-ui/react'
import { EmailInputOptions, Variable } from '@typebot.io/schemas'
import {
EmailInputOptions,
Variable,
invalidEmailDefaultRetryMessage,
} from '@typebot.io/schemas'
import React from 'react'

type Props = {
Expand Down Expand Up @@ -33,7 +37,9 @@ export const EmailInputSettings = ({ options, onOptionsChange }: Props) => {
/>
<TextInput
label="Retry message:"
defaultValue={options.retryMessageContent}
defaultValue={
options.retryMessageContent ?? invalidEmailDefaultRetryMessage
}
onChange={handleRetryMessageChange}
/>
<Stack>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { defaultEmailInputOptions, InputBlockType } from '@typebot.io/schemas'
import {
defaultEmailInputOptions,
InputBlockType,
invalidEmailDefaultRetryMessage,
} from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'

test.describe('Email input block', () => {
Expand Down Expand Up @@ -35,7 +39,7 @@ test.describe('Email input block', () => {
await expect(page.locator('text=Your email...')).toBeVisible()
await page.getByLabel('Button label:').fill('Go')
await page.fill(
`input[value="${defaultEmailInputOptions.retryMessageContent}"]`,
`input[value="${invalidEmailDefaultRetryMessage}"]`,
'Try again bro'
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { MakeComBlock } from '@typebot.io/schemas'
import { byId, isNotDefined } from '@typebot.io/lib'
import { isNotDefined } from '@typebot.io/lib'

type Props = {
block: MakeComBlock
}

export const MakeComContent = ({ block }: Props) => {
const { webhooks } = useTypebot()
const webhook = block.options.webhook ?? webhooks.find(byId(block.webhookId))
const webhook = block.options.webhook

if (isNotDefined(webhook?.body))
return <Text color="gray.500">Configure...</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Alert, AlertIcon, Button, Link, Stack, Text } from '@chakra-ui/react'
import { ExternalLinkIcon } from '@/components/icons'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { MakeComBlock, Webhook, WebhookOptions } from '@typebot.io/schemas'
import React, { useCallback, useEffect, useState } from 'react'
import { byId } from '@typebot.io/lib'
import React from 'react'
import { WebhookAdvancedConfigForm } from '../../webhook/components/WebhookAdvancedConfigForm'

type Props = {
Expand All @@ -12,45 +10,18 @@ type Props = {
}

export const MakeComSettings = ({
block: { webhookId, id: blockId, options },
block: { id: blockId, options },
onOptionsChange,
}: Props) => {
const { webhooks, updateWebhook } = useTypebot()
const webhook = webhooks.find(byId(webhookId))

const [localWebhook, _setLocalWebhook] = useState(webhook)

const setLocalWebhook = useCallback(
async (newLocalWebhook: Webhook) => {
if (options.webhook) {
onOptionsChange({
...options,
webhook: newLocalWebhook,
})
return
}
_setLocalWebhook(newLocalWebhook)
await updateWebhook(newLocalWebhook.id, newLocalWebhook)
},
[onOptionsChange, options, updateWebhook]
)

useEffect(() => {
if (
!localWebhook ||
localWebhook.url ||
!webhook?.url ||
webhook.url === localWebhook.url ||
options.webhook
)
return
setLocalWebhook({
...localWebhook,
url: webhook?.url,
const setLocalWebhook = async (newLocalWebhook: Webhook) => {
if (!options.webhook) return
onOptionsChange({
...options,
webhook: newLocalWebhook,
})
}, [webhook, localWebhook, setLocalWebhook, options.webhook])
}

const url = options.webhook?.url ?? localWebhook?.url
const url = options.webhook?.url

return (
<Stack spacing={4}>
Expand All @@ -72,10 +43,10 @@ export const MakeComSettings = ({
</Stack>
)}
</Alert>
{(localWebhook || options.webhook) && (
{options.webhook && (
<WebhookAdvancedConfigForm
blockId={blockId}
webhook={(options.webhook ?? localWebhook) as Webhook}
webhook={options.webhook as Webhook}
options={options}
onWebhookChange={setLocalWebhook}
onOptionsChange={onOptionsChange}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { PabblyConnectBlock } from '@typebot.io/schemas'
import { byId, isNotDefined } from '@typebot.io/lib'
import { isNotDefined } from '@typebot.io/lib'

type Props = {
block: PabblyConnectBlock
}

export const PabblyConnectContent = ({ block }: Props) => {
const { webhooks } = useTypebot()
const webhook = block.options.webhook ?? webhooks.find(byId(block.webhookId))
const webhook = block.options.webhook

if (isNotDefined(webhook?.body))
return <Text color="gray.500">Configure...</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Alert, AlertIcon, Button, Link, Stack, Text } from '@chakra-ui/react'
import { ExternalLinkIcon } from '@/components/icons'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import {
PabblyConnectBlock,
Webhook,
WebhookOptions,
} from '@typebot.io/schemas'
import React, { useState } from 'react'
import { byId } from '@typebot.io/lib'
import React from 'react'
import { WebhookAdvancedConfigForm } from '../../webhook/components/WebhookAdvancedConfigForm'
import { TextInput } from '@/components/inputs'

Expand All @@ -17,35 +15,23 @@ type Props = {
}

export const PabblyConnectSettings = ({
block: { webhookId, id: blockId, options },
block: { id: blockId, options },
onOptionsChange,
}: Props) => {
const { webhooks, updateWebhook } = useTypebot()

const [localWebhook, _setLocalWebhook] = useState(
webhooks.find(byId(webhookId))
)

const setLocalWebhook = async (newLocalWebhook: Webhook) => {
if (options.webhook) {
onOptionsChange({
...options,
webhook: newLocalWebhook,
})
return
}
_setLocalWebhook(newLocalWebhook)
await updateWebhook(newLocalWebhook.id, newLocalWebhook)
if (!options.webhook) return
onOptionsChange({
...options,
webhook: newLocalWebhook,
})
}

const handleUrlChange = (url: string) =>
localWebhook &&
setLocalWebhook({
...localWebhook,
url,
})
const updateUrl = (url: string) => {
if (!options.webhook) return
onOptionsChange({ ...options, webhook: { ...options.webhook, url } })
}

const url = options.webhook?.url ?? localWebhook?.url
const url = options.webhook?.url

return (
<Stack spacing={4}>
Expand All @@ -70,14 +56,14 @@ export const PabblyConnectSettings = ({
<TextInput
placeholder="Paste webhook URL..."
defaultValue={url ?? ''}
onChange={handleUrlChange}
onChange={updateUrl}
withVariableButton={false}
debounceTimeout={0}
/>
{(localWebhook || options.webhook) && (
{options.webhook && (
<WebhookAdvancedConfigForm
blockId={blockId}
webhook={(options.webhook ?? localWebhook) as Webhook}
webhook={options.webhook as Webhook}
options={options}
onWebhookChange={setLocalWebhook}
onOptionsChange={onOptionsChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const WebhookAdvancedConfigForm = ({
onWebhookChange,
onOptionsChange,
}: Props) => {
const { typebot, save, updateWebhook } = useTypebot()
const { typebot, save } = useTypebot()
const [isTestResponseLoading, setIsTestResponseLoading] = useState(false)
const [testResponse, setTestResponse] = useState<string>()
const [responseKeys, setResponseKeys] = useState<string[]>([])
Expand Down Expand Up @@ -80,8 +80,7 @@ export const WebhookAdvancedConfigForm = ({
const executeTestRequest = async () => {
if (!typebot) return
setIsTestResponseLoading(true)
if (!options.webhook)
await Promise.all([updateWebhook(webhook.id, webhook), save()])
if (!options.webhook) await save()
else await save()
const { data, error } = await executeWebhook(
typebot.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Stack, Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { WebhookBlock } from '@typebot.io/schemas'
import { byId } from '@typebot.io/lib'
import { SetVariableLabel } from '@/components/SetVariableLabel'

type Props = {
block: WebhookBlock
}

export const WebhookContent = ({ block: { options, webhookId } }: Props) => {
export const WebhookContent = ({ block: { options } }: Props) => {
const { typebot } = useTypebot()
const { webhooks } = useTypebot()
const webhook = options.webhook ?? webhooks.find(byId(webhookId))
const webhook = options.webhook

if (!webhook?.url) return <Text color="gray.500">Configure...</Text>
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React, { useState } from 'react'
import React from 'react'
import { Spinner, Stack } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { WebhookOptions, Webhook, WebhookBlock } from '@typebot.io/schemas'
import { byId } from '@typebot.io/lib'
import { TextInput } from '@/components/inputs'
import { WebhookAdvancedConfigForm } from './WebhookAdvancedConfigForm'

Expand All @@ -12,42 +10,32 @@ type Props = {
}

export const WebhookSettings = ({
block: { webhookId, id: blockId, options },
block: { id: blockId, options },
onOptionsChange,
}: Props) => {
const { webhooks, updateWebhook } = useTypebot()
const [localWebhook, _setLocalWebhook] = useState(
webhooks.find(byId(webhookId))
)

const setLocalWebhook = async (newLocalWebhook: Webhook) => {
if (options.webhook) {
onOptionsChange({ ...options, webhook: newLocalWebhook })
return
}
_setLocalWebhook(newLocalWebhook)
await updateWebhook(newLocalWebhook.id, newLocalWebhook)
if (!options.webhook) return
onOptionsChange({ ...options, webhook: newLocalWebhook })
return
}

const updateUrl = (url: string) => {
if (options.webhook)
onOptionsChange({ ...options, webhook: { ...options.webhook, url } })
else if (localWebhook)
setLocalWebhook({ ...localWebhook, url: url ?? undefined })
if (!options.webhook) return
onOptionsChange({ ...options, webhook: { ...options.webhook, url } })
}

if (!localWebhook && !options.webhook) return <Spinner />
if (!options.webhook) return <Spinner />

return (
<Stack spacing={4}>
<TextInput
placeholder="Paste webhook URL..."
defaultValue={options.webhook?.url ?? localWebhook?.url ?? ''}
defaultValue={options.webhook?.url ?? ''}
onChange={updateUrl}
/>
<WebhookAdvancedConfigForm
blockId={blockId}
webhook={(options.webhook ?? localWebhook) as Webhook}
webhook={options.webhook as Webhook}
options={options}
onWebhookChange={setLocalWebhook}
onOptionsChange={onOptionsChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ test.describe('API', () => {
expect(data.resultExample).toMatchObject({
message: 'This is a sample result, it has been generated ⬇️',
Welcome: 'Hi!',
Email: 'test@email.com',
Email: 'user@email.com',
Name: 'answer value',
Services: 'Website dev, Content Marketing, Social Media, UI / UX Design',
'Additional information': 'answer value',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { ZapierBlock } from '@typebot.io/schemas'
import { byId, isNotDefined } from '@typebot.io/lib'
import { isNotDefined } from '@typebot.io/lib'

type Props = {
block: ZapierBlock
}

export const ZapierContent = ({ block }: Props) => {
const { webhooks } = useTypebot()
const webhook = block.options.webhook ?? webhooks.find(byId(block.webhookId))
const webhook = block.options.webhook

if (isNotDefined(webhook?.body))
return <Text color="gray.500">Configure...</Text>
Expand Down
Loading

4 comments on commit 454d320

@vercel
Copy link

@vercel vercel bot commented on 454d320 Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 454d320 Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs-git-main-typebot-io.vercel.app
docs-typebot-io.vercel.app
docs.typebot.io

@vercel
Copy link

@vercel vercel bot commented on 454d320 Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
builder-v2-typebot-io.vercel.app
app.typebot.io

@vercel
Copy link

@vercel vercel bot commented on 454d320 Aug 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

gsbulletin.com
journey.cr8.ai
panther.cr7.ai
panther.cr8.ai
pay.sifuim.com
penguin.cr8.ai
segredomeu.com
talk.gocare.io
test.bot.gives
ticketfute.com
unicorn.cr8.ai
whats-app.chat
apo.nigerias.io
app.blogely.com
apr.nigerias.io
aso.nigerias.io
blackcan.cr8.ai
blackvip.online
bot.4display.nl
bot.artiweb.app
bot.devitus.com
bot.reeplai.com
bot.scayver.com
bot.tc-mail.com
carspecs.lam.ee
chat.lalmon.com
chat.sureb4.com
conversawpp.com
eventhub.com.au
feiraododia.com
fitness.riku.ai
games.klujo.com
localove.online
proscale.com.br
sellmycarbr.com
svhmapp.mprs.in
typebot.aloe.do
app-liberado.pro
ask.pemantau.org
batepapo.digital
bot.contakit.com
bot.imovfast.com
bot.piccinato.co
botc.ceox.com.br
chat.sifucrm.com
chat.syncwin.com
chatonlineja.com
clo.closeer.work
cockroach.cr8.ai
desafioem21d.com
faqs.nigerias.io
feiraodehoje.com
metodoelev.com.br
nutriandreia.shop
ov1.wpwakanda.com
ov2.wpwakanda.com
ov3.wpwakanda.com
pcb.drapamela.com
redeemchatgpt.com
softwarelucra.com
support.triplo.ai
viewer.typebot.io
welcome.triplo.ai
www.thegymgame.it
zeropendencia.com
1988.bouclidom.com
a.onewebcenter.com
amancarseat.online
amostra-safe.click
andreimayer.com.br
bebesemcolicas.com
bot.innovacion.fun
bot.lucide.contact
bot.neferlopez.com
bot.photonative.de
bot.samplehunt.com
bot.sinalcerto.com
bot.wphelpchat.com
bots.robomotion.io
cadu.uninta.edu.br
chat.hand-made.one
chat.tuanpakya.com
chat.webisharp.com
chatbotforthat.com
descobrindotudo.me
dicanatural.online
digitalhelp.com.au
draraquelnutri.com
drcarlosyoshi.site
goalsettingbot.com
leads.gecoelho.com
noticiasnet.online
novoappespiao.site
omarcodosanjos.com
pant.maxbot.com.br
pantherview.cr8.ai
positivobra.com.br
rollingball.cr8.ai
speciallife.com.br
sub.yolozeeeer.com

Please sign in to comment.