🚸 (sendEmail) Make custom sender name optional
This commit is contained in:
@ -73,14 +73,12 @@ export const GeneralSettingsForm = ({
|
|||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="prefill"
|
|
||||||
label="Prefill input"
|
label="Prefill input"
|
||||||
initialValue={generalSettings.isInputPrefillEnabled ?? true}
|
initialValue={generalSettings.isInputPrefillEnabled ?? true}
|
||||||
onCheckChange={handleInputPrefillChange}
|
onCheckChange={handleInputPrefillChange}
|
||||||
moreInfoContent="Inputs are automatically pre-filled whenever their associated variable has a value"
|
moreInfoContent="Inputs are automatically pre-filled whenever their associated variable has a value"
|
||||||
/>
|
/>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="new-result"
|
|
||||||
label="Remember session"
|
label="Remember session"
|
||||||
initialValue={
|
initialValue={
|
||||||
isDefined(generalSettings.isNewResultOnRefreshEnabled)
|
isDefined(generalSettings.isNewResultOnRefreshEnabled)
|
||||||
@ -91,7 +89,6 @@ export const GeneralSettingsForm = ({
|
|||||||
moreInfoContent="If the user refreshes the page, its existing results will be overwritten. Disable this if you want to create a new results every time the user refreshes the page."
|
moreInfoContent="If the user refreshes the page, its existing results will be overwritten. Disable this if you want to create a new results every time the user refreshes the page."
|
||||||
/>
|
/>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="query-params"
|
|
||||||
label="Hide query params on bot start"
|
label="Hide query params on bot start"
|
||||||
initialValue={generalSettings.isHideQueryParamsEnabled ?? true}
|
initialValue={generalSettings.isHideQueryParamsEnabled ?? true}
|
||||||
onCheckChange={handleHideQueryParamsChange}
|
onCheckChange={handleHideQueryParamsChange}
|
||||||
|
@ -24,8 +24,7 @@ export const ChoiceInputSettingsBody = ({
|
|||||||
return (
|
return (
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id={'is-multiple'}
|
label="Multiple choice?"
|
||||||
label={'Multiple choice?'}
|
|
||||||
initialValue={options?.isMultipleChoice ?? false}
|
initialValue={options?.isMultipleChoice ?? false}
|
||||||
onCheckChange={handleIsMultipleChange}
|
onCheckChange={handleIsMultipleChange}
|
||||||
/>
|
/>
|
||||||
|
@ -33,7 +33,6 @@ export const CodeSettings = ({ options, onOptionsChange }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="shouldExecuteInParentContext"
|
|
||||||
label="Execute in parent window"
|
label="Execute in parent window"
|
||||||
moreInfoContent="Execute the code in the parent window context (when the bot is embedded). If it isn't detected, the code will be executed in the current window context."
|
moreInfoContent="Execute the code in the parent window context (when the bot is embedded). If it isn't detected, the code will be executed in the current window context."
|
||||||
initialValue={options.shouldExecuteInParentContext ?? false}
|
initialValue={options.shouldExecuteInParentContext ?? false}
|
||||||
|
@ -30,14 +30,12 @@ export const DateInputSettingsBody = ({
|
|||||||
return (
|
return (
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="is-range"
|
label="Is range?"
|
||||||
label={'Is range?'}
|
|
||||||
initialValue={options.isRange}
|
initialValue={options.isRange}
|
||||||
onCheckChange={handleIsRangeChange}
|
onCheckChange={handleIsRangeChange}
|
||||||
/>
|
/>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="with-time"
|
label="With time?"
|
||||||
label={'With time?'}
|
|
||||||
initialValue={options.isRange}
|
initialValue={options.isRange}
|
||||||
onCheckChange={handleHasTimeChange}
|
onCheckChange={handleHasTimeChange}
|
||||||
/>
|
/>
|
||||||
|
@ -28,13 +28,11 @@ export const FileInputSettings = ({ options, onOptionsChange }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="required"
|
|
||||||
label="Required?"
|
label="Required?"
|
||||||
initialValue={options.isRequired ?? true}
|
initialValue={options.isRequired ?? true}
|
||||||
onCheckChange={handleRequiredChange}
|
onCheckChange={handleRequiredChange}
|
||||||
/>
|
/>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="switch"
|
|
||||||
label="Allow multiple files?"
|
label="Allow multiple files?"
|
||||||
initialValue={options.isMultipleAllowed}
|
initialValue={options.isMultipleAllowed}
|
||||||
onCheckChange={handleMultipleFilesChange}
|
onCheckChange={handleMultipleFilesChange}
|
||||||
|
@ -68,7 +68,6 @@ export const RatingInputSettings = ({
|
|||||||
|
|
||||||
{options.buttonType === 'Icons' && (
|
{options.buttonType === 'Icons' && (
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="switch"
|
|
||||||
label="Custom icon?"
|
label="Custom icon?"
|
||||||
initialValue={options.customIcon.isEnabled}
|
initialValue={options.customIcon.isEnabled}
|
||||||
onCheckChange={handleCustomIconCheck}
|
onCheckChange={handleCustomIconCheck}
|
||||||
|
@ -29,7 +29,6 @@ export const RedirectSettings = ({ options, onOptionsChange }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="new-tab"
|
|
||||||
label="Open in new tab?"
|
label="Open in new tab?"
|
||||||
initialValue={options.isNewTab}
|
initialValue={options.isNewTab}
|
||||||
onCheckChange={handleIsNewTabChange}
|
onCheckChange={handleIsNewTabChange}
|
||||||
|
@ -154,7 +154,6 @@ export const SendEmailSettings = ({ options, onOptionsChange }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id={'custom-body'}
|
|
||||||
label={'Custom content?'}
|
label={'Custom content?'}
|
||||||
initialValue={options.isCustomBody ?? false}
|
initialValue={options.isCustomBody ?? false}
|
||||||
onCheckChange={handleIsCustomBodyChange}
|
onCheckChange={handleIsCustomBodyChange}
|
||||||
|
@ -28,60 +28,53 @@ export const SmtpConfigForm = ({ config, onConfigChange }: Props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack as="form" spacing={4}>
|
<Stack as="form" spacing={4}>
|
||||||
<FormControl isRequired>
|
<Input
|
||||||
<FormLabel>From email:</FormLabel>
|
isRequired
|
||||||
<Input
|
label="From email"
|
||||||
defaultValue={config.from.email ?? ''}
|
defaultValue={config.from.email ?? ''}
|
||||||
onChange={handleFromEmailChange}
|
onChange={handleFromEmailChange}
|
||||||
placeholder="notifications@provider.com"
|
placeholder="notifications@provider.com"
|
||||||
withVariableButton={false}
|
withVariableButton={false}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
<Input
|
||||||
<FormControl isRequired>
|
label="From name"
|
||||||
<FormLabel>From name:</FormLabel>
|
defaultValue={config.from.name ?? ''}
|
||||||
<Input
|
onChange={handleFromNameChange}
|
||||||
defaultValue={config.from.name ?? ''}
|
placeholder="John Smith"
|
||||||
onChange={handleFromNameChange}
|
withVariableButton={false}
|
||||||
placeholder="John Smith"
|
/>
|
||||||
withVariableButton={false}
|
<Input
|
||||||
/>
|
isRequired
|
||||||
</FormControl>
|
label="Host"
|
||||||
<FormControl isRequired>
|
defaultValue={config.host ?? ''}
|
||||||
<FormLabel>Host:</FormLabel>
|
onChange={handleHostChange}
|
||||||
<Input
|
placeholder="mail.provider.com"
|
||||||
defaultValue={config.host ?? ''}
|
withVariableButton={false}
|
||||||
onChange={handleHostChange}
|
/>
|
||||||
placeholder="mail.provider.com"
|
<Input
|
||||||
withVariableButton={false}
|
isRequired
|
||||||
/>
|
label="Username / Email"
|
||||||
</FormControl>
|
type="email"
|
||||||
<FormControl isRequired>
|
defaultValue={config.username ?? ''}
|
||||||
<FormLabel>Username / Email:</FormLabel>
|
onChange={handleUsernameChange}
|
||||||
<Input
|
placeholder="user@provider.com"
|
||||||
type="email"
|
withVariableButton={false}
|
||||||
defaultValue={config.username ?? ''}
|
/>
|
||||||
onChange={handleUsernameChange}
|
<Input
|
||||||
placeholder="user@provider.com"
|
isRequired
|
||||||
withVariableButton={false}
|
label="Password"
|
||||||
/>
|
type="password"
|
||||||
</FormControl>
|
defaultValue={config.password ?? ''}
|
||||||
<FormControl isRequired>
|
onChange={handlePasswordChange}
|
||||||
<FormLabel>Password:</FormLabel>
|
withVariableButton={false}
|
||||||
<Input
|
/>
|
||||||
type="password"
|
|
||||||
defaultValue={config.password ?? ''}
|
|
||||||
onChange={handlePasswordChange}
|
|
||||||
withVariableButton={false}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="Tls"
|
label="Secure?"
|
||||||
label={'Secure?'}
|
|
||||||
initialValue={config.isTlsEnabled ?? false}
|
initialValue={config.isTlsEnabled ?? false}
|
||||||
onCheckChange={handleTlsCheck}
|
onCheckChange={handleTlsCheck}
|
||||||
moreInfoContent="If enabled, the connection will use TLS when connecting to server. If disabled then TLS is used if server supports the STARTTLS extension. In most cases enable it if you are connecting to port 465. For port 587 or 25 keep it disabled."
|
moreInfoContent="If enabled, the connection will use TLS when connecting to server. If disabled then TLS is used if server supports the STARTTLS extension. In most cases enable it if you are connecting to port 465. For port 587 or 25 keep it disabled."
|
||||||
/>
|
/>
|
||||||
<FormControl as={HStack} justifyContent="space-between">
|
<FormControl as={HStack} justifyContent="space-between" isRequired>
|
||||||
<FormLabel mb="0">Port number:</FormLabel>
|
<FormLabel mb="0">Port number:</FormLabel>
|
||||||
<SmartNumberInput
|
<SmartNumberInput
|
||||||
placeholder="25"
|
placeholder="25"
|
||||||
|
@ -83,10 +83,10 @@ export const SmtpConfigModal = ({
|
|||||||
onClick={handleCreateClick}
|
onClick={handleCreateClick}
|
||||||
isDisabled={
|
isDisabled={
|
||||||
isNotDefined(smtpConfig.from.email) ||
|
isNotDefined(smtpConfig.from.email) ||
|
||||||
isNotDefined(smtpConfig.from.name) ||
|
|
||||||
isNotDefined(smtpConfig.host) ||
|
isNotDefined(smtpConfig.host) ||
|
||||||
isNotDefined(smtpConfig.username) ||
|
isNotDefined(smtpConfig.username) ||
|
||||||
isNotDefined(smtpConfig.password)
|
isNotDefined(smtpConfig.password) ||
|
||||||
|
isNotDefined(smtpConfig.port)
|
||||||
}
|
}
|
||||||
isLoading={isCreating}
|
isLoading={isCreating}
|
||||||
>
|
>
|
||||||
|
@ -26,7 +26,6 @@ export const TextInputSettingsBody = ({
|
|||||||
return (
|
return (
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id="switch"
|
|
||||||
label="Long text?"
|
label="Long text?"
|
||||||
initialValue={options?.isLong ?? false}
|
initialValue={options?.isLong ?? false}
|
||||||
onCheckChange={handleLongChange}
|
onCheckChange={handleLongChange}
|
||||||
|
@ -172,7 +172,6 @@ export const WebhookSettings = ({
|
|||||||
withVariableButton={!provider}
|
withVariableButton={!provider}
|
||||||
/>
|
/>
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id={'easy-config'}
|
|
||||||
label="Advanced configuration"
|
label="Advanced configuration"
|
||||||
initialValue={options.isAdvancedConfig ?? true}
|
initialValue={options.isAdvancedConfig ?? true}
|
||||||
onCheckChange={handleAdvancedConfigChange}
|
onCheckChange={handleAdvancedConfigChange}
|
||||||
@ -225,7 +224,6 @@ export const WebhookSettings = ({
|
|||||||
</AccordionButton>
|
</AccordionButton>
|
||||||
<AccordionPanel pb={4} as={Stack} spacing="6">
|
<AccordionPanel pb={4} as={Stack} spacing="6">
|
||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
id={'custom-body'}
|
|
||||||
label="Custom body"
|
label="Custom body"
|
||||||
initialValue={options.isCustomBody ?? true}
|
initialValue={options.isCustomBody ?? true}
|
||||||
onCheckChange={handleBodyFormStateChange}
|
onCheckChange={handleBodyFormStateChange}
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import { FormLabel, HStack, Switch, SwitchProps } from '@chakra-ui/react'
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
HStack,
|
||||||
|
Switch,
|
||||||
|
SwitchProps,
|
||||||
|
} from '@chakra-ui/react'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { MoreInfoTooltip } from './MoreInfoTooltip'
|
import { MoreInfoTooltip } from './MoreInfoTooltip'
|
||||||
|
|
||||||
type SwitchWithLabelProps = {
|
type SwitchWithLabelProps = {
|
||||||
id: string
|
|
||||||
label: string
|
label: string
|
||||||
initialValue: boolean
|
initialValue: boolean
|
||||||
moreInfoContent?: string
|
moreInfoContent?: string
|
||||||
@ -11,12 +16,11 @@ type SwitchWithLabelProps = {
|
|||||||
} & SwitchProps
|
} & SwitchProps
|
||||||
|
|
||||||
export const SwitchWithLabel = ({
|
export const SwitchWithLabel = ({
|
||||||
id,
|
|
||||||
label,
|
label,
|
||||||
initialValue,
|
initialValue,
|
||||||
moreInfoContent,
|
moreInfoContent,
|
||||||
onCheckChange,
|
onCheckChange,
|
||||||
...props
|
...switchProps
|
||||||
}: SwitchWithLabelProps) => {
|
}: SwitchWithLabelProps) => {
|
||||||
const [isChecked, setIsChecked] = useState(initialValue)
|
const [isChecked, setIsChecked] = useState(initialValue)
|
||||||
|
|
||||||
@ -25,21 +29,16 @@ export const SwitchWithLabel = ({
|
|||||||
onCheckChange(!isChecked)
|
onCheckChange(!isChecked)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<HStack justifyContent="space-between">
|
<FormControl as={HStack} justifyContent="space-between">
|
||||||
<HStack>
|
<FormLabel mb="0">
|
||||||
<FormLabel htmlFor={id} mb="0" mr="0">
|
{label}
|
||||||
{label}
|
|
||||||
</FormLabel>
|
|
||||||
{moreInfoContent && (
|
{moreInfoContent && (
|
||||||
<MoreInfoTooltip>{moreInfoContent}</MoreInfoTooltip>
|
<>
|
||||||
|
<MoreInfoTooltip>{moreInfoContent}</MoreInfoTooltip>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</HStack>
|
</FormLabel>
|
||||||
<Switch
|
<Switch isChecked={isChecked} onChange={handleChange} {...switchProps} />
|
||||||
isChecked={isChecked}
|
</FormControl>
|
||||||
onChange={handleChange}
|
|
||||||
id={id}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</HStack>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { createTypebots } from 'utils/playwright/databaseActions'
|
|||||||
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
|
||||||
import cuid from 'cuid'
|
import cuid from 'cuid'
|
||||||
import { defaultChatwootOptions, IntegrationBlockType } from 'models'
|
import { defaultChatwootOptions, IntegrationBlockType } from 'models'
|
||||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
|
||||||
|
|
||||||
const typebotId = cuid()
|
const typebotId = cuid()
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ test('should be configurable', async ({ page }) => {
|
|||||||
await page.click('input[placeholder="Select a typebot"]')
|
await page.click('input[placeholder="Select a typebot"]')
|
||||||
await page.click('text=My link typebot 2')
|
await page.click('text=My link typebot 2')
|
||||||
await expect(page.locator('input[value="My link typebot 2"]')).toBeVisible()
|
await expect(page.locator('input[value="My link typebot 2"]')).toBeVisible()
|
||||||
|
await expect(page.getByText('Jump in My link typebot 2')).toBeVisible()
|
||||||
await page.click('[aria-label="Navigate to typebot"]')
|
await page.click('[aria-label="Navigate to typebot"]')
|
||||||
await expect(page).toHaveURL(
|
await expect(page).toHaveURL(
|
||||||
`/typebots/${linkedTypebotId}/edit?parentId=${typebotId}`
|
`/typebots/${linkedTypebotId}/edit?parentId=${typebotId}`
|
||||||
|
@ -6,19 +6,16 @@ import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
|||||||
import { freeWorkspaceId } from 'utils/playwright/databaseSetup'
|
import { freeWorkspaceId } from 'utils/playwright/databaseSetup'
|
||||||
import { typebotViewer } from 'utils/playwright/testHelpers'
|
import { typebotViewer } from 'utils/playwright/testHelpers'
|
||||||
|
|
||||||
const typebotId = cuid()
|
|
||||||
|
|
||||||
test.describe.parallel('Settings page', () => {
|
test.describe.parallel('Settings page', () => {
|
||||||
test.beforeAll(async () => {
|
|
||||||
await importTypebotInDatabase(
|
|
||||||
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
|
||||||
{
|
|
||||||
id: typebotId,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
test.describe('General', () => {
|
test.describe('General', () => {
|
||||||
test('should reflect change in real-time', async ({ page }) => {
|
test('should reflect change in real-time', async ({ page }) => {
|
||||||
|
const typebotId = cuid()
|
||||||
|
await importTypebotInDatabase(
|
||||||
|
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
||||||
|
{
|
||||||
|
id: typebotId,
|
||||||
|
}
|
||||||
|
)
|
||||||
await page.goto(`/typebots/${typebotId}/settings`)
|
await page.goto(`/typebots/${typebotId}/settings`)
|
||||||
await expect(
|
await expect(
|
||||||
typebotViewer(page).locator('a:has-text("Made with Typebot")')
|
typebotViewer(page).locator('a:has-text("Made with Typebot")')
|
||||||
@ -72,7 +69,7 @@ test.describe.parallel('Settings page', () => {
|
|||||||
test('should be fillable', async ({ page }) => {
|
test('should be fillable', async ({ page }) => {
|
||||||
const favIconUrl = 'https://www.baptistearno.com/favicon.png'
|
const favIconUrl = 'https://www.baptistearno.com/favicon.png'
|
||||||
const imageUrl = 'https://www.baptistearno.com/images/site-preview.png'
|
const imageUrl = 'https://www.baptistearno.com/images/site-preview.png'
|
||||||
const typebotId = 'metadata-typebot'
|
const typebotId = cuid()
|
||||||
await importTypebotInDatabase(
|
await importTypebotInDatabase(
|
||||||
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
||||||
{
|
{
|
||||||
@ -124,7 +121,7 @@ test.describe.parallel('Settings page', () => {
|
|||||||
|
|
||||||
test.describe('Free workspace', () => {
|
test.describe('Free workspace', () => {
|
||||||
test("can't remove branding", async ({ page }) => {
|
test("can't remove branding", async ({ page }) => {
|
||||||
const typebotId = 'free-branding-typebot'
|
const typebotId = cuid()
|
||||||
await importTypebotInDatabase(
|
await importTypebotInDatabase(
|
||||||
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
||||||
{
|
{
|
||||||
|
@ -66,11 +66,7 @@ test('can create and delete a new workspace', async ({ page }) => {
|
|||||||
)
|
)
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
await page.click('text="Delete"')
|
await page.click('text="Delete"')
|
||||||
await expect(page.locator('text=Free workspace')).toBeVisible()
|
await expect(page.locator('text="John Doe\'s workspace"')).toBeHidden()
|
||||||
await page.click('text=Free workspace')
|
|
||||||
await expect(
|
|
||||||
page.locator('text="John Doe\'s workspace" >> nth=1')
|
|
||||||
).toBeHidden()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('can update workspace info', async ({ page }) => {
|
test('can update workspace info', async ({ page }) => {
|
||||||
|
Reference in New Issue
Block a user