🚸 Improve parsing preprocessing on typebots

This commit is contained in:
Baptiste Arnaud
2023-08-23 10:57:38 +02:00
parent fe54888350
commit 0acede92ef
24 changed files with 132 additions and 584 deletions

View File

@@ -1,14 +0,0 @@
import { Webhook } from '@typebot.io/schemas'
import { sendRequest } from '@typebot.io/lib'
type Props = {
typebotId: string
data: Partial<Omit<Webhook, 'typebotId'>>
}
export const createWebhookQuery = ({ typebotId, data }: Props) =>
sendRequest<{ webhook: Webhook }>({
method: 'POST',
url: `/api/typebots/${typebotId}/webhooks`,
body: { data },
})

View File

@@ -1,27 +0,0 @@
import { Webhook } from '@typebot.io/schemas'
import { sendRequest } from '@typebot.io/lib'
import { createWebhookQuery } from './createWebhookQuery'
type Props = {
existingIds: { typebotId: string; webhookId: string }
newIds: { typebotId: string; webhookId: string }
}
export const duplicateWebhookQuery = async ({
existingIds,
newIds,
}: Props): Promise<Webhook | undefined> => {
const { data } = await sendRequest<{ webhook: Webhook }>(
`/api/typebots/${existingIds.typebotId}/webhooks/${existingIds.webhookId}`
)
if (!data) return
const newWebhook = {
...data.webhook,
id: newIds.webhookId,
typebotId: newIds.typebotId,
}
await createWebhookQuery({
typebotId: newIds.typebotId,
data: { ...data.webhook, id: newIds.webhookId },
})
return newWebhook
}

View File

@@ -1,15 +0,0 @@
import { Webhook } from '@typebot.io/schemas'
import { sendRequest } from '@typebot.io/lib'
type Props = {
typebotId: string
webhookId: string
data: Partial<Omit<Webhook, 'id' | 'typebotId'>>
}
export const updateWebhookQuery = ({ typebotId, webhookId, data }: Props) =>
sendRequest<{ webhook: Webhook }>({
method: 'PATCH',
url: `/api/typebots/${typebotId}/webhooks/${webhookId}`,
body: { data },
})

View File

@@ -24,7 +24,7 @@ export const getLinkedTypebots = authenticatedProcedure
.output(
z.object({
typebots: z.array(
typebotSchema.pick({
typebotSchema._def.schema.pick({
id: true,
groups: true,
variables: true,
@@ -58,7 +58,7 @@ export const getLinkedTypebots = authenticatedProcedure
throw new TRPCError({ code: 'NOT_FOUND', message: 'No typebot found' })
const linkedTypebotIds =
typebotSchema.shape.groups
typebotSchema._def.schema.shape.groups
.parse(typebot.groups)
.flatMap((group) => group.blocks)
.reduce<string[]>(
@@ -102,8 +102,10 @@ export const getLinkedTypebots = authenticatedProcedure
})
.map((typebot) => ({
...typebot,
groups: typebotSchema.shape.groups.parse(typebot.groups),
variables: typebotSchema.shape.variables.parse(typebot.variables),
groups: typebotSchema._def.schema.shape.groups.parse(typebot.groups),
variables: typebotSchema._def.schema.shape.variables.parse(
typebot.variables
),
}))
return {

View File

@@ -1,62 +0,0 @@
import { createId } from '@paralleldrive/cuid2'
import {
defaultSettings,
defaultTheme,
Group,
StartBlock,
Typebot,
} from '@typebot.io/schemas'
// TODO: remove
export type NewTypebotProps = Omit<
Typebot,
| 'createdAt'
| 'updatedAt'
| 'id'
| 'publicId'
| 'customDomain'
| 'icon'
| 'isArchived'
| 'isClosed'
| 'resultsTablePreferences'
>
export const parseNewTypebot = ({
folderId,
name,
workspaceId,
isBrandingEnabled = true,
}: {
folderId: string | null
workspaceId: string
name: string
ownerAvatarUrl?: string
isBrandingEnabled?: boolean
}): NewTypebotProps => {
const startGroupId = createId()
const startBlockId = createId()
const startBlock: StartBlock = {
groupId: startGroupId,
id: startBlockId,
label: 'Start',
type: 'start',
}
const startGroup: Group = {
id: startGroupId,
title: 'Start',
graphCoordinates: { x: 0, y: 0 },
blocks: [startBlock],
}
return {
folderId,
name,
version: '4',
workspaceId,
groups: [startGroup],
edges: [],
variables: [],
selectedThemeTemplateId: null,
theme: defaultTheme,
settings: defaultSettings({ isBrandingEnabled }),
}
}

View File

@@ -33,9 +33,7 @@ test('should not be able to submit taken url ID', async ({ page }) => {
await page.getByRole('textbox').press('Enter')
await expect(
page
.getByText(
'Should contain only contain letters, numbers. Words can be separated by dashes.'
)
.getByText('Can only contain lowercase letters, numbers and dashes.')
.nth(0)
).toBeVisible()
await page.getByText(`${typebotId}-public`).click()

View File

@@ -1,4 +1,3 @@
import { parseInvalidTypebot } from '@/features/typebot/helpers/parseInvalidTypebot'
import { useToast } from '@/hooks/useToast'
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
import { Typebot, typebotCreateSchema } from '@typebot.io/schemas'
@@ -19,9 +18,7 @@ export const ImportTypebotFromFileButton = ({
const file = e.target.files[0]
const fileContent = await readFile(file)
try {
const typebot = typebotCreateSchema.parse(
parseInvalidTypebot(JSON.parse(fileContent))
)
const typebot = typebotCreateSchema.parse(JSON.parse(fileContent))
onNewTypebot(typebot as Typebot)
} catch (err) {
console.error(err)

View File

@@ -4,8 +4,6 @@ import { TRPCError } from '@trpc/server'
import { publicTypebotSchema } from '@typebot.io/schemas'
import { z } from 'zod'
import { isReadTypebotForbidden } from '../helpers/isReadTypebotForbidden'
import { parseInvalidTypebot } from '../helpers/parseInvalidTypebot'
import { PublicTypebot } from '@typebot.io/schemas'
export const getPublishedTypebot = authenticatedProcedure
.meta({
@@ -50,7 +48,7 @@ export const getPublishedTypebot = authenticatedProcedure
try {
const parsedTypebot = publicTypebotSchema.parse(
parseInvalidTypebot(existingTypebot.publishedTypebot as PublicTypebot)
existingTypebot.publishedTypebot
)
return {

View File

@@ -4,10 +4,7 @@ import { TRPCError } from '@trpc/server'
import { Typebot, typebotSchema } from '@typebot.io/schemas'
import { z } from 'zod'
import { isReadTypebotForbidden } from '../helpers/isReadTypebotForbidden'
import { omit } from '@typebot.io/lib'
import { Typebot as TypebotFromDb } from '@typebot.io/prisma'
import { migrateTypebotFromV3ToV4 } from '@typebot.io/lib/migrations/migrateTypebotFromV3ToV4'
import { parseInvalidTypebot } from '../helpers/parseInvalidTypebot'
export const getTypebot = authenticatedProcedure
.meta({
@@ -46,8 +43,8 @@ export const getTypebot = authenticatedProcedure
throw new TRPCError({ code: 'NOT_FOUND', message: 'Typebot not found' })
try {
const parsedTypebot = await parseTypebot(
omit(existingTypebot, 'collaborators')
const parsedTypebot = await migrateTypebot(
typebotSchema.parse(existingTypebot)
)
return {
@@ -66,10 +63,7 @@ export const getTypebot = authenticatedProcedure
}
})
const parseTypebot = async (typebot: TypebotFromDb): Promise<Typebot> => {
const parsedTypebot = typebotSchema.parse(
typebot.version !== '5' ? parseInvalidTypebot(typebot as Typebot) : typebot
)
if (['4', '5'].includes(parsedTypebot.version ?? '')) return parsedTypebot
return migrateTypebotFromV3ToV4(prisma)(parsedTypebot)
const migrateTypebot = async (typebot: Typebot): Promise<Typebot> => {
if (['4', '5'].includes(typebot.version ?? '')) return typebot
return migrateTypebotFromV3ToV4(prisma)(typebot)
}

View File

@@ -21,7 +21,7 @@ export const listTypebots = authenticatedProcedure
.output(
z.object({
typebots: z.array(
typebotSchema
typebotSchema._def.schema
.pick({
name: true,
icon: true,

View File

@@ -49,15 +49,21 @@ export const publishTypebot = authenticatedProcedure
},
data: {
version: existingTypebot.version,
edges: typebotSchema.shape.edges.parse(existingTypebot.edges),
groups: typebotSchema.shape.groups.parse(existingTypebot.groups),
settings: typebotSchema.shape.settings.parse(
edges: typebotSchema._def.schema.shape.edges.parse(
existingTypebot.edges
),
groups: typebotSchema._def.schema.shape.groups.parse(
existingTypebot.groups
),
settings: typebotSchema._def.schema.shape.settings.parse(
existingTypebot.settings
),
variables: typebotSchema.shape.variables.parse(
variables: typebotSchema._def.schema.shape.variables.parse(
existingTypebot.variables
),
theme: typebotSchema.shape.theme.parse(existingTypebot.theme),
theme: typebotSchema._def.schema.shape.theme.parse(
existingTypebot.theme
),
},
})
else
@@ -65,15 +71,21 @@ export const publishTypebot = authenticatedProcedure
data: {
version: existingTypebot.version,
typebotId: existingTypebot.id,
edges: typebotSchema.shape.edges.parse(existingTypebot.edges),
groups: typebotSchema.shape.groups.parse(existingTypebot.groups),
settings: typebotSchema.shape.settings.parse(
edges: typebotSchema._def.schema.shape.edges.parse(
existingTypebot.edges
),
groups: typebotSchema._def.schema.shape.groups.parse(
existingTypebot.groups
),
settings: typebotSchema._def.schema.shape.settings.parse(
existingTypebot.settings
),
variables: typebotSchema.shape.variables.parse(
variables: typebotSchema._def.schema.shape.variables.parse(
existingTypebot.variables
),
theme: typebotSchema.shape.theme.parse(existingTypebot.theme),
theme: typebotSchema._def.schema.shape.theme.parse(
existingTypebot.theme
),
},
})

View File

@@ -27,7 +27,7 @@ export const updateTypebot = authenticatedProcedure
z.object({
typebotId: z.string(),
typebot: typebotCreateSchema.merge(
typebotSchema
typebotSchema._def.schema
.pick({
isClosed: true,
})

View File

@@ -1,12 +0,0 @@
import { Edge, PublicTypebot, Typebot, edgeSchema } from '@typebot.io/schemas'
export const parseInvalidTypebot = (
typebot: Typebot | PublicTypebot
): Typebot | PublicTypebot => ({
...typebot,
version: typebot.version as null | '3' | '4' | '5',
edges: parseInvalidEdges(typebot.edges),
})
const parseInvalidEdges = (edges: Edge[]) =>
edges?.filter((edge) => edgeSchema.safeParse(edge).success)