2
0

♻️ Replace schemas with merge and discriminated unions

Closes #374
This commit is contained in:
Baptiste Arnaud
2023-03-14 16:42:12 +01:00
parent ff09814ead
commit d154c4e2f2
52 changed files with 3217 additions and 4328 deletions

View File

@ -14,7 +14,7 @@ import {
GoogleSheetsUpdateRowOptions,
} from 'models'
import React, { useMemo } from 'react'
import { isDefined, omit } from 'utils'
import { isDefined } from 'utils'
import { SheetsDropdown } from './SheetsDropdown'
import { SpreadsheetsDropdown } from './SpreadsheetDropdown'
import { CellWithValueStack } from './CellWithValueStack'
@ -50,8 +50,11 @@ export const GoogleSheetsSettingsBody = ({
() => sheets?.find((s) => s.id === options?.sheetId),
[sheets, options?.sheetId]
)
const handleCredentialsIdChange = (credentialsId?: string) =>
onOptionsChange({ ...omit(options, 'credentialsId'), credentialsId })
const handleCredentialsIdChange = (credentialsId: string | undefined) =>
onOptionsChange({
...options,
credentialsId,
})
const handleSpreadsheetIdChange = (spreadsheetId: string | undefined) =>
onOptionsChange({ ...options, spreadsheetId })
const handleSheetIdChange = (sheetId: string | undefined) =>
@ -137,7 +140,7 @@ export const GoogleSheetsSettingsBody = ({
/>
</>
)}
{'action' in options && (
{options.action && (
<ActionOptions
options={options}
sheet={sheet}

View File

@ -26,7 +26,7 @@ export const listTypebotsProcedure = authenticatedProcedure
icon: true,
id: true,
})
.and(z.object({ publishedTypebotId: z.string().optional() }))
.merge(z.object({ publishedTypebotId: z.string().optional() }))
),
})
)

View File

@ -1033,38 +1033,28 @@
"typebots": {
"type": "array",
"items": {
"allOf": [
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"icon": {
"type": "string",
"nullable": true
},
"id": {
"type": "string"
}
},
"required": [
"name",
"icon",
"id"
],
"additionalProperties": false
"type": "object",
"properties": {
"name": {
"type": "string"
},
{
"type": "object",
"properties": {
"publishedTypebotId": {
"type": "string"
}
},
"additionalProperties": false
"icon": {
"type": "string",
"nullable": true
},
"id": {
"type": "string"
},
"publishedTypebotId": {
"type": "string"
}
]
},
"required": [
"name",
"icon",
"id"
],
"additionalProperties": false
}
}
},
@ -1444,128 +1434,116 @@
"results": {
"type": "array",
"items": {
"allOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"typebotId": {
"type": "string"
},
"variables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"required": [
"id",
"name",
"value"
],
"additionalProperties": false
}
},
"isCompleted": {
"type": "boolean"
},
"hasStarted": {
"type": "boolean",
"nullable": true
},
"isArchived": {
"type": "boolean",
"nullable": true
}
},
"required": [
"id",
"createdAt",
"typebotId",
"variables",
"isCompleted",
"hasStarted",
"isArchived"
],
"additionalProperties": false
"type": "object",
"properties": {
"id": {
"type": "string"
},
{
"type": "object",
"properties": {
"answers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"createdAt": {
"type": "string",
"format": "date-time"
},
"resultId": {
"createdAt": {
"type": "string",
"format": "date-time"
},
"typebotId": {
"type": "string"
},
"variables": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"value": {
"anyOf": [
{
"type": "string"
},
"blockId": {
"type": "string"
},
"groupId": {
"type": "string"
},
"variableId": {
"type": "string",
"nullable": true
},
"content": {
"type": "string"
},
"storageUsed": {
"type": "number",
"nullable": true
{
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"createdAt",
"resultId",
"blockId",
"groupId",
"variableId",
"content",
"storageUsed"
],
"additionalProperties": false
]
}
}
},
"required": [
"answers"
],
"additionalProperties": false
},
"required": [
"id",
"name",
"value"
],
"additionalProperties": false
}
},
"isCompleted": {
"type": "boolean"
},
"hasStarted": {
"type": "boolean",
"nullable": true
},
"isArchived": {
"type": "boolean",
"nullable": true
},
"answers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"createdAt": {
"type": "string",
"format": "date-time"
},
"resultId": {
"type": "string"
},
"blockId": {
"type": "string"
},
"groupId": {
"type": "string"
},
"variableId": {
"type": "string",
"nullable": true
},
"content": {
"type": "string"
},
"storageUsed": {
"type": "number",
"nullable": true
}
},
"required": [
"createdAt",
"resultId",
"blockId",
"groupId",
"variableId",
"content",
"storageUsed"
],
"additionalProperties": false
}
}
]
},
"required": [
"id",
"createdAt",
"typebotId",
"variables",
"isCompleted",
"hasStarted",
"isArchived",
"answers"
],
"additionalProperties": false
}
},
"nextCursor": {

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,9 @@ export const executeGoogleSheetBlock = async (
state: SessionState,
block: GoogleSheetsBlock
): Promise<ExecuteIntegrationResponse> => {
if (!('action' in block.options))
return { outgoingEdgeId: block.outgoingEdgeId }
switch (block.options.action) {
const action = block.options.action
if (!action) return { outgoingEdgeId: block.outgoingEdgeId }
switch (action) {
case GoogleSheetsAction.INSERT_ROW:
return insertRow(state, {
options: block.options,

View File

@ -18,7 +18,7 @@ export const answerInputSchema = answerSchema
variableId: true,
storageUsed: true,
})
.and(
.merge(
z.object({
variableId: z.string().nullish(),
storageUsed: z.number().nullish(),

View File

@ -6,7 +6,7 @@ export const audioBubbleContentSchema = z.object({
url: z.string().optional(),
})
export const audioBubbleBlockSchema = blockBaseSchema.and(
export const audioBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.AUDIO]),
content: audioBubbleContentSchema,

View File

@ -8,7 +8,7 @@ export const embedBubbleContentSchema = z.object({
height: z.number().or(variableStringSchema),
})
export const embedBubbleBlockSchema = blockBaseSchema.and(
export const embedBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.EMBED]),
content: embedBubbleContentSchema,

View File

@ -6,7 +6,7 @@ export const imageBubbleContentSchema = z.object({
url: z.string().optional(),
})
export const imageBubbleBlockSchema = blockBaseSchema.and(
export const imageBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.IMAGE]),
content: imageBubbleContentSchema,

View File

@ -1,7 +1,6 @@
export * from './audio'
export * from './embed'
export * from './enums'
export * from './image'
export * from './schemas'
export * from './text'
export * from './video'
export * from './enums'

View File

@ -1,21 +0,0 @@
import { z } from 'zod'
import { audioBubbleBlockSchema, audioBubbleContentSchema } from './audio'
import { embedBubbleContentSchema, embedBubbleBlockSchema } from './embed'
import { imageBubbleContentSchema, imageBubbleBlockSchema } from './image'
import { textBubbleContentSchema, textBubbleBlockSchema } from './text'
import { videoBubbleContentSchema, videoBubbleBlockSchema } from './video'
export const bubbleBlockContentSchema = textBubbleContentSchema
.or(imageBubbleContentSchema)
.or(videoBubbleContentSchema)
.or(embedBubbleContentSchema)
.or(audioBubbleContentSchema)
export const bubbleBlockSchema = textBubbleBlockSchema
.or(imageBubbleBlockSchema)
.or(videoBubbleBlockSchema)
.or(embedBubbleBlockSchema)
.or(audioBubbleBlockSchema)
export type BubbleBlock = z.infer<typeof bubbleBlockSchema>
export type BubbleBlockContent = z.infer<typeof bubbleBlockContentSchema>

View File

@ -16,7 +16,7 @@ export const textBubbleContentSchema = z.object({
export type TextBubbleContent = z.infer<typeof textBubbleContentSchema>
export const textBubbleBlockSchema = blockBaseSchema.and(
export const textBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.TEXT]),
content: textBubbleContentSchema,

View File

@ -9,7 +9,7 @@ export const videoBubbleContentSchema = z.object({
type: z.nativeEnum(VideoBubbleContentType).optional(),
})
export const videoBubbleBlockSchema = blockBaseSchema.and(
export const videoBubbleBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([BubbleBlockType.VIDEO]),
content: videoBubbleContentSchema,

View File

@ -3,5 +3,5 @@ export * from './bubbles'
export * from './inputs'
export * from './integrations'
export * from './logic'
export * from './schemas'
export * from './start'
export * from './schemas'

View File

@ -5,7 +5,7 @@ import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const choiceInputOptionsSchema = optionBaseSchema.and(
export const choiceInputOptionsSchema = optionBaseSchema.merge(
z.object({
isMultipleChoice: z.boolean(),
buttonLabel: z.string(),
@ -18,14 +18,14 @@ export const defaultChoiceInputOptions: ChoiceInputOptions = {
isMultipleChoice: false,
}
export const buttonItemSchema = itemBaseSchema.and(
export const buttonItemSchema = itemBaseSchema.merge(
z.object({
type: z.literal(ItemType.BUTTON),
content: z.string().optional(),
})
)
export const choiceInputSchema = blockBaseSchema.and(
export const choiceInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.CHOICE]),
items: z.array(buttonItemSchema),

View File

@ -3,7 +3,7 @@ import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { defaultButtonLabel } from './constants'
import { InputBlockType } from './enums'
export const dateInputOptionsSchema = optionBaseSchema.and(
export const dateInputOptionsSchema = optionBaseSchema.merge(
z.object({
labels: z.object({
button: z.string(),
@ -15,7 +15,7 @@ export const dateInputOptionsSchema = optionBaseSchema.and(
})
)
export const dateInputSchema = blockBaseSchema.and(
export const dateInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.DATE]),
options: dateInputOptionsSchema,

View File

@ -5,14 +5,14 @@ import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const emailInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
})
)
export const emailInputSchema = blockBaseSchema.and(
export const emailInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.EMAIL]),
options: emailInputOptionsSchema,

View File

@ -2,7 +2,7 @@ import { z } from 'zod'
import { optionBaseSchema, blockBaseSchema } from '../baseSchemas'
import { InputBlockType } from './enums'
export const fileInputOptionsSchema = optionBaseSchema.and(
export const fileInputOptionsSchema = optionBaseSchema.merge(
z.object({
isRequired: z.boolean().optional(),
isMultipleAllowed: z.boolean(),
@ -16,7 +16,7 @@ export const fileInputOptionsSchema = optionBaseSchema.and(
})
)
export const fileInputStepSchema = blockBaseSchema.and(
export const fileInputStepSchema = blockBaseSchema.merge(
z.object({
type: z.literal(InputBlockType.FILE),
options: fileInputOptionsSchema,

View File

@ -8,6 +8,5 @@ export * from './number'
export * from './payment'
export * from './phone'
export * from './rating'
export * from './schemas'
export * from './text'
export * from './url'

View File

@ -5,8 +5,8 @@ import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const numberInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
min: z.number().optional(),
max: z.number().optional(),
@ -14,7 +14,7 @@ export const numberInputOptionsSchema = optionBaseSchema
})
)
export const numberInputSchema = blockBaseSchema.and(
export const numberInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.NUMBER]),
options: numberInputOptionsSchema,

View File

@ -14,7 +14,7 @@ export type CreditCardDetails = {
cvc: string
}
export const paymentInputOptionsSchema = optionBaseSchema.and(
export const paymentInputOptionsSchema = optionBaseSchema.merge(
z.object({
provider: z.nativeEnum(PaymentProvider),
labels: z.object({
@ -40,7 +40,7 @@ export const paymentInputRuntimeOptionsSchema = z.object({
publicKey: z.string(),
})
export const paymentInputSchema = blockBaseSchema.and(
export const paymentInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.PAYMENT]),
options: paymentInputOptionsSchema,

View File

@ -5,15 +5,15 @@ import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const phoneNumberInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
defaultCountryCode: z.string().optional(),
})
)
export const phoneNumberInputBlockSchema = blockBaseSchema.and(
export const phoneNumberInputBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.PHONE]),
options: phoneNumberInputOptionsSchema,

View File

@ -10,7 +10,7 @@ export const defaultRatingInputOptions: RatingInputOptions = {
customIcon: { isEnabled: false },
}
export const ratingInputOptionsSchema = optionBaseSchema.and(
export const ratingInputOptionsSchema = optionBaseSchema.merge(
z.object({
buttonType: z.literal('Icons').or(z.literal('Numbers')),
length: z.number(),
@ -27,7 +27,7 @@ export const ratingInputOptionsSchema = optionBaseSchema.and(
})
)
export const ratingInputBlockSchema = blockBaseSchema.and(
export const ratingInputBlockSchema = blockBaseSchema.merge(
z.object({
type: z.literal(InputBlockType.RATING),
options: ratingInputOptionsSchema,

View File

@ -1,42 +0,0 @@
import { z } from 'zod'
import { choiceInputOptionsSchema, choiceInputSchema } from './choice'
import { dateInputOptionsSchema, dateInputSchema } from './date'
import { emailInputOptionsSchema, emailInputSchema } from './email'
import { numberInputOptionsSchema, numberInputSchema } from './number'
import { paymentInputOptionsSchema, paymentInputSchema } from './payment'
import {
phoneNumberInputOptionsSchema,
phoneNumberInputBlockSchema,
} from './phone'
import { ratingInputOptionsSchema, ratingInputBlockSchema } from './rating'
import { textInputOptionsSchema, textInputSchema } from './text'
import { fileInputOptionsSchema, fileInputStepSchema } from './file'
import { urlInputOptionsSchema, urlInputSchema } from './url'
import { optionBaseSchema } from '../baseSchemas'
export type OptionBase = z.infer<typeof optionBaseSchema>
export const inputBlockOptionsSchema = textInputOptionsSchema
.or(choiceInputOptionsSchema)
.or(emailInputOptionsSchema)
.or(numberInputOptionsSchema)
.or(urlInputOptionsSchema)
.or(phoneNumberInputOptionsSchema)
.or(dateInputOptionsSchema)
.or(paymentInputOptionsSchema)
.or(ratingInputOptionsSchema)
.or(fileInputOptionsSchema)
export const inputBlockSchema = textInputSchema
.or(numberInputSchema)
.or(emailInputSchema)
.or(urlInputSchema)
.or(dateInputSchema)
.or(phoneNumberInputBlockSchema)
.or(choiceInputSchema)
.or(paymentInputSchema)
.or(ratingInputBlockSchema)
.or(fileInputStepSchema)
export type InputBlock = z.infer<typeof inputBlockSchema>
export type InputBlockOptions = z.infer<typeof inputBlockOptionsSchema>

View File

@ -11,8 +11,8 @@ export const textInputOptionsBaseSchema = z.object({
})
export const textInputOptionsSchema = textInputOptionsBaseSchema
.and(optionBaseSchema)
.and(
.merge(optionBaseSchema)
.merge(
z.object({
isLong: z.boolean(),
})
@ -23,7 +23,7 @@ export const defaultTextInputOptions: TextInputOptions = {
labels: { button: defaultButtonLabel, placeholder: 'Type your answer...' },
}
export const textInputSchema = blockBaseSchema.and(
export const textInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.TEXT]),
options: textInputOptionsSchema,

View File

@ -5,14 +5,14 @@ import { InputBlockType } from './enums'
import { textInputOptionsBaseSchema } from './text'
export const urlInputOptionsSchema = optionBaseSchema
.and(textInputOptionsBaseSchema)
.and(
.merge(textInputOptionsBaseSchema)
.merge(
z.object({
retryMessageContent: z.string(),
})
)
export const urlInputSchema = blockBaseSchema.and(
export const urlInputSchema = blockBaseSchema.merge(
z.object({
type: z.enum([InputBlockType.URL]),
options: urlInputOptionsSchema,

View File

@ -19,7 +19,7 @@ export const chatwootOptionsSchema = z.object({
.optional(),
})
export const chatwootBlockSchema = blockBaseSchema.and(
export const chatwootBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.CHATWOOT]),
options: chatwootOptionsSchema,

View File

@ -10,7 +10,7 @@ export const googleAnalyticsOptionsSchema = z.object({
value: z.number().optional(),
})
export const googleAnalyticsBlockSchema = blockBaseSchema.and(
export const googleAnalyticsBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.GOOGLE_ANALYTICS]),
options: googleAnalyticsOptionsSchema,

View File

@ -29,7 +29,13 @@ const rowsFilterComparisonSchema = z.object({
value: z.string().optional(),
})
const googleSheetsGetOptionsSchema = googleSheetsOptionsBaseSchema.and(
const initialGoogleSheetsOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.undefined(),
})
)
const googleSheetsGetOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.GET]),
// TODO: remove referenceCell once migrated to filtering
@ -42,14 +48,14 @@ const googleSheetsGetOptionsSchema = googleSheetsOptionsBaseSchema.and(
})
)
const googleSheetsInsertRowOptionsSchema = googleSheetsOptionsBaseSchema.and(
const googleSheetsInsertRowOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.INSERT_ROW]),
cellsToInsert: z.array(cellSchema),
})
)
const googleSheetsUpdateRowOptionsSchema = googleSheetsOptionsBaseSchema.and(
const googleSheetsUpdateRowOptionsSchema = googleSheetsOptionsBaseSchema.merge(
z.object({
action: z.enum([GoogleSheetsAction.UPDATE_ROW]),
cellsToUpsert: z.array(cellSchema),
@ -57,12 +63,14 @@ const googleSheetsUpdateRowOptionsSchema = googleSheetsOptionsBaseSchema.and(
})
)
export const googleSheetsOptionsSchema = googleSheetsGetOptionsSchema
.or(googleSheetsInsertRowOptionsSchema)
.or(googleSheetsUpdateRowOptionsSchema)
.or(googleSheetsOptionsBaseSchema)
export const googleSheetsOptionsSchema = z.discriminatedUnion('action', [
googleSheetsGetOptionsSchema,
googleSheetsInsertRowOptionsSchema,
googleSheetsUpdateRowOptionsSchema,
initialGoogleSheetsOptionsSchema,
])
export const googleSheetsBlockSchema = blockBaseSchema.and(
export const googleSheetsBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.GOOGLE_SHEETS]),
options: googleSheetsOptionsSchema,

View File

@ -4,7 +4,6 @@ export * from './googleAnalytics'
export * from './googleSheets'
export * from './makeCom'
export * from './pabblyConnect'
export * from './schemas'
export * from './sendEmail'
export * from './webhook'
export * from './zapier'

View File

@ -3,7 +3,7 @@ import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const makeComBlockSchema = blockBaseSchema.and(
export const makeComBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.MAKE_COM]),
options: webhookOptionsSchema,

View File

@ -3,7 +3,7 @@ import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const pabblyConnectBlockSchema = blockBaseSchema.and(
export const pabblyConnectBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.PABBLY_CONNECT]),
options: webhookOptionsSchema,

View File

@ -1,23 +0,0 @@
import { z } from 'zod'
import { chatwootBlockSchema } from './chatwoot'
import { googleAnalyticsBlockSchema } from './googleAnalytics'
import { googleSheetsBlockSchema } from './googleSheets/schemas'
import { makeComBlockSchema } from './makeCom'
import { openAIBlockSchema } from './openai'
import { pabblyConnectBlockSchema } from './pabblyConnect'
import { sendEmailBlockSchema } from './sendEmail'
import { webhookBlockSchema } from './webhook'
import { zapierBlockSchema } from './zapier'
export const integrationBlockSchema = googleSheetsBlockSchema
.or(googleAnalyticsBlockSchema)
.or(webhookBlockSchema)
.or(sendEmailBlockSchema)
.or(zapierBlockSchema)
.or(makeComBlockSchema)
.or(pabblyConnectBlockSchema)
.or(chatwootBlockSchema)
.or(openAIBlockSchema)
export type IntegrationBlock = z.infer<typeof integrationBlockSchema>
export type IntegrationBlockOptions = IntegrationBlock['options']

View File

@ -15,7 +15,7 @@ export const sendEmailOptionsSchema = z.object({
attachmentsVariableId: z.string().optional(),
})
export const sendEmailBlockSchema = blockBaseSchema.and(
export const sendEmailBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.EMAIL]),
options: sendEmailOptionsSchema,

View File

@ -21,7 +21,7 @@ export const webhookOptionsSchema = z.object({
isCustomBody: z.boolean().optional(),
})
export const webhookBlockSchema = blockBaseSchema.and(
export const webhookBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.WEBHOOK]),
options: webhookOptionsSchema,

View File

@ -3,7 +3,7 @@ import { blockBaseSchema } from '../baseSchemas'
import { IntegrationBlockType } from './enums'
import { webhookOptionsSchema } from './webhook'
export const zapierBlockSchema = blockBaseSchema.and(
export const zapierBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([IntegrationBlockType.ZAPIER]),
options: webhookOptionsSchema,

View File

@ -30,14 +30,14 @@ const conditionContentSchema = z.object({
comparisons: z.array(comparisonSchema),
})
export const conditionItemSchema = itemBaseSchema.and(
export const conditionItemSchema = itemBaseSchema.merge(
z.object({
type: z.literal(ItemType.CONDITION),
content: conditionContentSchema,
})
)
export const conditionBlockSchema = blockBaseSchema.and(
export const conditionBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.CONDITION]),
items: z.array(conditionItemSchema),

View File

@ -1,7 +1,6 @@
export * from './script'
export * from './condition'
export * from './enums'
export * from './logicBlock'
export * from './redirect'
export * from './setVariable'
export * from './typebotLink'

View File

@ -7,7 +7,7 @@ export const jumpOptionsSchema = z.object({
blockId: z.string().optional(),
})
export const jumpBlockSchema = blockBaseSchema.and(
export const jumpBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.JUMP]),
options: jumpOptionsSchema,

View File

@ -1,26 +0,0 @@
import { z } from 'zod'
import { scriptOptionsSchema, scriptBlockSchema } from './script'
import { conditionBlockSchema } from './condition'
import { redirectOptionsSchema, redirectBlockSchema } from './redirect'
import { setVariableOptionsSchema, setVariableBlockSchema } from './setVariable'
import { typebotLinkOptionsSchema, typebotLinkBlockSchema } from './typebotLink'
import { waitBlockSchema, waitOptionsSchema } from './wait'
import { jumpBlockSchema, jumpOptionsSchema } from './jump'
const logicBlockOptionsSchema = scriptOptionsSchema
.or(redirectOptionsSchema)
.or(setVariableOptionsSchema)
.or(typebotLinkOptionsSchema)
.or(waitOptionsSchema)
.or(jumpOptionsSchema)
export const logicBlockSchema = scriptBlockSchema
.or(conditionBlockSchema)
.or(redirectBlockSchema)
.or(typebotLinkBlockSchema)
.or(setVariableBlockSchema)
.or(waitBlockSchema)
.or(jumpBlockSchema)
export type LogicBlock = z.infer<typeof logicBlockSchema>
export type LogicBlockOptions = z.infer<typeof logicBlockOptionsSchema>

View File

@ -7,7 +7,7 @@ export const redirectOptionsSchema = z.object({
isNewTab: z.boolean(),
})
export const redirectBlockSchema = blockBaseSchema.and(
export const redirectBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.REDIRECT]),
options: redirectOptionsSchema,

View File

@ -8,7 +8,7 @@ export const scriptOptionsSchema = z.object({
shouldExecuteInParentContext: z.boolean().optional(),
})
export const scriptBlockSchema = blockBaseSchema.and(
export const scriptBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.SCRIPT]),
options: scriptOptionsSchema,

View File

@ -8,7 +8,7 @@ export const setVariableOptionsSchema = z.object({
isCode: z.boolean().optional(),
})
export const setVariableBlockSchema = blockBaseSchema.and(
export const setVariableBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.SET_VARIABLE]),
options: setVariableOptionsSchema,

View File

@ -7,7 +7,7 @@ export const typebotLinkOptionsSchema = z.object({
groupId: z.string().optional(),
})
export const typebotLinkBlockSchema = blockBaseSchema.and(
export const typebotLinkBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.TYPEBOT_LINK]),
options: typebotLinkOptionsSchema,

View File

@ -6,7 +6,7 @@ export const waitOptionsSchema = z.object({
secondsToWaitFor: z.string().optional(),
})
export const waitBlockSchema = blockBaseSchema.and(
export const waitBlockSchema = blockBaseSchema.merge(
z.object({
type: z.enum([LogicBlockType.WAIT]),
options: waitOptionsSchema,

View File

@ -1,28 +1,49 @@
import { z } from 'zod'
import { BubbleBlockType } from './bubbles/enums'
import { BubbleBlock, bubbleBlockSchema } from './bubbles/schemas'
import { ChoiceInputBlock } from './inputs/choice'
import { ChoiceInputBlock, choiceInputSchema } from './inputs/choice'
import { InputBlockType } from './inputs/enums'
import {
InputBlock,
InputBlockOptions,
inputBlockSchema,
} from './inputs/schemas'
import { IntegrationBlockType } from './integrations/enums'
import {
IntegrationBlock,
IntegrationBlockOptions,
integrationBlockSchema,
} from './integrations/schemas'
import { ConditionBlock } from './logic/condition'
import { ConditionBlock, conditionBlockSchema } from './logic/condition'
import { LogicBlockType } from './logic/enums'
import {
LogicBlock,
LogicBlockOptions,
logicBlockSchema,
} from './logic/logicBlock'
import { blockBaseSchema } from './baseSchemas'
import { startBlockSchema } from './start/schemas'
import {
textBubbleBlockSchema,
imageBubbleBlockSchema,
videoBubbleBlockSchema,
embedBubbleBlockSchema,
audioBubbleBlockSchema,
} from './bubbles'
import {
textInputSchema,
emailInputSchema,
numberInputSchema,
urlInputSchema,
phoneNumberInputBlockSchema,
dateInputSchema,
paymentInputSchema,
ratingInputBlockSchema,
fileInputStepSchema,
} from './inputs'
import {
chatwootBlockSchema,
googleAnalyticsBlockSchema,
googleSheetsBlockSchema,
makeComBlockSchema,
pabblyConnectBlockSchema,
sendEmailBlockSchema,
webhookBlockSchema,
zapierBlockSchema,
} from './integrations'
import { openAIBlockSchema } from './integrations/openai'
import {
scriptBlockSchema,
redirectBlockSchema,
setVariableBlockSchema,
typebotLinkBlockSchema,
waitBlockSchema,
} from './logic'
import { jumpBlockSchema } from './logic/jump'
export type DraggableBlock =
| BubbleBlock
@ -67,10 +88,74 @@ export type BlockIndices = {
blockIndex: number
}
export const blockSchema = startBlockSchema
.or(bubbleBlockSchema)
.or(inputBlockSchema)
.or(logicBlockSchema)
.or(integrationBlockSchema)
const bubbleBlockSchema = z.discriminatedUnion('type', [
textBubbleBlockSchema,
imageBubbleBlockSchema,
videoBubbleBlockSchema,
embedBubbleBlockSchema,
audioBubbleBlockSchema,
])
export type BubbleBlock = z.infer<typeof bubbleBlockSchema>
export type BubbleBlockContent = BubbleBlock['content']
export const inputBlockSchema = z.discriminatedUnion('type', [
textInputSchema,
choiceInputSchema,
emailInputSchema,
numberInputSchema,
urlInputSchema,
phoneNumberInputBlockSchema,
dateInputSchema,
paymentInputSchema,
ratingInputBlockSchema,
fileInputStepSchema,
])
export type InputBlock = z.infer<typeof inputBlockSchema>
export type InputBlockOptions = InputBlock['options']
export const logicBlockSchema = z.discriminatedUnion('type', [
scriptBlockSchema,
conditionBlockSchema,
redirectBlockSchema,
setVariableBlockSchema,
typebotLinkBlockSchema,
waitBlockSchema,
jumpBlockSchema,
])
export type LogicBlock = z.infer<typeof logicBlockSchema>
export type LogicBlockOptions = LogicBlock extends
| {
options?: infer Options
}
| {}
? Options
: never
export const integrationBlockSchema = z.discriminatedUnion('type', [
chatwootBlockSchema,
googleAnalyticsBlockSchema,
googleSheetsBlockSchema,
makeComBlockSchema,
openAIBlockSchema,
pabblyConnectBlockSchema,
sendEmailBlockSchema,
webhookBlockSchema,
zapierBlockSchema,
])
export type IntegrationBlock = z.infer<typeof integrationBlockSchema>
export type IntegrationBlockOptions = IntegrationBlock['options']
export const blockSchema = z.union([
startBlockSchema,
bubbleBlockSchema,
inputBlockSchema,
logicBlockSchema,
integrationBlockSchema,
])
export type Block = z.infer<typeof blockSchema>

View File

@ -1,7 +1,7 @@
import { z } from 'zod'
import { blockBaseSchema } from '../baseSchemas'
export const startBlockSchema = blockBaseSchema.and(
export const startBlockSchema = blockBaseSchema.merge(
z.object({
type: z.literal('start'),
label: z.string(),

View File

@ -1,7 +1,6 @@
import { z } from 'zod'
import {
googleAnalyticsOptionsSchema,
inputBlockSchema,
paymentInputRuntimeOptionsSchema,
redirectOptionsSchema,
} from './blocks'
@ -9,7 +8,6 @@ import { publicTypebotSchema } from './publicTypebot'
import { logSchema, resultSchema } from './result'
import { typebotSchema } from './typebot'
import {
BubbleBlockType,
textBubbleContentSchema,
imageBubbleContentSchema,
videoBubbleContentSchema,
@ -17,6 +15,8 @@ import {
embedBubbleContentSchema,
} from './blocks/bubbles'
import { answerSchema } from './answer'
import { BubbleBlockType } from './blocks/bubbles/enums'
import { inputBlockSchema } from './blocks/schemas'
const typebotInSessionStateSchema = publicTypebotSchema.pick({
id: true,
@ -40,7 +40,7 @@ const resultInSessionStateSchema = resultSchema
.pick({
variables: true,
})
.and(
.merge(
z.object({
answers: z.array(answerInSessionStateSchema),
id: z.string().optional(),
@ -72,7 +72,7 @@ const chatSessionSchema = z.object({
})
const textMessageSchema = z.object({
type: z.enum([BubbleBlockType.TEXT]),
type: z.literal(BubbleBlockType.TEXT),
content: textBubbleContentSchema.omit({
richText: true,
}),
@ -99,17 +99,19 @@ const embedMessageSchema = z.object({
.omit({
height: true,
})
.and(z.object({ height: z.number().optional() })),
.merge(z.object({ height: z.number().optional() })),
})
const chatMessageSchema = z
.object({ id: z.string() })
.and(
textMessageSchema
.or(imageMessageSchema)
.or(videoMessageSchema)
.or(audioMessageSchema)
.or(embedMessageSchema)
z.discriminatedUnion('type', [
textMessageSchema,
imageMessageSchema,
videoMessageSchema,
audioMessageSchema,
embedMessageSchema,
])
)
const scriptToExecuteSchema = z.object({
@ -187,7 +189,7 @@ const replyLogSchema = logSchema
status: true,
description: true,
})
.and(z.object({ details: z.unknown().optional() }))
.merge(z.object({ details: z.unknown().optional() }))
const clientSideActionSchema = z
.object({

View File

@ -22,7 +22,7 @@ export const publicTypebotSchema = z.object({
settings: settingsSchema,
}) satisfies z.ZodType<PrismaPublicTypebot>
const publicTypebotWithName = publicTypebotSchema.and(
const publicTypebotWithName = publicTypebotSchema.merge(
typebotSchema.pick({ name: true, isArchived: true, isClosed: true })
)

View File

@ -14,13 +14,13 @@ export const resultSchema = z.object({
isArchived: z.boolean().nullable(),
}) satisfies z.ZodType<ResultPrisma>
export const resultWithAnswersSchema = resultSchema.and(
export const resultWithAnswersSchema = resultSchema.merge(
z.object({
answers: z.array(answerSchema),
})
)
export const resultWithAnswersInputSchema = resultSchema.and(
export const resultWithAnswersInputSchema = resultSchema.merge(
z.object({
answers: z.array(answerInputSchema),
})

View File

@ -11,7 +11,7 @@ const containerColorsSchema = z.object({
color: z.string(),
})
const inputColorsSchema = containerColorsSchema.and(
const inputColorsSchema = containerColorsSchema.merge(
z.object({
placeholderColor: z.string(),
})

View File

@ -1,9 +1,9 @@
import { z } from 'zod'
import { settingsSchema } from './settings'
import { blockSchema } from '../blocks'
import { themeSchema } from './theme'
import { variableSchema } from './variable'
import { Typebot as TypebotPrisma } from 'db'
import { blockSchema } from '../blocks/schemas'
export const groupSchema = z.object({
id: z.string(),