♻️ Introduce typebot v6 with events (#1013)

Closes #885
This commit is contained in:
Baptiste Arnaud
2023-11-08 15:34:16 +01:00
committed by GitHub
parent 68e4fc71fb
commit 35300eaf34
634 changed files with 58971 additions and 31449 deletions

View File

@@ -1,10 +1,10 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { BubbleBlockType, defaultAudioBubbleContent } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { getTestAsset } from '@/test/utils/playwright'
import { proWorkspaceId } from '@typebot.io/lib/playwright/databaseSetup'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
const audioSampleUrl =
'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3'
@@ -16,7 +16,6 @@ test('should work as expected', async ({ page }) => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.AUDIO,
content: defaultAudioBubbleContent,
}),
},
])

View File

@@ -1,16 +1,17 @@
import { Button, Flex, HStack, Stack, Text } from '@chakra-ui/react'
import { AudioBubbleContent } from '@typebot.io/schemas'
import { TextInput } from '@/components/inputs'
import { useState } from 'react'
import { UploadButton } from '@/components/ImageUploadContent/UploadButton'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
import { useTranslate } from '@tolgee/react'
import { FilePathUploadProps } from '@/features/upload/api/generateUploadUrl'
import { AudioBubbleBlock } from '@typebot.io/schemas'
import { defaultAudioBubbleContent } from '@typebot.io/schemas/features/blocks/bubbles/audio/constants'
type Props = {
uploadFileProps: FilePathUploadProps
content: AudioBubbleContent
onContentChange: (content: AudioBubbleContent) => void
content: AudioBubbleBlock['content']
onContentChange: (content: AudioBubbleBlock['content']) => void
}
export const AudioBubbleForm = ({
@@ -64,7 +65,7 @@ export const AudioBubbleForm = ({
placeholder={t(
'editor.blocks.bubbles.audio.settings.worksWith.placeholder'
)}
defaultValue={content.url ?? ''}
defaultValue={content?.url ?? ''}
onChange={updateUrl}
/>
<Text fontSize="sm" color="gray.400" textAlign="center">
@@ -75,7 +76,10 @@ export const AudioBubbleForm = ({
</Stack>
<SwitchWithLabel
label={t('editor.blocks.bubbles.audio.settings.autoplay.label')}
initialValue={content.isAutoplayEnabled ?? true}
initialValue={
content?.isAutoplayEnabled ??
defaultAudioBubbleContent.isAutoplayEnabled
}
onCheckChange={updateAutoPlay}
/>
</Stack>

View File

@@ -1,10 +1,10 @@
import { Text } from '@chakra-ui/react'
import { AudioBubbleContent } from '@typebot.io/schemas'
import { isDefined } from '@typebot.io/lib'
import { useTranslate } from '@tolgee/react'
import { AudioBubbleBlock } from '@typebot.io/schemas'
type Props = {
url: AudioBubbleContent['url']
url: NonNullable<AudioBubbleBlock['content']>['url']
}
export const AudioBubbleNode = ({ url }: Props) => {

View File

@@ -1,12 +1,13 @@
import { TextInput, NumberInput } from '@/components/inputs'
import { Stack, Text } from '@chakra-ui/react'
import { EmbedBubbleContent } from '@typebot.io/schemas'
import { EmbedBubbleBlock } from '@typebot.io/schemas'
import { sanitizeUrl } from '@typebot.io/lib'
import { useTranslate } from '@tolgee/react'
import { defaultEmbedBubbleContent } from '@typebot.io/schemas/features/blocks/bubbles/embed/constants'
type Props = {
content: EmbedBubbleContent
onSubmit: (content: EmbedBubbleContent) => void
content: EmbedBubbleBlock['content']
onSubmit: (content: EmbedBubbleBlock['content']) => void
}
export const EmbedUploadContent = ({ content, onSubmit }: Props) => {
@@ -18,8 +19,9 @@ export const EmbedUploadContent = ({ content, onSubmit }: Props) => {
onSubmit({ ...content, url: iframeUrl })
}
const handleHeightChange = (height?: EmbedBubbleContent['height']) =>
height && onSubmit({ ...content, height })
const handleHeightChange = (
height?: NonNullable<EmbedBubbleBlock['content']>['height']
) => height && onSubmit({ ...content, height })
return (
<Stack p="2" spacing={6}>
@@ -38,7 +40,7 @@ export const EmbedUploadContent = ({ content, onSubmit }: Props) => {
<NumberInput
label="Height:"
defaultValue={content?.height}
defaultValue={content?.height ?? defaultEmbedBubbleContent.height}
onValueChange={handleHeightChange}
suffix={t('editor.blocks.bubbles.embed.settings.numberInput.unit')}
width="150px"

View File

@@ -1,8 +1,8 @@
import test, { expect } from '@playwright/test'
import { BubbleBlockType, defaultEmbedBubbleContent } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
const pdfSrc = 'https://www.orimi.com/pdf-test.pdf'
const siteSrc = 'https://app.cal.com/baptistearno/15min'
@@ -16,7 +16,6 @@ test.describe.parallel('Embed bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.EMBED,
content: defaultEmbedBubbleContent,
}),
},
])

View File

@@ -7,6 +7,7 @@ import { Stack } from '@chakra-ui/react'
import { isDefined, isNotEmpty } from '@typebot.io/lib'
import { ImageBubbleBlock } from '@typebot.io/schemas'
import React, { useState } from 'react'
import { defaultImageBubbleContent } from '@typebot.io/schemas/features/blocks/bubbles/image/constants'
type Props = {
uploadFileProps: FilePathUploadProps
@@ -21,7 +22,7 @@ export const ImageBubbleSettings = ({
}: Props) => {
const { t } = useTranslate()
const [showClickLinkInput, setShowClickLinkInput] = useState(
isNotEmpty(block.content.clickLink?.url)
isNotEmpty(block.content?.clickLink?.url)
)
const updateImage = (url: string) => {
@@ -31,19 +32,19 @@ export const ImageBubbleSettings = ({
const updateClickLinkUrl = (url: string) => {
onContentChange({
...block.content,
clickLink: { ...block.content.clickLink, url },
clickLink: { ...block.content?.clickLink, url },
})
}
const updateClickLinkAltText = (alt: string) => {
onContentChange({
...block.content,
clickLink: { ...block.content.clickLink, alt },
clickLink: { ...block.content?.clickLink, alt },
})
}
const toggleClickLink = () => {
if (isDefined(block.content.clickLink) && showClickLinkInput) {
if (isDefined(block.content?.clickLink) && showClickLinkInput) {
onContentChange({ ...block.content, clickLink: undefined })
}
setShowClickLinkInput(!showClickLinkInput)
@@ -55,6 +56,7 @@ export const ImageBubbleSettings = ({
uploadFileProps={uploadFileProps}
defaultUrl={block.content?.url}
onSubmit={updateImage}
excludedTabs={['emoji']}
/>
<Stack>
<SwitchWithLabel
@@ -68,14 +70,17 @@ export const ImageBubbleSettings = ({
autoFocus
placeholder="https://example.com"
onChange={updateClickLinkUrl}
defaultValue={block.content.clickLink?.url}
defaultValue={block.content?.clickLink?.url}
/>
<TextInput
placeholder={t(
'editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder'
)}
onChange={updateClickLinkAltText}
defaultValue={block.content.clickLink?.alt}
defaultValue={
block.content?.clickLink?.alt ??
defaultImageBubbleContent.clickLink.alt
}
/>
</>
)}

View File

@@ -1,10 +1,10 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { BubbleBlockType, defaultImageBubbleContent } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { getTestAsset } from '@/test/utils/playwright'
import { proWorkspaceId } from '@typebot.io/lib/playwright/databaseSetup'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
const unsplashImageSrc =
'https://images.unsplash.com/photo-1504297050568-910d24c426d3?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
@@ -18,7 +18,6 @@ test.describe.parallel('Image bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.IMAGE,
content: defaultImageBubbleContent,
}),
},
])
@@ -44,7 +43,6 @@ test.describe.parallel('Image bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.IMAGE,
content: defaultImageBubbleContent,
}),
},
])
@@ -66,7 +64,6 @@ test.describe.parallel('Image bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.IMAGE,
content: defaultImageBubbleContent,
}),
},
])

View File

@@ -8,7 +8,7 @@ type Props = {
}
export const TextBubbleContent = ({ block }: Props) => {
const isEmpty = block.content.richText.length === 0
const isEmpty = (block.content?.richText?.length ?? 0) === 0
return (
<Flex
w="90%"
@@ -17,7 +17,7 @@ export const TextBubbleContent = ({ block }: Props) => {
className="slate-html-container"
color={isEmpty ? 'gray.500' : 'inherit'}
>
{block.content.richText.map((element, idx) => (
{block.content?.richText?.map((element, idx) => (
<PlateBlock key={idx} element={element} />
))}
</Flex>

View File

@@ -26,22 +26,32 @@ export const PlateText = ({
const PlateTextContent = ({ text }: { text: string }) => {
const { typebot } = useTypebot()
return (
<>
{text.split(/\{\{(.*?\}\})/g).map((str, idx) => {
if (str.endsWith('}}')) {
const variableName = str.trim().slice(0, -2)
const matchingVariable = typebot?.variables.find(
(variable) => variable.name === variableName
)
if (!matchingVariable) return '{{' + str
{text.split(/\{\{=(.*?=\}\})/g).map((str, idx) => {
if (str.endsWith('=}}')) {
return (
<span className="slate-variable" key={idx}>
{str.trim().slice(0, -2)}
<span className="slate-inline-code" key={idx}>
{str.trim().slice(0, -3)}
</span>
)
}
return str
return str.split(/\{\{(.*?\}\})/g).map((str, idx) => {
if (str.endsWith('}}')) {
const variableName = str.trim().slice(0, -2)
const matchingVariable = typebot?.variables.find(
(variable) => variable.name === variableName
)
if (!matchingVariable) return '{{' + str
return (
<span className="slate-variable" key={idx}>
{str.trim().slice(0, -2)}
</span>
)
}
return str
})
})}
</>
)

View File

@@ -1,8 +1,8 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import { BubbleBlockType, defaultTextBubbleContent } from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
test.describe('Text bubble block', () => {
test('rich text features should work', async ({ page }) => {
@@ -12,7 +12,6 @@ test.describe('Text bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.TEXT,
content: defaultTextBubbleContent,
}),
},
])

View File

@@ -1,6 +1,7 @@
import { useTranslate } from '@tolgee/react'
import { Box, Text, Image } from '@chakra-ui/react'
import { VideoBubbleBlock, VideoBubbleContentType } from '@typebot.io/schemas'
import { VideoBubbleBlock } from '@typebot.io/schemas'
import { VideoBubbleContentType } from '@typebot.io/schemas/features/blocks/bubbles/video/constants'
type Props = {
block: VideoBubbleBlock

View File

@@ -1,16 +1,16 @@
import { Stack, Text } from '@chakra-ui/react'
import {
VariableString,
VideoBubbleContent,
VideoBubbleContentType,
} from '@typebot.io/schemas'
import { VariableString, VideoBubbleBlock } from '@typebot.io/schemas'
import { NumberInput, TextInput } from '@/components/inputs'
import { useTranslate } from '@tolgee/react'
import { parseVideoUrl } from '@typebot.io/lib/parseVideoUrl'
import {
VideoBubbleContentType,
defaultVideoBubbleContent,
} from '@typebot.io/schemas/features/blocks/bubbles/video/constants'
type Props = {
content?: VideoBubbleContent
onSubmit: (content: VideoBubbleContent) => void
content?: VideoBubbleBlock['content']
onSubmit: (content: VideoBubbleBlock['content']) => void
}
export const VideoUploadContent = ({ content, onSubmit }: Props) => {
@@ -47,7 +47,7 @@ export const VideoUploadContent = ({ content, onSubmit }: Props) => {
{content?.type !== VideoBubbleContentType.URL && (
<NumberInput
label="Height:"
defaultValue={content?.height ?? 400}
defaultValue={content?.height ?? defaultVideoBubbleContent.height}
onValueChange={updateHeight}
suffix={t('editor.blocks.bubbles.video.settings.numberInput.unit')}
width="150px"

View File

@@ -1,12 +1,9 @@
import test, { expect } from '@playwright/test'
import { createTypebots } from '@typebot.io/lib/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from '@typebot.io/lib/playwright/databaseHelpers'
import {
BubbleBlockType,
defaultVideoBubbleContent,
VideoBubbleContentType,
} from '@typebot.io/schemas'
import { createId } from '@paralleldrive/cuid2'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
import { VideoBubbleContentType } from '@typebot.io/schemas/features/blocks/bubbles/video/constants'
const videoSrc =
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4'
@@ -22,7 +19,6 @@ test.describe.parallel('Video bubble block', () => {
id: typebotId,
...parseDefaultGroupWithBlock({
type: BubbleBlockType.VIDEO,
content: defaultVideoBubbleContent,
}),
},
])