@@ -1,23 +1,21 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { isNotEmpty } from '@typebot.io/lib'
|
||||
import { GoogleAnalyticsBlock, SessionState } from '@typebot.io/schemas'
|
||||
|
||||
export const executeGoogleAnalyticsBlock = (
|
||||
{ typebot: { variables } }: SessionState,
|
||||
{ typebot: { variables }, result }: SessionState,
|
||||
block: GoogleAnalyticsBlock
|
||||
): ExecuteIntegrationResponse => {
|
||||
const googleAnalytics = deepParseVariables(variables)(block.options)
|
||||
if (!result) return { outgoingEdgeId: block.outgoingEdgeId }
|
||||
const googleAnalytics = deepParseVariables(variables, {
|
||||
guessCorrectTypes: true,
|
||||
removeEmptyStrings: true,
|
||||
})(block.options)
|
||||
return {
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
clientSideActions: [
|
||||
{
|
||||
googleAnalytics: {
|
||||
...googleAnalytics,
|
||||
value: isNotEmpty(googleAnalytics.value as string)
|
||||
? Number(googleAnalytics.value)
|
||||
: undefined,
|
||||
},
|
||||
googleAnalytics,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { deepParseVariables } from '@/features/variables/deepParseVariable'
|
||||
import { PixelBlock, SessionState } from '@typebot.io/schemas'
|
||||
|
||||
export const executePixelBlock = (
|
||||
{ typebot: { variables }, result }: SessionState,
|
||||
block: PixelBlock
|
||||
): ExecuteIntegrationResponse => {
|
||||
if (!result) return { outgoingEdgeId: block.outgoingEdgeId }
|
||||
const pixel = deepParseVariables(variables, {
|
||||
guessCorrectTypes: true,
|
||||
removeEmptyStrings: true,
|
||||
})(block.options)
|
||||
return {
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
clientSideActions: [
|
||||
{
|
||||
pixel: {
|
||||
...pixel,
|
||||
pixelId: block.options.pixelId,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import {
|
||||
ChatReply,
|
||||
chatReplySchema,
|
||||
ChatSession,
|
||||
GoogleAnalyticsBlock,
|
||||
IntegrationBlockType,
|
||||
PixelBlock,
|
||||
ResultInSession,
|
||||
sendMessageInputSchema,
|
||||
SessionState,
|
||||
@@ -180,10 +183,40 @@ const startSession = async (startParams?: StartParams, userId?: string) => {
|
||||
'setVariable' in action || 'streamOpenAiChatCompletion' in action
|
||||
)
|
||||
|
||||
const startClientSideAction = clientSideActions ?? []
|
||||
|
||||
const parsedStartPropsActions = parseStartClientSideAction(typebot)
|
||||
|
||||
const startLogs = logs ?? []
|
||||
|
||||
if (isDefined(parsedStartPropsActions)) {
|
||||
if (!result) {
|
||||
if ('startPropsToInject' in parsedStartPropsActions) {
|
||||
const { customHeadCode, googleAnalyticsId, pixelId, gtmId } =
|
||||
parsedStartPropsActions.startPropsToInject
|
||||
let toolsList = ''
|
||||
if (customHeadCode) toolsList += 'Custom head code, '
|
||||
if (googleAnalyticsId) toolsList += 'Google Analytics, '
|
||||
if (pixelId) toolsList += 'Pixel, '
|
||||
if (gtmId) toolsList += 'Google Tag Manager, '
|
||||
toolsList = toolsList.slice(0, -2)
|
||||
startLogs.push({
|
||||
description: `${toolsList} ${
|
||||
toolsList.includes(',') ? 'are not' : 'is not'
|
||||
} enabled in Preview mode`,
|
||||
status: 'info',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
startClientSideAction.push(parsedStartPropsActions)
|
||||
}
|
||||
}
|
||||
|
||||
if (!input && !clientSideActionsNeedSessionId)
|
||||
return {
|
||||
messages,
|
||||
clientSideActions,
|
||||
clientSideActions:
|
||||
startClientSideAction.length > 0 ? startClientSideAction : undefined,
|
||||
typebot: {
|
||||
id: typebot.id,
|
||||
settings: deepParseVariables(newSessionState.typebot.variables)(
|
||||
@@ -194,7 +227,7 @@ const startSession = async (startParams?: StartParams, userId?: string) => {
|
||||
),
|
||||
},
|
||||
dynamicTheme: parseDynamicThemeReply(newSessionState),
|
||||
logs,
|
||||
logs: startLogs.length > 0 ? startLogs : undefined,
|
||||
}
|
||||
|
||||
const session = (await prisma.chatSession.create({
|
||||
@@ -217,9 +250,10 @@ const startSession = async (startParams?: StartParams, userId?: string) => {
|
||||
},
|
||||
messages,
|
||||
input,
|
||||
clientSideActions,
|
||||
clientSideActions:
|
||||
startClientSideAction.length > 0 ? startClientSideAction : undefined,
|
||||
dynamicTheme: parseDynamicThemeReply(newSessionState),
|
||||
logs,
|
||||
logs: startLogs.length > 0 ? startLogs : undefined,
|
||||
} satisfies ChatReply
|
||||
}
|
||||
|
||||
@@ -403,3 +437,38 @@ const parseDynamicThemeReply = (
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
const parseStartClientSideAction = (
|
||||
typebot: StartTypebot
|
||||
): NonNullable<ChatReply['clientSideActions']>[number] | undefined => {
|
||||
const blocks = typebot.groups.flatMap((group) => group.blocks)
|
||||
const startPropsToInject = {
|
||||
customHeadCode: typebot.settings.metadata.customHeadCode,
|
||||
gtmId: typebot.settings.metadata.googleTagManagerId,
|
||||
googleAnalyticsId: (
|
||||
blocks.find(
|
||||
(block) =>
|
||||
block.type === IntegrationBlockType.GOOGLE_ANALYTICS &&
|
||||
block.options.trackingId
|
||||
) as GoogleAnalyticsBlock | undefined
|
||||
)?.options.trackingId,
|
||||
pixelId: (
|
||||
blocks.find(
|
||||
(block) =>
|
||||
block.type === IntegrationBlockType.PIXEL && block.options.pixelId
|
||||
) as PixelBlock | undefined
|
||||
)?.options.pixelId,
|
||||
}
|
||||
|
||||
if (
|
||||
!startPropsToInject.customHeadCode &&
|
||||
!startPropsToInject.gtmId &&
|
||||
!startPropsToInject.googleAnalyticsId &&
|
||||
!startPropsToInject.pixelId
|
||||
)
|
||||
return
|
||||
|
||||
return {
|
||||
startPropsToInject,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,11 @@ const parseBubbleBlock =
|
||||
(block: BubbleBlock): ChatReply['messages'][0] => {
|
||||
switch (block.type) {
|
||||
case BubbleBlockType.TEXT:
|
||||
return deepParseVariables(variables, { takeLatestIfList: true })(block)
|
||||
return deepParseVariables(
|
||||
variables,
|
||||
{},
|
||||
{ takeLatestIfList: true }
|
||||
)(block)
|
||||
case BubbleBlockType.EMBED: {
|
||||
const message = deepParseVariables(variables)(block)
|
||||
return {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { executeWebhookBlock } from '@/features/blocks/integrations/webhook/exec
|
||||
import { executeChatwootBlock } from '@/features/blocks/integrations/chatwoot/executeChatwootBlock'
|
||||
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/executeGoogleAnalyticsBlock'
|
||||
import { executeGoogleSheetBlock } from '@/features/blocks/integrations/googleSheets/executeGoogleSheetBlock'
|
||||
import { executePixelBlock } from '@/features/blocks/integrations/pixel/executePixelBlock'
|
||||
import {
|
||||
IntegrationBlock,
|
||||
IntegrationBlockType,
|
||||
@@ -30,5 +31,7 @@ export const executeIntegration =
|
||||
return executeWebhookBlock(state, block)
|
||||
case IntegrationBlockType.OPEN_AI:
|
||||
return executeOpenAIBlock(state, block)
|
||||
case IntegrationBlockType.PIXEL:
|
||||
return executePixelBlock(state, block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,38 @@ import {
|
||||
parseVariables,
|
||||
ParseVariablesOptions,
|
||||
} from './parseVariables'
|
||||
import { parseGuessedTypeFromString } from './parseGuessedTypeFromString'
|
||||
|
||||
type DeepParseOptions = {
|
||||
guessCorrectTypes?: boolean
|
||||
removeEmptyStrings?: boolean
|
||||
}
|
||||
|
||||
export const deepParseVariables =
|
||||
(
|
||||
variables: Variable[],
|
||||
options: ParseVariablesOptions = defaultParseVariablesOptions
|
||||
deepParseOptions: DeepParseOptions = {
|
||||
guessCorrectTypes: false,
|
||||
removeEmptyStrings: false,
|
||||
},
|
||||
parseVariablesOptions: ParseVariablesOptions = defaultParseVariablesOptions
|
||||
) =>
|
||||
<T extends Record<string, unknown>>(object: T): T =>
|
||||
Object.keys(object).reduce<T>((newObj, key) => {
|
||||
const currentValue = object[key]
|
||||
|
||||
if (typeof currentValue === 'string') {
|
||||
const parsedVariable = parseVariables(variables, options)(currentValue)
|
||||
const parsedVariable = parseVariables(
|
||||
variables,
|
||||
parseVariablesOptions
|
||||
)(currentValue)
|
||||
if (deepParseOptions.removeEmptyStrings && parsedVariable === '')
|
||||
return newObj
|
||||
return {
|
||||
...newObj,
|
||||
[key]: parsedVariable,
|
||||
[key]: deepParseOptions.guessCorrectTypes
|
||||
? parseGuessedTypeFromString(parsedVariable)
|
||||
: parsedVariable,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,14 +44,21 @@ export const deepParseVariables =
|
||||
...newObj,
|
||||
[key]: deepParseVariables(
|
||||
variables,
|
||||
options
|
||||
deepParseOptions,
|
||||
parseVariablesOptions
|
||||
)(currentValue as Record<string, unknown>),
|
||||
}
|
||||
|
||||
if (currentValue instanceof Array)
|
||||
return {
|
||||
...newObj,
|
||||
[key]: currentValue.map(deepParseVariables(variables, options)),
|
||||
[key]: currentValue.map(
|
||||
deepParseVariables(
|
||||
variables,
|
||||
deepParseOptions,
|
||||
parseVariablesOptions
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
return { ...newObj, [key]: currentValue }
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export const parseGuessedTypeFromString = (value: string): unknown => {
|
||||
if (value === 'undefined') return undefined
|
||||
return safeJsonParse(value)
|
||||
}
|
||||
|
||||
const safeJsonParse = (value: string): unknown => {
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export const parseVariables =
|
||||
return text.replace(
|
||||
pattern,
|
||||
(_full, nameInCurlyBraces, _dollarSign, nameInTemplateLitteral) => {
|
||||
const dollarSign = _dollarSign ?? ''
|
||||
const dollarSign = (_dollarSign ?? '') as string
|
||||
const matchedVarName = nameInCurlyBraces ?? nameInTemplateLitteral
|
||||
const variable = variables.find((variable) => {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user