From 6db0464fd7580443a3b705d45b8958e1461c606c Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Wed, 26 Jun 2024 10:13:38 +0200 Subject: [PATCH] :sparkles: Add attachments option to text input (#1608) Closes #854 --- apps/builder/package.json | 2 +- .../components/EditableEmojiOrImageIcon.tsx | 7 +- .../features/blocks/inputs/date/date.spec.ts | 2 +- .../inputs/fileUpload/fileUpload.spec.ts | 10 +- .../components/TextInputNodeContent.tsx | 41 +- .../components/TextInputSettings.tsx | 70 +- .../blocks/inputs/textInput/textInput.spec.ts | 45 + .../googleSheets/googleSheets.spec.ts | 12 +- .../blocks/logic/condition/condition.spec.ts | 6 +- .../logic/setVariable/setVariable.spec.ts | 19 +- .../logic/typebotLink/typebotLink.spec.ts | 4 +- .../dashboard/components/DashboardHeader.tsx | 15 +- .../editor/providers/typebotActions/groups.ts | 5 - .../embeds/snippetParsers/shared.ts | 2 +- .../features/whatsapp/startWhatsAppPreview.ts | 1 - .../components/WorkspaceSettingsModal.tsx | 4 +- .../src/pages/api/auth/[...nextauth].ts | 30 +- .../whatsapp/media/preview/[mediaId].ts | 62 ++ .../deploy/web/libraries/html-javascript.mdx | 8 +- apps/docs/deploy/web/webflow.mdx | 2 +- apps/docs/openapi/builder.json | 40 + apps/docs/self-hosting/configuration.mdx | 25 +- .../src/features/chat/api/continueChat.ts | 7 +- .../features/chat/api/legacy/sendMessageV1.ts | 22 +- .../features/chat/api/legacy/sendMessageV2.ts | 22 +- .../fileUpload/api/generateUploadUrl.ts | 109 ++- apps/viewer/src/test/chat.spec.ts | 14 +- apps/viewer/src/test/transcript.spec.ts | 6 +- apps/viewer/src/test/typebotLink.spec.ts | 8 +- .../bot-engine/apiHandlers/continueChat.ts | 3 +- packages/bot-engine/apiHandlers/startChat.ts | 6 +- .../apiHandlers/startChatPreview.ts | 6 +- .../logic/setVariable/executeSetVariable.ts | 12 +- packages/bot-engine/continueBotFlow.ts | 198 +++-- packages/bot-engine/queries/saveAnswer.ts | 1 - packages/bot-engine/resetSessionState.ts | 20 + packages/bot-engine/startSession.ts | 6 +- packages/bot-engine/types.ts | 10 +- .../bot-engine/whatsapp/resumeWhatsAppFlow.ts | 237 +++++- .../whatsapp/sendChatReplyToWhatsApp.ts | 30 +- .../whatsapp/startWhatsAppSession.ts | 4 +- packages/embeds/js/README.md | 8 +- packages/embeds/js/package.json | 3 +- packages/embeds/js/rollup.config.js | 12 + packages/embeds/js/src/assets/index.css | 144 ++++ packages/embeds/js/src/components/Bot.tsx | 14 + .../ConversationContainer.tsx | 8 - .../js/src/components/InputChatBlock.tsx | 33 +- packages/embeds/js/src/components/Modal.tsx | 27 + .../embeds/js/src/components/SendButton.tsx | 34 +- .../src/components/TextInputAddFileButton.tsx | 103 +++ .../js/src/components/bubbles/GuestBubble.tsx | 118 ++- .../js/src/components/icons/CameraIcon.tsx | 17 + .../js/src/components/icons/FileIcon.tsx | 17 + .../js/src/components/icons/PaperClipIcon.tsx | 18 + .../js/src/components/icons/PictureIcon.tsx | 19 + .../js/src/components/icons/PlusIcon.tsx | 17 + .../inputs/date/components/DateForm.tsx | 135 +-- .../inputs/email/components/EmailInput.tsx | 32 +- .../fileUpload/components/FilePreview.tsx | 80 ++ .../fileUpload/components/FileUploadForm.tsx | 154 ++-- .../fileUpload/components/SelectedFile.tsx | 91 ++ .../helpers/sanitizeSelectedFiles.ts | 40 + .../inputs/fileUpload/helpers/uploadFiles.ts | 14 +- .../inputs/number/components/NumberInput.tsx | 50 +- .../inputs/phone/components/PhoneInput.tsx | 11 +- .../inputs/textInput/components/TextInput.tsx | 206 ++++- .../blocks/inputs/url/components/UrlInput.tsx | 32 +- .../src/features/bubble/components/Bubble.tsx | 107 +-- .../src/features/popup/components/Popup.tsx | 69 +- .../features/standard/components/Standard.tsx | 7 +- packages/embeds/js/src/types.ts | 9 + packages/embeds/js/src/utils/toaster.ts | 6 + packages/embeds/nextjs/package.json | 2 +- packages/embeds/react/package.json | 2 +- packages/env/env.ts | 9 +- packages/lib/package.json | 1 + packages/lib/redis.ts | 16 + packages/logic/computeResultTranscript.ts | 41 +- packages/prisma/mysql/schema.prisma | 13 +- .../migration.sql | 2 + packages/prisma/postgresql/schema.prisma | 13 +- packages/schemas/features/answer.ts | 1 + .../features/blocks/inputs/text/constants.ts | 4 + .../features/blocks/inputs/text/schema.ts | 8 + packages/schemas/features/chat/schema.ts | 22 +- packages/schemas/features/whatsapp.ts | 6 +- pnpm-lock.yaml | 784 +++++++++++++++++- 88 files changed, 2958 insertions(+), 734 deletions(-) create mode 100644 apps/builder/src/pages/api/typebots/[typebotId]/whatsapp/media/preview/[mediaId].ts create mode 100644 packages/bot-engine/resetSessionState.ts create mode 100644 packages/embeds/js/src/components/Modal.tsx create mode 100644 packages/embeds/js/src/components/TextInputAddFileButton.tsx create mode 100644 packages/embeds/js/src/components/icons/CameraIcon.tsx create mode 100644 packages/embeds/js/src/components/icons/FileIcon.tsx create mode 100644 packages/embeds/js/src/components/icons/PaperClipIcon.tsx create mode 100644 packages/embeds/js/src/components/icons/PictureIcon.tsx create mode 100644 packages/embeds/js/src/components/icons/PlusIcon.tsx create mode 100644 packages/embeds/js/src/features/blocks/inputs/fileUpload/components/FilePreview.tsx create mode 100644 packages/embeds/js/src/features/blocks/inputs/fileUpload/components/SelectedFile.tsx create mode 100644 packages/embeds/js/src/features/blocks/inputs/fileUpload/helpers/sanitizeSelectedFiles.ts create mode 100644 packages/embeds/js/src/utils/toaster.ts create mode 100644 packages/lib/redis.ts create mode 100644 packages/prisma/postgresql/migrations/20240626074841_add_attachedfileurls_field_in_answerv2/migration.sql diff --git a/apps/builder/package.json b/apps/builder/package.json index bcf9be87e1..376021bc80 100644 --- a/apps/builder/package.json +++ b/apps/builder/package.json @@ -56,7 +56,6 @@ "@uiw/codemirror-theme-tokyo-night": "4.21.24", "@uiw/react-codemirror": "4.21.24", "@upstash/ratelimit": "0.4.3", - "@upstash/redis": "1.22.0", "@use-gesture/react": "10.2.27", "browser-image-compression": "2.0.2", "canvas-confetti": "1.6.0", @@ -69,6 +68,7 @@ "google-auth-library": "8.9.0", "google-spreadsheet": "4.1.1", "immer": "10.0.2", + "ioredis": "^5.4.1", "isolated-vm": "4.7.2", "jsonwebtoken": "9.0.1", "ky": "1.2.4", diff --git a/apps/builder/src/components/EditableEmojiOrImageIcon.tsx b/apps/builder/src/components/EditableEmojiOrImageIcon.tsx index 5f49038f68..fad061edaf 100644 --- a/apps/builder/src/components/EditableEmojiOrImageIcon.tsx +++ b/apps/builder/src/components/EditableEmojiOrImageIcon.tsx @@ -8,15 +8,17 @@ import { useColorModeValue, Portal, } from '@chakra-ui/react' -import React from 'react' +import React, { RefObject } from 'react' import { EmojiOrImageIcon } from './EmojiOrImageIcon' import { ImageUploadContent } from './ImageUploadContent' import { FilePathUploadProps } from '@/features/upload/api/generateUploadUrl' import { useTranslate } from '@tolgee/react' +import { useParentModal } from '@/features/graph/providers/ParentModalProvider' type Props = { uploadFileProps: FilePathUploadProps icon?: string | null + parentModalRef?: RefObject | undefined onChangeIcon: (icon: string) => void boxSize?: string } @@ -28,6 +30,7 @@ export const EditableEmojiOrImageIcon = ({ boxSize, }: Props) => { const { t } = useTranslate() + const { ref: parentModalRef } = useParentModal() const bg = useColorModeValue('gray.100', 'gray.700') return ( @@ -56,7 +59,7 @@ export const EditableEmojiOrImageIcon = ({ - + { 'date' ) await page.locator('[data-testid="from-date"]').fill('2021-01-01') - await page.locator('form').getByRole('button').click() + await page.getByLabel('Send').click() await expect(page.locator('text="01/01/2021"')).toBeVisible() await page.click(`text=Pick a date`) diff --git a/apps/builder/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts b/apps/builder/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts index 9bdb69903e..26ed08f239 100644 --- a/apps/builder/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts +++ b/apps/builder/src/features/blocks/inputs/fileUpload/fileUpload.spec.ts @@ -27,7 +27,9 @@ test('options should work', async ({ page }) => { await page .locator(`input[type="file"]`) .setInputFiles([getTestAsset('avatar.jpg')]) - await expect(page.locator(`text=File uploaded`)).toBeVisible() + await expect( + page.getByRole('img', { name: 'Attached image 1' }) + ).toBeVisible() await page.click('text="Collect file"') await page.click('text="Required?"') await page.click('text="Allow multiple files?"') @@ -46,9 +48,11 @@ test('options should work', async ({ page }) => { getTestAsset('avatar.jpg'), getTestAsset('avatar.jpg'), ]) - await expect(page.locator(`text="3"`)).toBeVisible() + await expect(page.getByRole('img', { name: 'avatar.jpg' })).toHaveCount(3) await page.locator('text="Go"').click() - await expect(page.locator(`text="3 files uploaded"`)).toBeVisible() + await expect( + page.getByRole('img', { name: 'Attached image 1' }) + ).toBeVisible() }) test.describe('Free workspace', () => { diff --git a/apps/builder/src/features/blocks/inputs/textInput/components/TextInputNodeContent.tsx b/apps/builder/src/features/blocks/inputs/textInput/components/TextInputNodeContent.tsx index 20ad882243..9ba9d005ae 100644 --- a/apps/builder/src/features/blocks/inputs/textInput/components/TextInputNodeContent.tsx +++ b/apps/builder/src/features/blocks/inputs/textInput/components/TextInputNodeContent.tsx @@ -1,25 +1,48 @@ import React from 'react' -import { Text } from '@chakra-ui/react' +import { Stack, Text } from '@chakra-ui/react' import { WithVariableContent } from '@/features/graph/components/nodes/block/WithVariableContent' import { TextInputBlock } from '@typebot.io/schemas' import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants' +import { useTypebot } from '@/features/editor/providers/TypebotProvider' +import { SetVariableLabel } from '@/components/SetVariableLabel' type Props = { options: TextInputBlock['options'] } export const TextInputNodeContent = ({ options }: Props) => { + const { typebot } = useTypebot() + const attachmentVariableId = + typebot && + options?.attachments?.isEnabled && + options?.attachments.saveVariableId if (options?.variableId) return ( - + + + {attachmentVariableId && ( + + )} + ) return ( - - {options?.labels?.placeholder ?? - defaultTextInputOptions.labels.placeholder} - + + + {options?.labels?.placeholder ?? + defaultTextInputOptions.labels.placeholder} + + {attachmentVariableId && ( + + )} + ) } diff --git a/apps/builder/src/features/blocks/inputs/textInput/components/TextInputSettings.tsx b/apps/builder/src/features/blocks/inputs/textInput/components/TextInputSettings.tsx index 73615e3ade..121c50c7a0 100644 --- a/apps/builder/src/features/blocks/inputs/textInput/components/TextInputSettings.tsx +++ b/apps/builder/src/features/blocks/inputs/textInput/components/TextInputSettings.tsx @@ -1,9 +1,12 @@ +import { DropdownList } from '@/components/DropdownList' +import { SwitchWithRelatedSettings } from '@/components/SwitchWithRelatedSettings' import { TextInput } from '@/components/inputs' import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel' import { VariableSearchInput } from '@/components/inputs/VariableSearchInput' import { FormLabel, Stack } from '@chakra-ui/react' import { useTranslate } from '@tolgee/react' import { TextInputBlock, Variable } from '@typebot.io/schemas' +import { fileVisibilityOptions } from '@typebot.io/schemas/features/blocks/inputs/file/constants' import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants' import React from 'react' @@ -14,21 +17,44 @@ type Props = { export const TextInputSettings = ({ options, onOptionsChange }: Props) => { const { t } = useTranslate() - const handlePlaceholderChange = (placeholder: string) => + const updatePlaceholder = (placeholder: string) => onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } }) - const handleButtonLabelChange = (button: string) => + + const updateButtonLabel = (button: string) => onOptionsChange({ ...options, labels: { ...options?.labels, button } }) - const handleLongChange = (isLong: boolean) => + + const updateIsLong = (isLong: boolean) => onOptionsChange({ ...options, isLong }) - const handleVariableChange = (variable?: Variable) => + + const updateVariableId = (variable?: Variable) => onOptionsChange({ ...options, variableId: variable?.id }) + const updateAttachmentsEnabled = (isEnabled: boolean) => + onOptionsChange({ + ...options, + attachments: { ...options?.attachments, isEnabled }, + }) + + const updateAttachmentsSaveVariableId = (variable?: Pick) => + onOptionsChange({ + ...options, + attachments: { ...options?.attachments, saveVariableId: variable?.id }, + }) + + const updateVisibility = ( + visibility: (typeof fileVisibilityOptions)[number] + ) => + onOptionsChange({ + ...options, + attachments: { ...options?.attachments, visibility }, + }) + return ( { options?.labels?.placeholder ?? defaultTextInputOptions.labels.placeholder } - onChange={handlePlaceholderChange} + onChange={updatePlaceholder} /> + + + + Save the URLs in a variable: + + + + + {t('blocks.inputs.settings.saveAnswer.label')} diff --git a/apps/builder/src/features/blocks/inputs/textInput/textInput.spec.ts b/apps/builder/src/features/blocks/inputs/textInput/textInput.spec.ts index 0b5edb44e9..ace3ed22e3 100644 --- a/apps/builder/src/features/blocks/inputs/textInput/textInput.spec.ts +++ b/apps/builder/src/features/blocks/inputs/textInput/textInput.spec.ts @@ -4,6 +4,7 @@ import { parseDefaultGroupWithBlock } from '@typebot.io/playwright/databaseHelpe import { createId } from '@paralleldrive/cuid2' import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants' import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants' +import { getTestAsset } from '@/test/utils/playwright' test.describe.parallel('Text input block', () => { test('options should work', async ({ page }) => { @@ -37,4 +38,48 @@ test.describe.parallel('Text input block', () => { ).toBeVisible() await expect(page.getByRole('button', { name: 'Go' })).toBeVisible() }) + + test('hey boy', async ({ page }) => { + const typebotId = createId() + await createTypebots([ + { + id: typebotId, + ...parseDefaultGroupWithBlock({ + type: InputBlockType.TEXT, + }), + }, + ]) + + await page.goto(`/typebots/${typebotId}/edit`) + + await page.click(`text=${defaultTextInputOptions.labels.placeholder}`) + await page.getByText('Allow attachments').click() + await page.locator('[data-testid="variables-input"]').first().click() + await page.getByText('var1').click() + await page.getByRole('button', { name: 'Test' }).click() + await page + .getByPlaceholder('Type your answer...') + .fill('Help me with these') + await page.getByLabel('Add attachments').click() + await expect(page.getByRole('menuitem', { name: 'Document' })).toBeVisible() + await expect( + page.getByRole('menuitem', { name: 'Photos & videos' }) + ).toBeVisible() + await page + .locator('#document-upload') + .setInputFiles(getTestAsset('typebots/theme.json')) + await expect(page.getByText('theme.json')).toBeVisible() + await page + .locator('#photos-upload') + .setInputFiles([getTestAsset('avatar.jpg'), getTestAsset('avatar.jpg')]) + await expect(page.getByRole('img', { name: 'avatar.jpg' })).toHaveCount(2) + await page.getByRole('img', { name: 'avatar.jpg' }).first().hover() + await page.getByLabel('Remove attachment').first().click() + await expect(page.getByRole('img', { name: 'avatar.jpg' })).toHaveCount(1) + await page.getByLabel('Send').click() + await expect( + page.getByRole('img', { name: 'Attached image 1' }) + ).toBeVisible() + await expect(page.getByText('Help me with these')).toBeVisible() + }) }) diff --git a/apps/builder/src/features/blocks/integrations/googleSheets/googleSheets.spec.ts b/apps/builder/src/features/blocks/integrations/googleSheets/googleSheets.spec.ts index 420304589a..b0bb7fcc04 100644 --- a/apps/builder/src/features/blocks/integrations/googleSheets/googleSheets.spec.ts +++ b/apps/builder/src/features/blocks/integrations/googleSheets/googleSheets.spec.ts @@ -19,9 +19,9 @@ test.describe.parallel('Google sheets integration', () => { await page.click('text=Add a value') await page.click('text=Select a column') - await page.click('button >> text="Email"') + await page.getByRole('menuitem', { name: 'Email' }).click() await page.click('[aria-label="Insert a variable"]') - await page.click('button >> text="Email" >> nth=1') + await page.getByRole('menuitem', { name: 'Email' }).last().click() await page.click('text=Add a value') await page.click('text=Select a column') @@ -61,11 +61,11 @@ test.describe.parallel('Google sheets integration', () => { await page.getByRole('button', { name: 'Row(s) to update' }).click() await page.getByRole('button', { name: 'Add filter rule' }).click() await page.click('text=Select a column') - await page.click('button >> text="Email"') + await page.getByRole('menuitem', { name: 'Email' }).click() await page.getByRole('button', { name: 'Select an operator' }).click() await page.getByRole('menuitem', { name: 'Equal to' }).click() await page.click('[aria-label="Insert a variable"]') - await page.click('button >> text="Email" >> nth=1') + await page.getByRole('menuitem', { name: 'Email' }).last().click() await page.getByRole('button', { name: 'Cells to update' }).click() await page.click('text=Add a value') @@ -106,11 +106,11 @@ test.describe.parallel('Google sheets integration', () => { await page.getByRole('button', { name: 'Select row(s)' }).click() await page.getByRole('button', { name: 'Add filter rule' }).click() await page.click('text=Select a column') - await page.click('button >> text="Email"') + await page.getByRole('menuitem', { name: 'Email' }).click() await page.getByRole('button', { name: 'Select an operator' }).click() await page.getByRole('menuitem', { name: 'Equal to' }).click() await page.click('[aria-label="Insert a variable"]') - await page.click('button >> text="Email" >> nth=1') + await page.getByRole('menuitem', { name: 'Email' }).last().click() await page.getByRole('button', { name: 'Add filter rule' }).click() await page.getByRole('button', { name: 'AND', exact: true }).click() diff --git a/apps/builder/src/features/blocks/logic/condition/condition.spec.ts b/apps/builder/src/features/blocks/logic/condition/condition.spec.ts index 0963c8fe86..a5989ba04f 100644 --- a/apps/builder/src/features/blocks/logic/condition/condition.spec.ts +++ b/apps/builder/src/features/blocks/logic/condition/condition.spec.ts @@ -20,7 +20,7 @@ test.describe('Condition block', () => { 'input[placeholder="Search for a variable"] >> nth=-1', 'Age' ) - await page.click('button:has-text("Age")') + await page.getByRole('menuitem', { name: 'Age' }).click() await page.click('button:has-text("Select an operator")') await page.click('button:has-text("Greater than")', { force: true }) await page.fill('input[placeholder="Type a number..."]', '80') @@ -31,7 +31,7 @@ test.describe('Condition block', () => { ':nth-match(input[placeholder="Search for a variable"], 2)', 'Age' ) - await page.click('button:has-text("Age")') + await page.getByRole('menuitem', { name: 'Age' }).click() await page.click('button:has-text("Select an operator")') await page.click('button:has-text("Less than")', { force: true }) await page.fill( @@ -44,7 +44,7 @@ test.describe('Condition block', () => { 'input[placeholder="Search for a variable"] >> nth=-1', 'Age' ) - await page.click('button:has-text("Age")') + await page.getByRole('menuitem', { name: 'Age' }).click() await page.click('button:has-text("Select an operator")') await page.click('button:has-text("Greater than")', { force: true }) await page.fill('input[placeholder="Type a number..."]', '20') diff --git a/apps/builder/src/features/blocks/logic/setVariable/setVariable.spec.ts b/apps/builder/src/features/blocks/logic/setVariable/setVariable.spec.ts index e2a63de662..40dcc6f2c7 100644 --- a/apps/builder/src/features/blocks/logic/setVariable/setVariable.spec.ts +++ b/apps/builder/src/features/blocks/logic/setVariable/setVariable.spec.ts @@ -23,10 +23,7 @@ test.describe('Set variable block', () => { await page.click('text=Click to edit... >> nth = 0') await page.fill('input[placeholder="Select a variable"] >> nth=-1', 'Total') await page.getByRole('menuitem', { name: 'Create Total' }).click() - await page - .getByTestId('code-editor') - .getByRole('textbox') - .fill('1000 * {{Num}}') + await page.locator('textarea').fill('1000 * {{Num}}') await page.click('text=Click to edit...', { force: true }) await expect(page.getByText('Save in results?')).toBeHidden() @@ -39,10 +36,7 @@ test.describe('Set variable block', () => { await expect( page.getByRole('group').nth(1).locator('.chakra-switch') ).not.toHaveAttribute('data-checked') - await page - .getByTestId('code-editor') - .getByRole('textbox') - .fill('Custom value') + await page.locator('textarea').fill('Custom value') await page.click('text=Click to edit...', { force: true }) await page.fill( @@ -50,10 +44,7 @@ test.describe('Set variable block', () => { 'Addition' ) await page.getByRole('menuitem', { name: 'Create Addition' }).click() - await page - .getByTestId('code-editor') - .getByRole('textbox') - .fill('1000 + {{Total}}') + await page.locator('textarea').fill('1000 + {{Total}}') await page.click('text=Test') await page @@ -94,14 +85,14 @@ test.describe('Set variable block', () => { await page.getByRole('button', { name: 'Test' }).click() await page.getByRole('button', { name: 'There is a bug 🐛' }).click() await page.getByTestId('textarea').fill('Hello!!') - await page.getByTestId('input').getByRole('button').click() + await page.getByLabel('Send').click() await page .locator('typebot-standard') .getByRole('button', { name: 'Restart' }) .click() await page.getByRole('button', { name: 'I have a question 💭' }).click() await page.getByTestId('textarea').fill('How are you?') - await page.getByTestId('input').getByRole('button').click() + await page.getByLabel('Send').click() await page.getByRole('button', { name: 'Transcription' }).click() await expect( diff --git a/apps/builder/src/features/blocks/logic/typebotLink/typebotLink.spec.ts b/apps/builder/src/features/blocks/logic/typebotLink/typebotLink.spec.ts index 366d79a02b..132b147d91 100644 --- a/apps/builder/src/features/blocks/logic/typebotLink/typebotLink.spec.ts +++ b/apps/builder/src/features/blocks/logic/typebotLink/typebotLink.spec.ts @@ -46,8 +46,8 @@ test('should be configurable', async ({ page }) => { await page.getByLabel('Clear').click() await page.click('text=Test') - await page.locator('typebot-standard').locator('input').fill('Hello there!') - await page.locator('typebot-standard').locator('input').press('Enter') + await page.getByPlaceholder('Type your answer...').fill('Hello there!') + await page.getByPlaceholder('Type your answer...').press('Enter') await expect( page.locator('typebot-standard').locator('text=Hello there!') ).toBeVisible() diff --git a/apps/builder/src/features/dashboard/components/DashboardHeader.tsx b/apps/builder/src/features/dashboard/components/DashboardHeader.tsx index ce78662f92..6f21a88b3a 100644 --- a/apps/builder/src/features/dashboard/components/DashboardHeader.tsx +++ b/apps/builder/src/features/dashboard/components/DashboardHeader.tsx @@ -9,6 +9,7 @@ import { useTranslate } from '@tolgee/react' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { WorkspaceDropdown } from '@/features/workspace/components/WorkspaceDropdown' import { WorkspaceSettingsModal } from '@/features/workspace/components/WorkspaceSettingsModal' +import { ParentModalProvider } from '@/features/graph/providers/ParentModalProvider' export const DashboardHeader = () => { const { t } = useTranslate() @@ -38,12 +39,14 @@ export const DashboardHeader = () => { {user && workspace && !workspace.isPastDue && ( - + + + )} {!workspace?.isPastDue && (