2
0

(wait) Add pause option on Wait block

Closes #751
This commit is contained in:
Baptiste Arnaud
2023-09-04 14:52:16 +02:00
parent 66dc570527
commit 111fb323b1
16 changed files with 672 additions and 589 deletions

View File

@@ -1,7 +1,15 @@
import { Stack } from '@chakra-ui/react' import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Stack,
} from '@chakra-ui/react'
import { WaitOptions } from '@typebot.io/schemas' import { WaitOptions } from '@typebot.io/schemas'
import React from 'react' import React from 'react'
import { TextInput } from '@/components/inputs' import { TextInput } from '@/components/inputs'
import { SwitchWithLabel } from '@/components/inputs/SwitchWithLabel'
type Props = { type Props = {
options: WaitOptions options: WaitOptions
@@ -13,6 +21,10 @@ export const WaitSettings = ({ options, onOptionsChange }: Props) => {
onOptionsChange({ ...options, secondsToWaitFor }) onOptionsChange({ ...options, secondsToWaitFor })
} }
const updateShouldPause = (shouldPause: boolean) => {
onOptionsChange({ ...options, shouldPause })
}
return ( return (
<Stack spacing={4}> <Stack spacing={4}>
<TextInput <TextInput
@@ -21,6 +33,22 @@ export const WaitSettings = ({ options, onOptionsChange }: Props) => {
onChange={handleSecondsChange} onChange={handleSecondsChange}
placeholder="0" placeholder="0"
/> />
<Accordion allowToggle>
<AccordionItem>
<AccordionButton justifyContent="space-between">
Advanced
<AccordionIcon />
</AccordionButton>
<AccordionPanel py="4">
<SwitchWithLabel
label="Pause the flow"
moreInfoContent="When enabled, the flow is paused until the client sends another message. This is automatic on the web bot."
initialValue={options.shouldPause ?? false}
onCheckChange={updateShouldPause}
/>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack> </Stack>
) )
} }

View File

@@ -7,3 +7,9 @@ This can be useful if you want the bot to emphasize on what's been said or to wa
:::caution :::caution
This should be used wisely. If you want the bot to write slower or faster in a more general sense, you need to check the [Typing emulation settings](/editor/settings#typing-emulation) This should be used wisely. If you want the bot to write slower or faster in a more general sense, you need to check the [Typing emulation settings](/editor/settings#typing-emulation)
::: :::
## Pause the flow
You can enable the "Pause the flow" option if you ever need to mark a pause in the flow.
Under the hood, typebot always compute all the blocks between each input blocks. But sometimes you may want to display some messages before a long-running action like a slow webhook request.

View File

@@ -2088,6 +2088,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -6381,6 +6384,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -10309,6 +10315,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -14377,6 +14386,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -18325,6 +18337,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -22328,6 +22343,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -26394,6 +26412,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false

View File

@@ -1671,6 +1671,9 @@
"properties": { "properties": {
"secondsToWaitFor": { "secondsToWaitFor": {
"type": "string" "type": "string"
},
"shouldPause": {
"type": "boolean"
} }
}, },
"additionalProperties": false "additionalProperties": false
@@ -5204,6 +5207,9 @@
"properties": { "properties": {
"lastBubbleBlockId": { "lastBubbleBlockId": {
"type": "string" "type": "string"
},
"expectsDedicatedReply": {
"type": "boolean"
} }
} }
}, },

View File

@@ -95,6 +95,7 @@ export const createChatCompletionOpenAI = async (
assistantMessageVariableName assistantMessageVariableName
), ),
}, },
expectsDedicatedReply: true,
}, },
], ],
outgoingEdgeId, outgoingEdgeId,

View File

@@ -64,6 +64,7 @@ export const executeWebhookBlock = async (
clientSideActions: [ clientSideActions: [
{ {
webhookToExecute: parsedWebhook, webhookToExecute: parsedWebhook,
expectsDedicatedReply: true,
}, },
], ],
} }

View File

@@ -34,6 +34,7 @@ export const executeSetVariable = (
setVariable: { setVariable: {
scriptToExecute, scriptToExecute,
}, },
expectsDedicatedReply: true,
}, },
], ],
} }

View File

@@ -19,6 +19,7 @@ export const executeWait = (
? [ ? [
{ {
wait: { secondsToWaitFor: parsedSecondsToWaitFor }, wait: { secondsToWaitFor: parsedSecondsToWaitFor },
expectsDedicatedReply: block.options.shouldPause,
}, },
] ]
: undefined, : undefined,

View File

@@ -1,6 +1,6 @@
import { TRPCError } from '@trpc/server'
import { import {
AnswerInSessionState, AnswerInSessionState,
Block,
BubbleBlockType, BubbleBlockType,
ChatReply, ChatReply,
InputBlock, InputBlock,
@@ -8,8 +8,6 @@ import {
IntegrationBlockType, IntegrationBlockType,
LogicBlockType, LogicBlockType,
SessionState, SessionState,
SetVariableBlock,
WebhookBlock,
defaultPaymentInputOptions, defaultPaymentInputOptions,
invalidEmailDefaultRetryMessage, invalidEmailDefaultRetryMessage,
} from '@typebot.io/schemas' } from '@typebot.io/schemas'
@@ -21,7 +19,6 @@ import { formatPhoneNumber } from '@/features/blocks/inputs/phone/formatPhoneNum
import { validateUrl } from '@/features/blocks/inputs/url/validateUrl' import { validateUrl } from '@/features/blocks/inputs/url/validateUrl'
import { updateVariables } from '@/features/variables/updateVariables' import { updateVariables } from '@/features/variables/updateVariables'
import { parseVariables } from '@/features/variables/parseVariables' import { parseVariables } from '@/features/variables/parseVariables'
import { OpenAIBlock } from '@typebot.io/schemas/features/blocks/integrations/openai'
import { resumeChatCompletion } from '@/features/blocks/integrations/openai/resumeChatCompletion' import { resumeChatCompletion } from '@/features/blocks/integrations/openai/resumeChatCompletion'
import { resumeWebhookExecution } from '@/features/blocks/integrations/webhook/resumeWebhookExecution' import { resumeWebhookExecution } from '@/features/blocks/integrations/webhook/resumeWebhookExecution'
import { upsertAnswer } from '../queries/upsertAnswer' import { upsertAnswer } from '../queries/upsertAnswer'
@@ -80,11 +77,7 @@ export const continueBotFlow =
})(reply) })(reply)
newSessionState = result.newSessionState newSessionState = result.newSessionState
} }
} else if (!isInputBlock(block)) }
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Current block is not an input block',
})
let formattedReply: string | undefined let formattedReply: string | undefined
@@ -276,10 +269,7 @@ const setNewAnswerInState =
const getOutgoingEdgeId = const getOutgoingEdgeId =
(state: Pick<SessionState, 'typebotsQueue'>) => (state: Pick<SessionState, 'typebotsQueue'>) =>
( (block: Block, reply: string | undefined) => {
block: InputBlock | SetVariableBlock | OpenAIBlock | WebhookBlock,
reply: string | undefined
) => {
const variables = state.typebotsQueue[0].typebot.variables const variables = state.typebotsQueue[0].typebot.variables
if ( if (
block.type === InputBlockType.CHOICE && block.type === InputBlockType.CHOICE &&

View File

@@ -94,10 +94,7 @@ export const executeGroup =
] ]
if ( if (
executionResponse.clientSideActions?.find( executionResponse.clientSideActions?.find(
(action) => (action) => action.expectsDedicatedReply
'setVariable' in action ||
'streamOpenAiChatCompletion' in action ||
'webhookToExecute' in action
) )
) { ) {
return { return {

View File

@@ -22,10 +22,7 @@ export const saveStateToDatabase = async ({
clientSideActions, clientSideActions,
}: Props) => { }: Props) => {
const containsSetVariableClientSideAction = clientSideActions?.some( const containsSetVariableClientSideAction = clientSideActions?.some(
(action) => (action) => action.expectsDedicatedReply
'setVariable' in action ||
'webhookToExecute' in action ||
'streamOpenAiChatCompletion' in action
) )
const isCompleted = Boolean(!input && !containsSetVariableClientSideAction) const isCompleted = Boolean(!input && !containsSetVariableClientSideAction)

View File

@@ -165,10 +165,7 @@ export const startSession = async ({
} }
const clientSideActionsNeedSessionId = clientSideActions?.some( const clientSideActionsNeedSessionId = clientSideActions?.some(
(action) => (action) => action.expectsDedicatedReply
'setVariable' in action ||
'streamOpenAiChatCompletion' in action ||
'webhookToExecute' in action
) )
if (!input && !clientSideActionsNeedSessionId) if (!input && !clientSideActionsNeedSessionId)

View File

@@ -39,7 +39,10 @@ export const executeClientSideAction = async ({
return executeRedirect(clientSideAction.redirect) return executeRedirect(clientSideAction.redirect)
} }
if ('wait' in clientSideAction) { if ('wait' in clientSideAction) {
return executeWait(clientSideAction.wait) await executeWait(clientSideAction.wait)
return clientSideAction.expectsDedicatedReply
? { replyToSend: undefined }
: undefined
} }
if ('setVariable' in clientSideAction) { if ('setVariable' in clientSideAction) {
return executeSetVariable(clientSideAction.setVariable.scriptToExecute) return executeSetVariable(clientSideAction.setVariable.scriptToExecute)

View File

@@ -4,6 +4,7 @@ import { LogicBlockType } from './enums'
export const waitOptionsSchema = z.object({ export const waitOptionsSchema = z.object({
secondsToWaitFor: z.string().optional(), secondsToWaitFor: z.string().optional(),
shouldPause: z.boolean().optional(),
}) })
export const waitBlockSchema = blockBaseSchema.merge( export const waitBlockSchema = blockBaseSchema.merge(

View File

@@ -177,6 +177,7 @@ const startPropsToInjectSchema = z.object({
const clientSideActionSchema = z const clientSideActionSchema = z
.object({ .object({
lastBubbleBlockId: z.string().optional(), lastBubbleBlockId: z.string().optional(),
expectsDedicatedReply: z.boolean().optional(),
}) })
.and( .and(
z z

1156
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff