@@ -4,7 +4,7 @@ import { authenticatedProcedure } from '@/helpers/server/trpc'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { Typebot, Webhook } from '@typebot.io/schemas'
|
||||
import { z } from 'zod'
|
||||
import { getLinkedTypebots } from '@/features/blocks/logic/typebotLink/helpers/getLinkedTypebots'
|
||||
import { fetchLinkedTypebots } from '@/features/blocks/logic/typebotLink/helpers/fetchLinkedTypebots'
|
||||
import { parseResultExample } from '../helpers/parseResultExample'
|
||||
|
||||
export const getResultExample = authenticatedProcedure
|
||||
@@ -63,7 +63,7 @@ export const getResultExample = authenticatedProcedure
|
||||
if (!block)
|
||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Block not found' })
|
||||
|
||||
const linkedTypebots = await getLinkedTypebots(typebot, user)
|
||||
const linkedTypebots = await fetchLinkedTypebots(typebot, user)
|
||||
|
||||
return {
|
||||
resultExample: await parseResultExample(
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import prisma from '@/lib/prisma'
|
||||
import { authenticatedProcedure } from '@/helpers/server/trpc'
|
||||
import { TRPCError } from '@trpc/server'
|
||||
import { Typebot, typebotSchema } from '@typebot.io/schemas'
|
||||
import { z } from 'zod'
|
||||
import { getUserRoleInWorkspace } from '@/features/workspace/helpers/getUserRoleInWorkspace'
|
||||
|
||||
export const getLinkedTypebots = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/linkedTypebots',
|
||||
protect: true,
|
||||
summary: 'Get linked typebots',
|
||||
tags: ['Typebot'],
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
workspaceId: z.string(),
|
||||
typebotIds: z.string().describe('Comma separated list of typebot ids'),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
typebots: z.array(
|
||||
typebotSchema.pick({
|
||||
id: true,
|
||||
groups: true,
|
||||
variables: true,
|
||||
name: true,
|
||||
})
|
||||
),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { workspaceId, typebotIds }, ctx: { user } }) => {
|
||||
const typebotIdsArray = typebotIds.split(',')
|
||||
const workspace = await prisma.workspace.findUnique({
|
||||
where: { id: workspaceId },
|
||||
select: { members: true },
|
||||
})
|
||||
const userRole = getUserRoleInWorkspace(user.id, workspace?.members)
|
||||
if (userRole === undefined)
|
||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
||||
const typebots = (await prisma.typebot.findMany({
|
||||
where: {
|
||||
isArchived: { not: true },
|
||||
id: { in: typebotIdsArray },
|
||||
workspaceId,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
select: {
|
||||
id: true,
|
||||
groups: true,
|
||||
variables: true,
|
||||
name: true,
|
||||
},
|
||||
})) as Pick<Typebot, 'id' | 'groups' | 'variables' | 'name'>[]
|
||||
|
||||
if (!typebots)
|
||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'No typebots found' })
|
||||
|
||||
return {
|
||||
typebots,
|
||||
}
|
||||
})
|
||||
@@ -1,27 +1,22 @@
|
||||
import prisma from '@/lib/prisma'
|
||||
import { canReadTypebots } from '@/helpers/databaseRules'
|
||||
import { User } from '@typebot.io/prisma'
|
||||
import {
|
||||
LogicBlockType,
|
||||
PublicTypebot,
|
||||
Typebot,
|
||||
TypebotLinkBlock,
|
||||
} from '@typebot.io/schemas'
|
||||
import { isDefined } from '@typebot.io/lib'
|
||||
import { LogicBlockType, PublicTypebot, Typebot } from '@typebot.io/schemas'
|
||||
|
||||
export const getLinkedTypebots = async (
|
||||
export const fetchLinkedTypebots = async (
|
||||
typebot: Pick<PublicTypebot, 'groups'>,
|
||||
user?: User
|
||||
): Promise<(Typebot | PublicTypebot)[]> => {
|
||||
const linkedTypebotIds = (
|
||||
typebot.groups
|
||||
.flatMap((g) => g.blocks)
|
||||
.filter(
|
||||
(s) =>
|
||||
s.type === LogicBlockType.TYPEBOT_LINK &&
|
||||
isDefined(s.options.typebotId)
|
||||
) as TypebotLinkBlock[]
|
||||
).map((s) => s.options.typebotId as string)
|
||||
const linkedTypebotIds = typebot.groups
|
||||
.flatMap((group) => group.blocks)
|
||||
.reduce<string[]>((typebotIds, block) => {
|
||||
if (block.type !== LogicBlockType.TYPEBOT_LINK) return typebotIds
|
||||
const typebotId = block.options.typebotId
|
||||
if (!typebotId) return typebotIds
|
||||
return typebotIds.includes(typebotId)
|
||||
? typebotIds
|
||||
: [...typebotIds, typebotId]
|
||||
}, [])
|
||||
if (linkedTypebotIds.length === 0) return []
|
||||
const typebots = (await ('typebotId' in typebot
|
||||
? prisma.publicTypebot.findMany({
|
||||
@@ -36,6 +31,6 @@ export const getLinkedTypebots = async (
|
||||
],
|
||||
}
|
||||
: { id: { in: linkedTypebotIds } },
|
||||
}))) as unknown as (Typebot | PublicTypebot)[]
|
||||
}))) as (Typebot | PublicTypebot)[]
|
||||
return typebots
|
||||
}
|
||||
@@ -57,7 +57,7 @@ test('should be configurable', async ({ page }) => {
|
||||
await page.waitForTimeout(1000)
|
||||
await page.getByTestId('selected-item-label').first().click({ force: true })
|
||||
await page.click('button >> text=Current typebot')
|
||||
await page.getByPlaceholder('Select a block').click()
|
||||
await page.getByRole('textbox').nth(1).click()
|
||||
await page.click('button >> text=Hello')
|
||||
|
||||
await page.click('text=Preview')
|
||||
|
||||
@@ -24,7 +24,6 @@ import { dequal } from 'dequal'
|
||||
import { useToast } from '@/hooks/useToast'
|
||||
import { useTypebotQuery } from '@/hooks/useTypebotQuery'
|
||||
import { useUndo } from '../hooks/useUndo'
|
||||
import { useLinkedTypebots } from '@/hooks/useLinkedTypebots'
|
||||
import { updateTypebotQuery } from '../queries/updateTypebotQuery'
|
||||
import { updateWebhookQuery } from '@/features/blocks/integrations/webhook/queries/updateWebhookQuery'
|
||||
import { useAutoSave } from '@/hooks/useAutoSave'
|
||||
@@ -39,6 +38,7 @@ import { areTypebotsEqual } from '@/features/publish/helpers/areTypebotsEqual'
|
||||
import { isPublished as isPublishedHelper } from '@/features/publish/helpers/isPublished'
|
||||
import { convertTypebotToPublicTypebot } from '@/features/publish/helpers/convertTypebotToPublicTypebot'
|
||||
import { convertPublicTypebotToTypebot } from '@/features/publish/helpers/convertPublicTypebotToTypebot'
|
||||
import { trpc } from '@/lib/trpc'
|
||||
|
||||
const autoSaveTimeout = 10000
|
||||
|
||||
@@ -65,7 +65,7 @@ const typebotContext = createContext<
|
||||
{
|
||||
typebot?: Typebot
|
||||
publishedTypebot?: PublicTypebot
|
||||
linkedTypebots?: Typebot[]
|
||||
linkedTypebots?: Pick<Typebot, 'id' | 'groups' | 'variables' | 'name'>[]
|
||||
webhooks: Webhook[]
|
||||
isReadOnly?: boolean
|
||||
isPublished: boolean
|
||||
@@ -132,16 +132,21 @@ export const TypebotProvider = ({
|
||||
[]
|
||||
) ?? []
|
||||
|
||||
const { typebots: linkedTypebots } = useLinkedTypebots({
|
||||
workspaceId: localTypebot?.workspaceId ?? undefined,
|
||||
typebotId,
|
||||
typebotIds: linkedTypebotIds,
|
||||
onError: (error) =>
|
||||
showToast({
|
||||
title: 'Error while fetching linkedTypebots',
|
||||
description: error.message,
|
||||
}),
|
||||
})
|
||||
const { data: linkedTypebotsData } = trpc.getLinkedTypebots.useQuery(
|
||||
{
|
||||
workspaceId: localTypebot?.workspaceId as string,
|
||||
typebotIds: linkedTypebotIds.join(','),
|
||||
},
|
||||
{
|
||||
enabled:
|
||||
isDefined(localTypebot?.workspaceId) && linkedTypebotIds.length > 0,
|
||||
onError: (error) =>
|
||||
showToast({
|
||||
title: 'Error while fetching linkedTypebots',
|
||||
description: error.message,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!typebot && isDefined(localTypebot)) setLocalTypebot(undefined)
|
||||
@@ -385,7 +390,7 @@ export const TypebotProvider = ({
|
||||
value={{
|
||||
typebot: localTypebot,
|
||||
publishedTypebot,
|
||||
linkedTypebots,
|
||||
linkedTypebots: linkedTypebotsData?.typebots ?? [],
|
||||
webhooks: webhooks ?? [],
|
||||
isReadOnly,
|
||||
isSavingLoading,
|
||||
|
||||
@@ -223,6 +223,7 @@ test.describe.parallel('Theme page', () => {
|
||||
})
|
||||
await page.goto(`/typebots/${typebotId}/theme`)
|
||||
await expect(page.locator('button >> text="Go"')).toBeVisible()
|
||||
await page.getByRole('button', { name: 'Templates New!' }).click()
|
||||
await page.getByRole('button', { name: 'Save current theme' }).click()
|
||||
await page.getByPlaceholder('My template').fill('My awesome theme')
|
||||
await page.getByRole('button', { name: 'Save' }).click()
|
||||
|
||||
@@ -5,6 +5,7 @@ import { WorkspaceRole } from '@typebot.io/prisma'
|
||||
import { PublicTypebot, Typebot, typebotSchema } from '@typebot.io/schemas'
|
||||
import { omit } from '@typebot.io/lib'
|
||||
import { z } from 'zod'
|
||||
import { getUserRoleInWorkspace } from '@/features/workspace/helpers/getUserRoleInWorkspace'
|
||||
|
||||
export const listTypebots = authenticatedProcedure
|
||||
.meta({
|
||||
@@ -31,33 +32,27 @@ export const listTypebots = authenticatedProcedure
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { workspaceId, folderId }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findUnique({
|
||||
where: { id: workspaceId },
|
||||
select: { members: true },
|
||||
})
|
||||
const userRole = getUserRoleInWorkspace(user.id, workspace?.members)
|
||||
if (userRole === undefined)
|
||||
throw new TRPCError({ code: 'NOT_FOUND', message: 'Workspace not found' })
|
||||
const typebots = (await prisma.typebot.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
isArchived: { not: true },
|
||||
folderId: folderId === 'root' ? null : folderId,
|
||||
workspace: {
|
||||
id: workspaceId,
|
||||
members: {
|
||||
some: {
|
||||
userId: user.id,
|
||||
role: { not: WorkspaceRole.GUEST },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
isArchived: { not: true },
|
||||
workspace: {
|
||||
id: workspaceId,
|
||||
members: {
|
||||
some: { userId: user.id, role: WorkspaceRole.GUEST },
|
||||
},
|
||||
},
|
||||
collaborators: { some: { userId: user.id } },
|
||||
},
|
||||
],
|
||||
isArchived: { not: true },
|
||||
folderId:
|
||||
userRole === WorkspaceRole.GUEST
|
||||
? undefined
|
||||
: folderId === 'root'
|
||||
? null
|
||||
: folderId,
|
||||
workspaceId,
|
||||
collaborators:
|
||||
userRole === WorkspaceRole.GUEST
|
||||
? { some: { userId: user.id } }
|
||||
: undefined,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
select: {
|
||||
|
||||
Reference in New Issue
Block a user