🚸 Improve parsing preprocessing on typebots
This commit is contained in:
@@ -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 },
|
||||
})
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 },
|
||||
})
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 }),
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ export const listTypebots = authenticatedProcedure
|
||||
.output(
|
||||
z.object({
|
||||
typebots: z.array(
|
||||
typebotSchema
|
||||
typebotSchema._def.schema
|
||||
.pick({
|
||||
name: true,
|
||||
icon: true,
|
||||
|
||||
@@ -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
|
||||
),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const updateTypebot = authenticatedProcedure
|
||||
z.object({
|
||||
typebotId: z.string(),
|
||||
typebot: typebotCreateSchema.merge(
|
||||
typebotSchema
|
||||
typebotSchema._def.schema
|
||||
.pick({
|
||||
isClosed: true,
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user