2
0

📦 Upgrade packages

This commit is contained in:
Baptiste Arnaud
2022-11-02 19:45:46 +01:00
committed by GitHub
parent 48285479cc
commit 2c66c59dfc
64 changed files with 2518 additions and 3158 deletions

View File

@ -1,13 +0,0 @@
on:
pull_request:
types: [opened, edited, ready_for_review, synchronize]
jobs:
move-linked-issues:
runs-on: ubuntu-latest
name: Move linked issues to In Review column
steps:
- uses: rharter/github-move-linked-project-cards@v0.1.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
column: Reviewing 👀

View File

@ -1,41 +0,0 @@
name: Playwright Tests
on:
deployment_status:
jobs:
test-builder:
timeout-minutes: 60
runs-on: ubuntu-latest
if: ${{ github.event.deployment_status.state == 'success' && contains(github.event.deployment_status.environment, 'builder')}}
steps:
- name: Log Info
run: echo ${{ github.event.deployment_status.target_url }} && echo ${{ github.event.deployment }} && echo ${{ github.event.deployment_status.environment }}
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.2.2
- name: Install dependencies
run: pnpm i --frozen-lockfile
- name: Build dependencies
run: pnpm turbo run build --filter="builder^..."
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run tests
working-directory: ./apps/builder
run: pnpm test
env:
PLAYWRIGHT_BUILDER_TEST_BASE_URL: ${{ github.event.deployment_status.target_url }}
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
SMTP_HOST: smtp.ethereal.email
SMTP_PORT: 587
SMTP_SECURE: false
SMTP_USERNAME: tobin.tillman65@ethereal.email
SMTP_PASSWORD: Ty9BcwCBrK6w8AG2hx
STRIPE_TEST_PUBLIC_KEY: pk_test_fYwf5fyL66hiRIkFVcpStukl00K1MTPPmG
STRIPE_TEST_SECRET_KEY: ${{ secrets.STRIPE_TEST_SECRET_KEY }}
ENCRYPTION_SECRET: ${{ secrets.ENCRYPTION_SECRET }}
- name: Upload test results
if: always()
uses: actions/upload-artifact@v2
with:
name: playwright-results
path: ./apps/builder/playwright-report

View File

@ -1,4 +1,4 @@
name: Publish Docker images
name: Build Docker images
on:
create:
@ -9,32 +9,34 @@ on:
branches: [main]
jobs:
push_builder:
name: Builder
build:
runs-on: ubuntu-latest
strategy:
matrix:
app: ['builder', 'viewer']
steps:
- name: Check out the repo
uses: actions/checkout@v3
- name: Extract Builder meta
id: builder-meta
- name: Extract existing image metadata
id: ${{ matrix.app }}-meta
uses: docker/metadata-action@v4
with:
images: baptistearno/typebot-builder
images: baptistearno/typebot-${{ matrix.app }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
- if: github.event_name != 'pull_request'
name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push builder image
- name: Build image
uses: docker/build-push-action@v3
with:
context: .
@ -42,38 +44,4 @@ jobs:
tags: ${{ steps.builder-meta.outputs.tags }}
labels: ${{ steps.builder-meta.outputs.labels }}
build-args: |
SCOPE=builder
push_viewer:
name: Viewer
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v3
- name: Extract Viewer meta
id: viewer-meta
uses: docker/metadata-action@v4
with:
images: baptistearno/typebot-viewer
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push viewer image
uses: docker/build-push-action@v3
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.viewer-meta.outputs.tags }}
labels: ${{ steps.viewer-meta.outputs.labels }}
build-args: |
SCOPE=viewer
SCOPE=${{ matrix.app }}

View File

@ -1,6 +1,6 @@
import React from 'react'
import { NextChakraLink } from '../nextChakra/NextChakraLink'
import { Text } from '@chakra-ui/react'
import { TextLink } from 'components/shared/TextLink'
type Props = {
type: 'register' | 'signin'
@ -10,16 +10,11 @@ export const AuthSwitcher = ({ type }: Props) => (
{type === 'signin' ? (
<Text>
Don't have an account?{' '}
<NextChakraLink href="/register" color="blue.500" textDecor="underline">
Sign up for free
</NextChakraLink>
<TextLink href="/register">Sign up for free</TextLink>
</Text>
) : (
<Text>
Already have an account?{' '}
<NextChakraLink href="/signin" color="blue.500" textDecor="underline">
Sign in
</NextChakraLink>
Already have an account? <TextLink href="/signin">Sign in</TextLink>
</Text>
)}
</>

View File

@ -19,9 +19,9 @@ import {
import { DividerWithText } from './DividerWithText'
import { SocialLoginButtons } from './SocialLoginButtons'
import { useRouter } from 'next/router'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { BuiltInProviderType } from 'next-auth/providers'
import { useToast } from 'components/shared/hooks/useToast'
import { TextLink } from 'components/shared/TextLink'
type Props = {
defaultEmail?: string
@ -76,14 +76,12 @@ export const SignInForm = ({
return (
<Text>
You need to{' '}
<NextChakraLink
<TextLink
href="https://docs.typebot.io/self-hosting/configuration"
isExternal
color="blue.400"
textDecor="underline"
>
configure at least one auth provider
</NextChakraLink>{' '}
</TextLink>{' '}
(Email, Google, GitHub, Facebook or Azure AD).
</Text>
)

View File

@ -12,7 +12,6 @@ import {
useDisclosure,
} from '@chakra-ui/react'
import { TypebotLogo } from 'assets/logos'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import {
ChevronLeftIcon,
HardDriveIcon,
@ -27,6 +26,7 @@ import { EmojiOrImageIcon } from 'components/shared/EmojiOrImageIcon'
import { WorkspaceSettingsModal } from './WorkspaceSettingsModal'
import { isNotDefined } from 'utils'
import { PlanTag } from 'components/shared/PlanTag'
import Link from 'next/link'
export const DashboardHeader = () => {
const { user } = useUser()
@ -52,13 +52,9 @@ export const DashboardHeader = () => {
maxW="1000px"
flex="1"
>
<NextChakraLink
className="w-24"
href="/typebots"
data-testid="typebot-logo"
>
<Link href="/typebots" data-testid="typebot-logo">
<TypebotLogo w="30px" />
</NextChakraLink>
</Link>
<HStack>
{user && workspace && (
<WorkspaceSettingsModal

View File

@ -1,7 +1,7 @@
import { Button } from '@chakra-ui/react'
import { ChevronLeftIcon } from 'assets/icons'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { useTypebotDnd } from 'contexts/TypebotDndContext'
import Link from 'next/link'
import React, { useMemo } from 'react'
export const BackButton = ({ id }: { id: string | null }) => {
@ -17,7 +17,7 @@ export const BackButton = ({ id }: { id: string | null }) => {
const handleMouseLeave = () => setMouseOverFolderId(undefined)
return (
<Button
as={NextChakraLink}
as={Link}
href={id ? `/typebots/folders/${id}` : '/typebots'}
leftIcon={<ChevronLeftIcon />}
variant={'outline'}

View File

@ -1,7 +1,7 @@
import { HStack, Stack, Text } from '@chakra-ui/react'
import { StripeClimateLogo } from 'assets/logos/StripeClimateLogo'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { ChangePlanForm } from 'components/shared/ChangePlanForm'
import { TextLink } from 'components/shared/TextLink'
import { useWorkspace } from 'contexts/WorkspaceContext'
import { Plan } from 'db'
import React from 'react'
@ -33,13 +33,9 @@ export const BillingContent = () => {
<Text fontSize="xs" color="gray.500">
Typebot is contributing 1% of your subscription to remove CO from
the atmosphere.{' '}
<NextChakraLink
href="https://climate.stripe.com/5VCRAq"
isExternal
textDecor="underline"
>
<TextLink href="https://climate.stripe.com/5VCRAq" isExternal>
More info.
</NextChakraLink>
</TextLink>
</Text>
</HStack>
{workspace.plan !== Plan.CUSTOM &&

View File

@ -14,8 +14,8 @@ import {
Text,
} from '@chakra-ui/react'
import { DownloadIcon, FileIcon } from 'assets/icons'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { Workspace } from 'db'
import Link from 'next/link'
import React from 'react'
import { useInvoicesQuery } from './queries/useInvoicesQuery'
@ -54,12 +54,12 @@ export const InvoicesList = ({ workspace }: Props) => {
<Td>{getFormattedPrice(invoice.amount, invoice.currency)}</Td>
<Td>
<IconButton
as={NextChakraLink}
as={Link}
size="xs"
icon={<DownloadIcon />}
variant="outline"
href={invoice.url}
isExternal
target="_blank"
aria-label={'Download invoice'}
/>
</Td>

View File

@ -1,47 +0,0 @@
import { PropsWithChildren } from 'react'
import NextLink from 'next/link'
import { LinkProps as NextLinkProps } from 'next/dist/client/link'
import {
Link as ChakraLink,
LinkProps as ChakraLinkProps,
} from '@chakra-ui/react'
import React from 'react'
export type NextChakraLinkProps = PropsWithChildren<
NextLinkProps & Omit<ChakraLinkProps, 'href'>
>
export const NextChakraLink = React.forwardRef<
HTMLAnchorElement,
NextChakraLinkProps
>(
(
{
href,
replace,
scroll,
shallow,
prefetch,
children,
locale,
...chakraProps
},
ref
) => {
return (
<NextLink
passHref={true}
href={href}
replace={replace}
scroll={scroll}
shallow={shallow}
prefetch={prefetch}
locale={locale}
>
<ChakraLink ref={ref} {...chakraProps}>
{children}
</ChakraLink>
</NextLink>
)
}
)

View File

@ -248,10 +248,9 @@ const IndeterminateCheckbox = React.forwardRef(
const resolvedRef: any = ref || defaultRef
return (
<Flex justify="center" data-testid="checkbox">
<Flex justify="center" data-testid="checkbox" {...rest}>
<Checkbox
ref={resolvedRef}
{...rest}
isIndeterminate={indeterminate}
isChecked={checked}
/>

View File

@ -1,9 +1,9 @@
import { Stack, HStack, Text } from '@chakra-ui/react'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { useUser } from 'contexts/UserContext'
import { useWorkspace } from 'contexts/WorkspaceContext'
import { Plan } from 'db'
import { useToast } from '../hooks/useToast'
import { TextLink } from '../TextLink'
import { ProPlanContent } from './ProPlanContent'
import { pay } from './queries/updatePlan'
import { useCurrentSubscriptionInfo } from './queries/useCurrentSubscriptionInfo'
@ -89,13 +89,9 @@ export const ChangePlanForm = () => {
</HStack>
<Text color="gray.500">
Need custom limits? Specific features?{' '}
<NextChakraLink
href={'https://typebot.io/enterprise-lead-form'}
isExternal
textDecor="underline"
>
<TextLink href={'https://typebot.io/enterprise-lead-form'} isExternal>
Let's chat!
</NextChakraLink>
</TextLink>
</Text>
</Stack>
)

View File

@ -13,9 +13,9 @@ import {
Flex,
} from '@chakra-ui/react'
import { GoogleLogo } from 'assets/logos'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { Info } from 'components/shared/Info'
import { useWorkspace } from 'contexts/WorkspaceContext'
import Link from 'next/link'
import React from 'react'
import { getGoogleSheetsConsentScreenUrl } from 'services/integrations'
@ -53,7 +53,7 @@ export const GoogleSheetConnectModal = ({
/>
<Flex>
<Button
as={NextChakraLink}
as={Link}
leftIcon={<GoogleLogo />}
data-testid="google"
isLoading={['loading', 'authenticated'].includes(status)}

View File

@ -18,12 +18,11 @@ import { CredentialsType, StripeCredentialsData } from 'models'
import React, { useState } from 'react'
import { useWorkspace } from 'contexts/WorkspaceContext'
import { Input } from 'components/shared/Textbox'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { MoreInfoTooltip } from 'components/shared/MoreInfoTooltip'
import { ExternalLinkIcon } from 'assets/icons'
import { createCredentials } from 'services/credentials'
import { omit } from 'utils'
import { useToast } from 'components/shared/hooks/useToast'
import { TextLink } from 'components/shared/TextLink'
type Props = {
isOpen: boolean
@ -157,13 +156,9 @@ export const StripeConfigModal = ({
<Text>
(You can find your keys{' '}
<NextChakraLink
href="https://dashboard.stripe.com/apikeys"
isExternal
textDecor="underline"
>
here <ExternalLinkIcon />
</NextChakraLink>
<TextLink href="https://dashboard.stripe.com/apikeys" isExternal>
here
</TextLink>
)
</Text>
</Stack>

View File

@ -1,8 +1,8 @@
import { HStack, IconButton, Input } from '@chakra-ui/react'
import { ExternalLinkIcon } from 'assets/icons'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { useToast } from 'components/shared/hooks/useToast'
import { SearchableDropdown } from 'components/shared/SearchableDropdown'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
import { useTypebots } from 'services/typebots'
@ -54,7 +54,7 @@ export const TypebotsDropdown = ({
<IconButton
aria-label="Navigate to typebot"
icon={<ExternalLinkIcon />}
as={NextChakraLink}
as={Link}
href={`/typebots/${currentTypebot?.id}/edit?parentId=${query.typebotId}`}
/>
)}

View File

@ -0,0 +1,37 @@
import Link, { LinkProps } from 'next/link'
import React from 'react'
import { chakra, HStack, TextProps } from '@chakra-ui/react'
import { ExternalLinkIcon } from 'assets/icons'
type TextLinkProps = LinkProps & TextProps & { isExternal?: boolean }
export const TextLink = ({
children,
href,
shallow,
replace,
scroll,
prefetch,
isExternal,
...textProps
}: TextLinkProps) => (
<Link
href={href}
shallow={shallow}
replace={replace}
scroll={scroll}
prefetch={prefetch}
target={isExternal ? '_blank' : undefined}
>
<chakra.span textDecor="underline" display="inline-block" {...textProps}>
{isExternal ? (
<HStack spacing={1}>
<chakra.span>{children}</chakra.span>
<ExternalLinkIcon />
</HStack>
) : (
children
)}
</chakra.span>
</Link>
)

View File

@ -8,7 +8,6 @@ import {
Text,
} from '@chakra-ui/react'
import { BuoyIcon, ChevronLeftIcon, RedoIcon, UndoIcon } from 'assets/icons'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { RightPanel, useEditor } from 'contexts/EditorContext'
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
import { useRouter } from 'next/router'
@ -20,6 +19,7 @@ import { CollaborationMenuButton } from './CollaborationMenuButton'
import { EditableTypebotName } from './EditableTypebotName'
import { getBubbleActions } from 'typebot-js'
import { isCloudProdInstance } from 'services/utils'
import Link from 'next/link'
export const headerHeight = 56
@ -71,7 +71,7 @@ export const TypebotHeader = () => {
right={{ base: 280, xl: 0 }}
>
<Button
as={NextChakraLink}
as={Link}
href={`/typebots/${typebot?.id}/edit`}
colorScheme={router.pathname.includes('/edit') ? 'blue' : 'gray'}
variant={router.pathname.includes('/edit') ? 'outline' : 'ghost'}
@ -80,7 +80,7 @@ export const TypebotHeader = () => {
Flow
</Button>
<Button
as={NextChakraLink}
as={Link}
href={`/typebots/${typebot?.id}/theme`}
colorScheme={router.pathname.endsWith('theme') ? 'blue' : 'gray'}
variant={router.pathname.endsWith('theme') ? 'outline' : 'ghost'}
@ -89,7 +89,7 @@ export const TypebotHeader = () => {
Theme
</Button>
<Button
as={NextChakraLink}
as={Link}
href={`/typebots/${typebot?.id}/settings`}
colorScheme={router.pathname.endsWith('settings') ? 'blue' : 'gray'}
variant={router.pathname.endsWith('settings') ? 'outline' : 'ghost'}
@ -98,7 +98,7 @@ export const TypebotHeader = () => {
Settings
</Button>
<Button
as={NextChakraLink}
as={Link}
href={`/typebots/${typebot?.id}/share`}
colorScheme={router.pathname.endsWith('share') ? 'blue' : 'gray'}
variant={router.pathname.endsWith('share') ? 'outline' : 'ghost'}
@ -108,7 +108,7 @@ export const TypebotHeader = () => {
</Button>
{typebot?.publishedTypebotId && (
<Button
as={NextChakraLink}
as={Link}
href={`/typebots/${typebot?.id}/results`}
colorScheme={router.pathname.includes('results') ? 'blue' : 'gray'}
variant={router.pathname.includes('results') ? 'outline' : 'ghost'}
@ -127,7 +127,7 @@ export const TypebotHeader = () => {
>
<HStack alignItems="center" spacing={3}>
<IconButton
as={NextChakraLink}
as={Link}
aria-label="Navigate back"
icon={<ChevronLeftIcon fontSize={25} />}
href={

View File

@ -8,59 +8,59 @@
"start": "next start",
"lint": "next lint",
"test": "pnpm playwright test",
"test:open": "NO_RETRIES=1 pnpm playwright test --debug"
"test:report": "pnpm playwright show-report"
},
"dependencies": {
"@chakra-ui/css-reset": "2.0.8",
"@chakra-ui/react": "2.3.5",
"@codemirror/lang-css": "6.0.0",
"@codemirror/lang-html": "6.1.2",
"@codemirror/lang-javascript": "6.1.0",
"@codemirror/lang-json": "6.0.0",
"@chakra-ui/react": "2.3.6",
"@codemirror/lang-css": "6.0.1",
"@codemirror/lang-html": "6.1.3",
"@codemirror/lang-javascript": "6.1.1",
"@codemirror/lang-json": "6.0.1",
"@codemirror/lint": "6.0.0",
"@codemirror/state": "6.1.2",
"@dnd-kit/core": "6.0.5",
"@dnd-kit/sortable": "7.0.1",
"@dnd-kit/utilities": "3.2.0",
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"@emotion/react": "11.10.5",
"@emotion/styled": "11.10.5",
"@giphy/js-fetch-api": "4.4.0",
"@giphy/js-types": "4.2.1",
"@giphy/react-components": "6.2.0",
"@googleapis/drive": "3.0.1",
"@sentry/nextjs": "7.15.0",
"@stripe/stripe-js": "1.41.0",
"@tanstack/react-table": "8.5.15",
"@udecode/plate-basic-marks": "18.2.0",
"@googleapis/drive": "4.0.0",
"@sentry/nextjs": "7.17.3",
"@stripe/stripe-js": "1.42.1",
"@tanstack/react-table": "8.5.22",
"@udecode/plate-basic-marks": "18.7.0",
"@udecode/plate-common": "^7.0.2",
"@udecode/plate-core": "18.2.0",
"@udecode/plate-link": "18.2.0",
"@udecode/plate-serializer-html": "18.2.0",
"@udecode/plate-ui-link": "18.2.0",
"@udecode/plate-ui-toolbar": "18.2.0",
"aws-sdk": "2.1233.0",
"@udecode/plate-core": "18.7.0",
"@udecode/plate-link": "18.7.0",
"@udecode/plate-serializer-html": "18.7.0",
"@udecode/plate-ui-link": "18.7.0",
"@udecode/plate-ui-toolbar": "18.7.0",
"aws-sdk": "2.1245.0",
"bot-engine": "workspace:*",
"browser-image-compression": "2.0.0",
"canvas-confetti": "1.5.1",
"canvas-confetti": "1.6.0",
"codemirror": "6.0.1",
"cuid": "2.1.8",
"deep-object-diff": "1.1.7",
"dequal": "2.0.3",
"emojilib": "3.0.7",
"focus-visible": "5.2.0",
"framer-motion": "7.5.3",
"google-auth-library": "8.5.2",
"framer-motion": "7.6.4",
"google-auth-library": "8.6.0",
"google-spreadsheet": "3.3.0",
"got": "12.5.2",
"htmlparser2": "8.0.1",
"immer": "9.0.15",
"immer": "9.0.16",
"js-video-url-parser": "0.5.1",
"jsonwebtoken": "8.5.1",
"kbar": "0.1.0-beta.36",
"micro": "9.4.1",
"micro-cors": "0.1.1",
"minio": "7.0.32",
"next": "12.3.1",
"next": "13.0.1",
"next-auth": "4.12.3",
"nodemailer": "6.8.0",
"nprogress": "0.2.0",
@ -74,7 +74,7 @@
"slate-history": "0.66.0",
"slate-hyperscript": "0.77.0",
"slate-react": "0.83.2",
"stripe": "10.14.0",
"stripe": "10.15.0",
"styled-components": "5.3.6",
"svg-round-corners": "0.4.1",
"swr": "1.3.0",
@ -85,7 +85,7 @@
"@faire/mjml-react": "2.1.4"
},
"devDependencies": {
"@babel/core": "7.19.3",
"@babel/core": "7.19.6",
"@chakra-ui/styled-system": "2.3.4",
"@playwright/test": "1.27.1",
"@types/canvas-confetti": "1.4.3",
@ -93,24 +93,25 @@
"@types/jsonwebtoken": "8.5.9",
"@types/micro-cors": "0.1.2",
"@types/minio": "7.0.14",
"@types/node": "18.11.0",
"@types/node": "18.11.9",
"@types/nodemailer": "6.4.6",
"@types/nprogress": "0.2.0",
"@types/papaparse": "5.3.5",
"@types/prettier": "2.7.1",
"@types/qs": "6.9.7",
"@types/react": "18.0.21",
"@types/react": "18.0.24",
"@types/tinycolor2": "1.4.3",
"@typescript-eslint/eslint-plugin": "5.40.0",
"@typescript-eslint/parser": "5.40.0",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"db": "workspace:*",
"dotenv": "16.0.3",
"eslint": "8.25.0",
"eslint-config-next": "12.3.1",
"eslint": "8.26.0",
"eslint-config-next": "13.0.1",
"eslint-plugin-react": "7.31.10",
"models": "workspace:*",
"next-transpile-modules": "9.1.0",
"next-transpile-modules": "10.0.0",
"typescript": "4.8.4",
"utils": "workspace:*"
"utils": "workspace:*",
"configs": "workspace:*"
}
}

View File

@ -2,7 +2,6 @@ import { Seo } from 'components/Seo'
import { TypebotHeader } from 'components/shared/TypebotHeader'
import React, { useMemo } from 'react'
import { HStack, Button, Tag, Flex, Text } from '@chakra-ui/react'
import { NextChakraLink } from 'components/nextChakra/NextChakraLink'
import { ResultsContent } from 'components/results/ResultsContent'
import { useTypebot } from 'contexts/TypebotContext'
import { useWorkspace } from 'contexts/WorkspaceContext'
@ -14,6 +13,7 @@ import { ResultsProvider } from 'contexts/ResultsProvider'
import { UnlockPlanInfo } from 'components/shared/Info'
import { getChatsLimit, getStorageLimit } from 'utils'
import { useUsage } from 'components/dashboard/WorkspaceSettingsModal/BillingContent/UsageContent/useUsage'
import Link from 'next/link'
const ALERT_CHATS_PERCENT_THRESHOLD = 80
const ALERT_STORAGE_PERCENT_THRESHOLD = 80
@ -130,7 +130,7 @@ const ResultsPage = () => {
>
<HStack maxW="1600px" w="full" px="4">
<Button
as={NextChakraLink}
as={Link}
colorScheme={!isAnalytics ? 'blue' : 'gray'}
variant={!isAnalytics ? 'outline' : 'ghost'}
size="sm"
@ -144,7 +144,7 @@ const ResultsPage = () => {
)}
</Button>
<Button
as={NextChakraLink}
as={Link}
colorScheme={isAnalytics ? 'blue' : 'gray'}
variant={isAnalytics ? 'outline' : 'ghost'}
href={`/typebots/${typebot?.id}/results/analytics`}

View File

@ -1,35 +1,22 @@
import { devices, PlaywrightTestConfig } from '@playwright/test'
import { PlaywrightTestConfig } from '@playwright/test'
import path from 'path'
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config({
path: path.join(__dirname, 'playwright/.env'),
})
import { playwrightBaseConfig } from 'configs/playwright'
const config: PlaywrightTestConfig = {
globalSetup: require.resolve(path.join(__dirname, 'playwright/global-setup')),
...playwrightBaseConfig,
testDir: path.join(__dirname, 'playwright/tests'),
retries: process.env.NO_RETRIES ? 0 : 2,
workers: process.env.CI ? 1 : 3,
reporter: 'html',
maxFailures: process.env.CI ? 10 : undefined,
webServer: process.env.CI
? {
...(playwrightBaseConfig.webServer as { command: string }),
port: 3000,
}
: undefined,
use: {
actionTimeout: 0,
baseURL: process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL,
trace: 'on-first-retry',
...playwrightBaseConfig.use,
baseURL: process.env.NEXTAUTH_URL,
storageState: path.join(__dirname, 'playwright/firstUser.json'),
video: 'retain-on-failure',
locale: 'en-US',
},
outputDir: path.join(__dirname, 'playwright/test-results/'),
projects: [
{
name: 'Chrome',
use: {
...devices['Desktop Chrome'],
viewport: { width: 1400, height: 1000 },
},
},
],
}
export default config

View File

@ -119,12 +119,12 @@
"graphCoordinates": { "x": 639, "y": 142 }
},
{
"id": "q5dAhqSTCaNdiGSJm9B9Rw",
"id": "group1",
"blocks": [
{
"id": "sgtE2Sy7cKykac9B223Kq9R",
"type": "text",
"groupId": "q5dAhqSTCaNdiGSJm9B9Rw",
"groupId": "group1",
"content": {
"html": "<div>What&#x27;s your name?</div>",
"richText": [
@ -134,9 +134,9 @@
}
},
{
"id": "sqEsMo747LTDnY9FjQcEwUv",
"id": "block1",
"type": "text input",
"groupId": "q5dAhqSTCaNdiGSJm9B9Rw",
"groupId": "group1",
"options": {
"isLong": false,
"labels": {

View File

@ -1,14 +0,0 @@
import { FullConfig } from '@playwright/test'
import { setupDatabase, teardownDatabase } from 'utils/playwright/databaseSetup'
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config({ path: '.env' })
async function globalSetup(config: FullConfig) {
const { baseURL } = config.projects[0].use
if (!baseURL) throw new Error('baseURL is missing')
await teardownDatabase()
await setupDatabase()
}
export default globalSetup

View File

@ -10,7 +10,7 @@ import { proWorkspaceId } from 'utils/playwright/databaseSetup'
const prisma = new PrismaClient()
const stripe = new Stripe(process.env.STRIPE_TEST_SECRET_KEY ?? '', {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '', {
apiVersion: '2022-08-01',
})

View File

@ -21,7 +21,7 @@ test('should display user info properly', async ({ page }) => {
await expect(page.locator('img >> nth=1')).toHaveAttribute(
'src',
new RegExp(
`http://localhost:9000/typebot/public/users/${userId}/avatar`,
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
'gm'
)
)

View File

@ -1,7 +1,10 @@
import test, { expect } from '@playwright/test'
import cuid from 'cuid'
import path from 'path'
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
import {
importTypebotInDatabase,
injectFakeResults,
} from 'utils/playwright/databaseActions'
import { starterWorkspaceId } from 'utils/playwright/databaseSetup'
test('analytics are not available for non-pro workspaces', async ({ page }) => {
@ -13,6 +16,7 @@ test('analytics are not available for non-pro workspaces', async ({ page }) => {
workspaceId: starterWorkspaceId,
}
)
await injectFakeResults({ typebotId, count: 10 })
await page.goto(`/typebots/${typebotId}/results/analytics`)
const firstDropoffBox = page.locator('text="%" >> nth=0')
await firstDropoffBox.hover()

View File

@ -227,7 +227,7 @@ test('should display invoices', async ({ page }) => {
await page.click('text=Settings & Members')
await page.click('text=Billing & Usage')
await expect(page.locator('text="Invoices"')).toBeVisible()
await expect(page.locator('tr')).toHaveCount(2)
await expect(page.locator('tr')).toHaveCount(3)
await expect(page.locator('text="€39.00"')).toBeVisible()
})

View File

@ -33,7 +33,7 @@ test.describe.parallel('Image bubble block', () => {
await expect(page.locator('img')).toHaveAttribute(
'src',
new RegExp(
`http://localhost:9000/typebot/public/typebots/${typebotId}/avatar.jpg`,
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/typebots/${typebotId}/avatar.jpg`,
'gm'
)
)

View File

@ -26,19 +26,19 @@ test.describe('Payment input block', () => {
await page.fill('[placeholder="Typebot"]', 'My Stripe Account')
await page.fill(
'[placeholder="sk_test_..."]',
process.env.STRIPE_TEST_SECRET_KEY ?? ''
process.env.STRIPE_SECRET_KEY ?? ''
)
await page.fill(
'[placeholder="sk_live_..."]',
process.env.STRIPE_TEST_SECRET_KEY ?? ''
process.env.STRIPE_SECRET_KEY ?? ''
)
await page.fill(
'[placeholder="pk_test_..."]',
process.env.STRIPE_TEST_PUBLIC_KEY ?? ''
process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
)
await page.fill(
'[placeholder="pk_live_..."]',
process.env.STRIPE_TEST_PUBLIC_KEY ?? ''
process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY ?? ''
)
await expect(page.locator('button >> text="Connect"')).toBeEnabled()
await page.click('button >> text="Connect"')
@ -66,6 +66,9 @@ test.describe('Payment input block', () => {
await stripePaymentForm(page)
.locator(`[placeholder="1234 1234 1234 1234"]`)
.fill('4242424242424242')
const zipInput = stripePaymentForm(page).getByPlaceholder('90210')
const isZipInputVisible = await zipInput.isVisible()
if (isZipInputVisible) await zipInput.fill('12345')
await typebotViewer(page).locator(`text="Pay 30€"`).click()
await expect(typebotViewer(page).locator(`text="Success"`)).toBeVisible()
})

View File

@ -11,10 +11,9 @@ test.describe('Send email block', () => {
if (
!process.env.SMTP_USERNAME ||
!process.env.SMTP_PORT ||
!process.env.SMTP_SECURE ||
!process.env.SMTP_HOST ||
!process.env.SMTP_PASSWORD ||
!process.env.SMTP_FROM
!process.env.NEXT_PUBLIC_SMTP_FROM
)
throw new Error('SMTP_ env vars are missing')
await importTypebotInDatabase(
@ -29,7 +28,7 @@ test.describe('Send email block', () => {
await page.goto(`/typebots/${typebotId}/edit`)
await page.click('text=Configure...')
await page.click(`text=${process.env.SMTP_FROM}`)
await page.click(`text=notifications@typebot.io`)
await page.click('text=Connect new')
const createButton = page.locator('button >> text=Create')
await expect(createButton).toBeDisabled()
@ -44,7 +43,6 @@ test.describe('Send email block', () => {
process.env.SMTP_USERNAME
)
await page.fill('[type="password"]', process.env.SMTP_PASSWORD)
if (process.env.SMTP_SECURE === 'true') await page.click('text=Use TLS?')
await page.fill('input[role="spinbutton"]', process.env.SMTP_PORT)
await expect(createButton).toBeEnabled()
await createButton.click()

View File

@ -24,7 +24,7 @@ test.describe('Webhook block', () => {
await page.click('text=Configure...')
await page.fill(
'input[placeholder="Paste webhook URL..."]',
`${process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL}/api/mock/webhook-easy-config`
`${process.env.NEXTAUTH_URL}/api/mock/webhook-easy-config`
)
await page.click('text=Test the request')
await expect(page.locator('div[role="textbox"] >> nth=-1')).toContainText(
@ -46,7 +46,7 @@ test.describe('Webhook block', () => {
await page.click('text=Configure...')
await page.fill(
'input[placeholder="Paste webhook URL..."]',
`${process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL}/api/mock/webhook`
`${process.env.NEXTAUTH_URL}/api/mock/webhook`
)
await page.click('text=Advanced configuration')
await page.click('text=GET')

View File

@ -1,184 +1,174 @@
import test, { expect, Page } from '@playwright/test'
import cuid from 'cuid'
import { readFileSync } from 'fs'
import { defaultTextInputOptions, InputBlockType } from 'models'
import { parse } from 'papaparse'
import path from 'path'
import {
importTypebotInDatabase,
injectFakeResults,
createTypebots,
} from 'utils/playwright/databaseActions'
import { parseDefaultGroupWithBlock } from 'utils/playwright/databaseHelpers'
import { deleteButtonInConfirmDialog } from '../services/selectorUtils'
const typebotId = cuid()
test('Submission table header should be parsed correctly', async ({ page }) => {
const typebotId = cuid()
test.beforeEach(async () => {
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/results/submissionHeader.json'),
{
id: typebotId,
}
)
await page.goto(`/typebots/${typebotId}/results`)
await expect(page.locator('text=Submitted at')).toBeVisible()
await expect(page.locator('text=Welcome')).toBeVisible()
await expect(page.locator('text=Email')).toBeVisible()
await expect(page.locator('text=Name')).toBeVisible()
await expect(page.locator('text=Services')).toBeVisible()
await expect(page.locator('text=Additional information')).toBeVisible()
await expect(page.locator('text=utm_source')).toBeVisible()
await expect(page.locator('text=utm_userid')).toBeVisible()
})
test('results should be deletable', async ({ page }) => {
await createTypebots([
{
id: typebotId,
...parseDefaultGroupWithBlock({
type: InputBlockType.TEXT,
options: defaultTextInputOptions,
}),
},
])
await injectFakeResults({ typebotId, count: 200, isChronological: true })
await page.goto(`/typebots/${typebotId}/results`)
await expect(page.locator('text=content199')).toBeVisible()
await page.click('[data-testid="checkbox"] >> nth=1')
await page.click('[data-testid="checkbox"] >> nth=2')
await page.click('text="Delete"')
await deleteButtonInConfirmDialog(page).click()
await expect(page.locator('text=content199')).toBeHidden()
await expect(page.locator('text=content198')).toBeHidden()
await page.waitForTimeout(1000)
await page.click('[data-testid="checkbox"] >> nth=0')
await page.click('text="Delete"')
await deleteButtonInConfirmDialog(page).click()
await page.waitForTimeout(1000)
expect(await page.locator('tr').count()).toBe(1)
await expect(page.locator('text="Delete"')).toBeHidden()
})
test('submissions table should have infinite scroll', async ({ page }) => {
const scrollToBottom = () =>
page.evaluate(() => {
const tableWrapper = document.querySelector('.table-wrapper')
if (!tableWrapper) return
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
})
await injectFakeResults({ typebotId, count: 200, isChronological: true })
await page.goto(`/typebots/${typebotId}/results`)
await expect(page.locator('text=content199')).toBeVisible()
await expect(page.locator('text=content149')).toBeHidden()
await scrollToBottom()
await expect(page.locator('text=content149')).toBeVisible()
await expect(page.locator('text=content99')).toBeHidden()
await scrollToBottom()
await expect(page.locator('text=content99')).toBeVisible()
await expect(page.locator('text=content49')).toBeHidden()
await scrollToBottom()
await expect(page.locator('text=content49')).toBeVisible()
await expect(page.locator('text=content0')).toBeVisible()
})
test('should correctly export selection in CSV', async ({ page }) => {
await page.goto(`/typebots/${typebotId}/results`)
await expect(page.locator('text=content199')).toBeVisible()
await page.click('[data-testid="checkbox"] >> nth=1')
await page.click('[data-testid="checkbox"] >> nth=2')
const [download] = await Promise.all([
page.waitForEvent('download'),
page.locator('text="Export"').click(),
])
const path = await download.path()
expect(path).toBeDefined()
const file = readFileSync(path as string).toString()
const { data } = parse(file)
validateExportSelection(data)
await page.click('[data-testid="checkbox"] >> nth=0')
const [downloadAll] = await Promise.all([
page.waitForEvent('download'),
page.locator('text="Export"').click(),
])
const pathAll = await downloadAll.path()
expect(pathAll).toBeDefined()
const fileAll = readFileSync(pathAll as string).toString()
const { data: dataAll } = parse(fileAll)
validateExportAll(dataAll)
})
test('Can resize, hide and reorder columns', async ({ page }) => {
const typebotId = cuid()
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/results/submissionHeader.json'),
{
id: typebotId,
}
)
test('Results', async ({ page }) => {
await page.goto(`/typebots/${typebotId}/results`)
// Resize
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(200)
await page.waitForTimeout(500)
await page.dragAndDrop(
'[data-testid="resize-handle"] >> nth=3',
'[data-testid="resize-handle"] >> nth=3',
{ targetPosition: { x: 150, y: 0 }, force: true }
)
await page.waitForTimeout(500)
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(345)
await test.step('Check header format', async () => {
await expect(page.locator('text=Submitted at')).toBeVisible()
await expect(page.locator('text=Welcome')).toBeVisible()
await expect(page.locator('text=Email')).toBeVisible()
await expect(page.locator('text=Name')).toBeVisible()
await expect(page.locator('text=Services')).toBeVisible()
await expect(page.locator('text=Additional information')).toBeVisible()
await expect(page.locator('text=utm_source')).toBeVisible()
await expect(page.locator('text=utm_userid')).toBeVisible()
})
// Hide
await expect(
page.locator('[data-testid="Submitted at header"]')
).toBeVisible()
await expect(page.locator('[data-testid="Email header"]')).toBeVisible()
await page.click('button >> text="Columns"')
await page.click('[aria-label="Hide column"] >> nth=0')
await page.click('[aria-label="Hide column"] >> nth=1')
await expect(page.locator('[data-testid="Submitted at header"]')).toBeHidden()
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
await test.step('Resize columns', async () => {
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(200)
await page.waitForTimeout(500)
await page.dragAndDrop(
'[data-testid="resize-handle"] >> nth=3',
'[data-testid="resize-handle"] >> nth=3',
{ targetPosition: { x: 150, y: 0 }, force: true }
)
await page.waitForTimeout(500)
expect((await page.locator('th >> nth=4').boundingBox())?.width).toBe(345)
})
// Reorder
await expect(page.locator('th >> nth=1')).toHaveText('Welcome')
await expect(page.locator('th >> nth=2')).toHaveText('Name')
await page.dragAndDrop(
'[aria-label="Drag"] >> nth=0',
'[aria-label="Drag"] >> nth=0',
{ targetPosition: { x: 0, y: 80 }, force: true }
)
await expect(page.locator('th >> nth=1')).toHaveText('Name')
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
await test.step('Hide columns', async () => {
await expect(
page.locator('[data-testid="Submitted at header"]')
).toBeVisible()
await expect(page.locator('[data-testid="Email header"]')).toBeVisible()
await page.click('button >> text="Columns"')
await page.click('[aria-label="Hide column"] >> nth=0')
await page.click('[aria-label="Hide column"] >> nth=1')
await expect(
page.locator('[data-testid="Submitted at header"]')
).toBeHidden()
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
})
// Preferences should be persisted
const saveAndReload = async (page: Page) => {
await page.click('text="Theme"')
await page.waitForTimeout(2000)
await page.goto(`/typebots/${typebotId}/results`)
}
await saveAndReload(page)
expect((await page.locator('th >> nth=1').boundingBox())?.width).toBe(345)
await expect(page.locator('[data-testid="Submitted at header"]')).toBeHidden()
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
await expect(page.locator('th >> nth=1')).toHaveText('Name')
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
await test.step('Reorder columns', async () => {
await expect(page.locator('th >> nth=1')).toHaveText('Welcome')
await expect(page.locator('th >> nth=2')).toHaveText('Name')
await page.dragAndDrop(
'[aria-label="Drag"] >> nth=0',
'[aria-label="Drag"] >> nth=0',
{ targetPosition: { x: 0, y: 80 }, force: true }
)
await expect(page.locator('th >> nth=1')).toHaveText('Name')
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
})
await test.step('Preferences should be persisted', async () => {
await saveAndReload(page)
expect((await page.locator('th >> nth=1').boundingBox())?.width).toBe(345)
await expect(
page.locator('[data-testid="Submitted at header"]')
).toBeHidden()
await expect(page.locator('[data-testid="Email header"]')).toBeHidden()
await expect(page.locator('th >> nth=1')).toHaveText('Name')
await expect(page.locator('th >> nth=2')).toHaveText('Welcome')
})
await test.step('Infinite scroll', async () => {
await expect(page.locator('text=content199')).toBeVisible()
await expect(page.locator('text=content149')).toBeHidden()
await scrollToBottom(page)
await expect(page.locator('text=content149')).toBeVisible()
await expect(page.locator('text=content99')).toBeHidden()
await scrollToBottom(page)
await expect(page.locator('text=content99')).toBeVisible()
await expect(page.locator('text=content49')).toBeHidden()
await scrollToBottom(page)
await expect(page.locator('text=content49')).toBeVisible()
await expect(page.locator('text=content0')).toBeVisible()
})
await test.step('Export', async () => {
// For some reason, we need to double click on checkboxes to check them
await getNthCheckbox(page, 1).dblclick()
await getNthCheckbox(page, 2).dblclick()
const [download] = await Promise.all([
page.waitForEvent('download'),
page.getByRole('button', { name: 'Export 2' }).click(),
])
const path = await download.path()
expect(path).toBeDefined()
const file = readFileSync(path as string).toString()
const { data } = parse(file)
validateExportSelection(data)
await getNthCheckbox(page, 0).click()
const [downloadAll] = await Promise.all([
page.waitForEvent('download'),
page.getByRole('button', { name: 'Export 200' }).click(),
])
const pathAll = await downloadAll.path()
expect(pathAll).toBeDefined()
const fileAll = readFileSync(pathAll as string).toString()
const { data: dataAll } = parse(fileAll)
validateExportAll(dataAll)
await getNthCheckbox(page, 0).click()
})
await test.step('Delete', async () => {
await getNthCheckbox(page, 1).click()
await getNthCheckbox(page, 2).click()
await page.click('text="Delete"')
await deleteButtonInConfirmDialog(page).click()
await expect(page.locator('text=content199')).toBeHidden()
await expect(page.locator('text=content198')).toBeHidden()
await page.waitForTimeout(1000)
await page.click('[data-testid="checkbox"] >> nth=0')
await page.click('text="Delete"')
await deleteButtonInConfirmDialog(page).click()
await page.waitForTimeout(1000)
expect(await page.locator('tr').count()).toBe(1)
await expect(page.locator('text="Delete"')).toBeHidden()
})
})
const validateExportSelection = (data: unknown[]) => {
expect(data).toHaveLength(3)
expect((data[1] as unknown[])[1]).toBe('content199')
expect((data[2] as unknown[])[1]).toBe('content198')
expect((data[1] as unknown[])[3]).toBe('content199')
expect((data[2] as unknown[])[3]).toBe('content198')
}
const validateExportAll = (data: unknown[]) => {
expect(data).toHaveLength(201)
expect((data[1] as unknown[])[1]).toBe('content199')
expect((data[200] as unknown[])[1]).toBe('content0')
expect((data[1] as unknown[])[3]).toBe('content199')
expect((data[200] as unknown[])[3]).toBe('content0')
}
const scrollToBottom = (page: Page) =>
page.evaluate(() => {
const tableWrapper = document.querySelector('.table-wrapper')
if (!tableWrapper) return
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
})
const saveAndReload = async (page: Page) => {
await page.click('text="Theme"')
await page.waitForTimeout(2000)
await page.goto(`/typebots/${typebotId}/results`)
}
const getNthCheckbox = (page: Page, n: number) =>
page.getByTestId('checkbox').nth(n)

View File

@ -6,17 +6,19 @@ import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
import { freeWorkspaceId } from 'utils/playwright/databaseSetup'
import { typebotViewer } from 'utils/playwright/testHelpers'
const typebotId = cuid()
test.describe.parallel('Settings page', () => {
test.beforeAll(async () => {
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/settings.json'),
{
id: typebotId,
}
)
})
test.describe('General', () => {
test('should reflect change in real-time', async ({ page }) => {
const typebotId = cuid()
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/settings.json'),
{
id: typebotId,
}
)
await page.goto(`/typebots/${typebotId}/settings`)
await expect(
typebotViewer(page).locator('a:has-text("Made with Typebot")')
@ -134,7 +136,6 @@ test.describe.parallel('Settings page', () => {
await expect(
typebotViewer(page).locator('text="What\'s your name?"')
).toBeVisible()
await page.click('button:has-text("General")')
await expect(
page.locator('[data-testid="starter-lock-tag"]')
).toBeVisible()

View File

@ -91,7 +91,7 @@ test('can manage members', async ({ page }) => {
await page.goto('/typebots')
await page.click('text=Settings & Members')
await page.click('text="Members"')
await expect(page.locator('text="user@email.com"')).toBeVisible()
await expect(page.locator('text="user@email.com"').nth(1)).toBeVisible()
await expect(page.locator('button >> text="Invite"')).toBeEnabled()
await page.fill(
'input[placeholder="colleague@company.com"]',

View File

@ -15,14 +15,14 @@
"update-search": "docker run -it --rm --env-file=.env -e \"CONFIG=$(cat docsearch-scrapper-config.json | jq -r tostring)\" algolia/docsearch-scraper"
},
"dependencies": {
"@docusaurus/core": "2.1.0",
"@docusaurus/preset-classic": "2.1.0",
"@docusaurus/theme-search-algolia": "2.1.0",
"@docusaurus/theme-common": "2.1.0",
"@docusaurus/core": "2.2.0",
"@docusaurus/preset-classic": "2.2.0",
"@docusaurus/theme-search-algolia": "2.2.0",
"@docusaurus/theme-common": "2.2.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"@mdx-js/react": "1.6.22",
"@svgr/webpack": "6.5.0",
"@svgr/webpack": "6.5.1",
"clsx": "1.2.1",
"file-loader": "6.2.0",
"prism-react-renderer": "1.3.5",

View File

@ -36,8 +36,8 @@ export const Testimonial = (props: TestimonialProps) => {
src={image}
alt={name}
placeholder="blur"
width="80px"
height="80px"
width={80}
height={80}
className="rounded-full"
/>
<Box>

View File

@ -9,35 +9,35 @@
},
"dependencies": {
"@chakra-ui/icon": "3.0.11",
"@chakra-ui/react": "2.3.5",
"@emotion/react": "11.10.4",
"@emotion/styled": "11.10.4",
"@chakra-ui/react": "2.3.6",
"@emotion/react": "11.10.5",
"@emotion/styled": "11.10.5",
"aos": "2.3.4",
"bot-engine": "workspace:*",
"focus-visible": "5.2.0",
"framer-motion": "7.5.3",
"framer-motion": "7.6.4",
"models": "workspace:*",
"next": "12.3.1",
"next": "13.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"utils": "workspace:*",
"db": "workspace:*"
},
"devDependencies": {
"@babel/core": "7.19.3",
"@babel/core": "7.19.6",
"@chakra-ui/styled-system": "2.3.4",
"@next/bundle-analyzer": "12.3.1",
"@next/bundle-analyzer": "13.0.1",
"@types/aos": "3.0.4",
"@types/node": "18.11.0",
"@types/react": "18.0.21",
"@typescript-eslint/eslint-plugin": "5.40.0",
"@typescript-eslint/parser": "5.40.0",
"autoprefixer": "10.4.12",
"@types/node": "18.11.9",
"@types/react": "18.0.24",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"autoprefixer": "10.4.13",
"cross-env": "7.0.3",
"eslint": "8.25.0",
"eslint-config-next": "12.3.1",
"eslint": "8.26.0",
"eslint-config-next": "13.0.1",
"eslint-plugin-react": "7.31.10",
"next-transpile-modules": "9.1.0",
"next-transpile-modules": "10.0.0",
"postcss": "8.4.18",
"prettier": "2.7.1",
"typescript": "4.8.4"

View File

@ -5,27 +5,27 @@
"scripts": {
"dev": "ENVSH_ENV=.env.local bash ../../env.sh next dev -p 3001",
"build": "next build",
"start": "next start",
"start": "next start -p 3001",
"lint": "next lint",
"test": "pnpm playwright test",
"test:open": "PWDEBUG=1 pnpm playwright test"
"test:report": "pnpm playwright show-report"
},
"dependencies": {
"@sentry/nextjs": "7.15.0",
"aws-sdk": "2.1233.0",
"@sentry/nextjs": "7.17.3",
"aws-sdk": "2.1245.0",
"bot-engine": "*",
"cors": "2.8.5",
"cuid": "2.1.8",
"db": "workspace:*",
"google-spreadsheet": "3.3.0",
"got": "12.5.2",
"next": "12.3.1",
"next": "13.0.1",
"nodemailer": "6.8.0",
"qs": "6.11.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"sanitize-html": "2.7.2",
"stripe": "10.14.0"
"sanitize-html": "2.7.3",
"stripe": "10.15.0"
},
"devDependencies": {
"@babel/preset-env": "7.19.4",
@ -33,26 +33,27 @@
"@playwright/test": "1.27.1",
"@types/cors": "2.8.12",
"@types/google-spreadsheet": "3.3.0",
"@types/node": "18.11.0",
"@types/node": "18.11.9",
"@types/nodemailer": "6.4.6",
"@types/papaparse": "5.3.5",
"@types/qs": "6.9.7",
"@types/react": "18.0.21",
"@types/react": "18.0.24",
"@types/sanitize-html": "2.6.2",
"@typescript-eslint/eslint-plugin": "5.40.0",
"@typescript-eslint/parser": "5.40.0",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"dotenv": "16.0.3",
"emails": "workspace:*",
"eslint": "8.25.0",
"eslint-config-next": "12.3.1",
"eslint": "8.26.0",
"eslint-config-next": "13.0.1",
"eslint-plugin-react": "7.31.10",
"eslint-plugin-react-hooks": "4.6.0",
"google-auth-library": "8.5.2",
"google-auth-library": "8.6.0",
"models": "workspace:*",
"next-transpile-modules": "9.1.0",
"next-transpile-modules": "10.0.0",
"node-fetch": "^3.2.10",
"papaparse": "5.3.2",
"typescript": "4.8.4",
"utils": "workspace:*"
"utils": "workspace:*",
"configs": "workspace:*"
}
}

View File

@ -1,38 +1,21 @@
import { devices, PlaywrightTestConfig } from '@playwright/test'
import { PlaywrightTestConfig } from '@playwright/test'
import path from 'path'
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config({
path: path.join(__dirname, 'playwright/.env'),
})
import { playwrightBaseConfig } from 'configs/playwright'
const config: PlaywrightTestConfig = {
globalSetup: require.resolve(path.join(__dirname, 'playwright/global-setup')),
...playwrightBaseConfig,
testDir: path.join(__dirname, 'playwright/tests'),
timeout: 10 * 2000,
expect: {
timeout: 5000,
},
retries: process.env.NO_RETRIES ? 0 : 1,
workers: process.env.CI ? 1 : 3,
reporter: 'html',
maxFailures: process.env.CI ? 10 : undefined,
webServer: process.env.CI
? {
...(playwrightBaseConfig.webServer as { command: string }),
port: 3001,
}
: undefined,
use: {
actionTimeout: 0,
baseURL: process.env.VIEWER_URL,
trace: 'on-first-retry',
video: 'retain-on-failure',
locale: 'en-US',
...playwrightBaseConfig.use,
baseURL: process.env.NEXT_PUBLIC_VIEWER_URL,
},
outputDir: path.join(__dirname, 'playwright/test-results/'),
projects: [
{
name: 'Chrome',
use: {
...devices['Desktop Chrome'],
viewport: { width: 1400, height: 1000 },
},
},
],
}
export default config

View File

@ -1,4 +0,0 @@
VIEWER_URL=http://localhost:3001
BUILDER_URL=http://localhost:3000
DATABASE_URL=postgresql://postgres:typebot@localhost:5432/typebot
ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6 #256-bits secret (can be generated here: https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx)

View File

@ -1,7 +1,7 @@
import { CredentialsType, SmtpCredentialsData } from 'models'
import { PrismaClient } from 'db'
import { encrypt } from 'utils/api'
import { freeWorkspaceId } from 'utils/playwright/databaseSetup'
import { proWorkspaceId } from 'utils/playwright/databaseSetup'
const prisma = new PrismaClient()
@ -17,7 +17,7 @@ export const createSmtpCredentials = (
iv,
name: smtpData.from.email as string,
type: CredentialsType.SMTP,
workspaceId: freeWorkspaceId,
workspaceId: proWorkspaceId,
},
})
}

View File

@ -28,7 +28,7 @@ test('should work as expected', async ({ page, browser }) => {
await expect(
typebotViewer(page).locator(`text="3 files uploaded"`)
).toBeVisible()
await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text="api.json"')).toHaveAttribute(
'href',
/.+\/api\.json/
@ -52,7 +52,7 @@ test('should work as expected', async ({ page, browser }) => {
const file = readFileSync(downloadPath as string).toString()
const { data } = parse(file)
expect(data).toHaveLength(2)
expect((data[1] as unknown[])[1]).toContain('http://localhost:9000')
expect((data[1] as unknown[])[1]).toContain(process.env.S3_ENDPOINT)
const urls = (
await Promise.all(
@ -72,17 +72,7 @@ test('should work as expected', async ({ page, browser }) => {
await page.locator('button >> text="Delete" >> nth=1').click()
await expect(page.locator('text="api.json"')).toBeHidden()
await page2.goto(urls[0])
await expect(
page2.locator('span:has-text("The specified key does not exist.")')
).toBeVisible()
await page2.goto(urls[1])
await expect(
page2.locator('span:has-text("The specified key does not exist.")')
).toBeVisible()
await page2.goto(urls[2])
await expect(
page2.locator('span:has-text("The specified key does not exist.")')
).toBeVisible()
await expect(page2.locator('pre')).toBeHidden()
})
// TODO: uncomment on 1st of November
@ -124,7 +114,7 @@ test('should work as expected', async ({ page, browser }) => {
// await page.evaluate(() =>
// window.localStorage.setItem('workspaceId', 'starterWorkspace')
// )
// await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
// await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
// await expect(page.locator('text="150%"')).toBeVisible()
// await expect(page.locator('text="api.json"')).toBeHidden()
// })

View File

@ -16,7 +16,7 @@ test('should work as expected', async ({ page }) => {
await typebotViewer(page).locator('input').fill('26')
await typebotViewer(page).locator('input').press('Enter')
await typebotViewer(page).locator('button >> text=Yes').click()
await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text="Baptiste"')).toBeVisible()
await expect(page.locator('text="26"')).toBeVisible()
await expect(page.locator('text="Yes"')).toBeVisible()

View File

@ -17,10 +17,17 @@ const mockSmtpCredentials: SmtpCredentialsData = {
password: 'yXZChpPy25Qa5yBbeH',
}
test.beforeAll(async () => {
try {
const credentialsId = 'send-email-credentials'
await createSmtpCredentials(credentialsId, mockSmtpCredentials)
} catch (err) {
console.error(err)
}
})
test('should send an email', async ({ page }) => {
const typebotId = cuid()
const credentialsId = 'send-email-credentials'
await createSmtpCredentials(credentialsId, mockSmtpCredentials)
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/sendEmail.json'),
{ id: typebotId, publicId: `${typebotId}-public` }
@ -41,7 +48,7 @@ test('should send an email', async ({ page }) => {
await expect(
page.locator('text="<baptiste.arnaud95@gmail.com>" >> nth=0')
).toBeVisible()
await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await page.click('text="See logs"')
await expect(page.locator('text="Email successfully sent"')).toBeVisible()
})

View File

@ -3,18 +3,25 @@ import path from 'path'
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
import { typebotViewer } from 'utils/playwright/testHelpers'
test('should work as expected', async ({ page }) => {
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
const linkedTypebotId = 'cl0ibhv8d0130n21aw8doxhj5'
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/linkTypebots/1.json'),
{ id: typebotId, publicId: `${typebotId}-public` }
)
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/linkTypebots/2.json'),
{ id: linkedTypebotId, publicId: `${linkedTypebotId}-public` }
)
const typebotId = 'cl0ibhi7s0018n21aarlmg0cm'
const linkedTypebotId = 'cl0ibhv8d0130n21aw8doxhj5'
test.beforeAll(async () => {
try {
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/linkTypebots/1.json'),
{ id: typebotId, publicId: `${typebotId}-public` }
)
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/linkTypebots/2.json'),
{ id: linkedTypebotId, publicId: `${linkedTypebotId}-public` }
)
} catch (err) {
console.error(err)
}
})
test('should work as expected', async ({ page }) => {
await page.goto(`/${typebotId}-public`)
await typebotViewer(page).locator('input').fill('Hello there!')
await Promise.all([
@ -26,6 +33,6 @@ test('should work as expected', async ({ page }) => {
),
typebotViewer(page).locator('input').press('Enter'),
])
await page.goto(`${process.env.BUILDER_URL}/typebots/${typebotId}/results`)
await page.goto(`${process.env.NEXTAUTH_URL}/typebots/${typebotId}/results`)
await expect(page.locator('text=Hello there!')).toBeVisible()
})

View File

@ -4,12 +4,15 @@ import path from 'path'
import { HttpMethod } from 'models'
import {
createWebhook,
deleteTypebots,
deleteWebhooks,
importTypebotInDatabase,
} from 'utils/playwright/databaseActions'
import { typebotViewer } from 'utils/playwright/testHelpers'
test('should execute webhooks properly', async ({ page }) => {
const typebotId = cuid()
const typebotId = cuid()
test.beforeEach(async () => {
await importTypebotInDatabase(
path.join(__dirname, '../fixtures/typebots/webhook.json'),
{ id: typebotId, publicId: `${typebotId}-public` }
@ -38,7 +41,18 @@ test('should execute webhooks properly', async ({ page }) => {
method: HttpMethod.POST,
body: `{{Full body}}`,
})
})
test.afterEach(async () => {
await deleteTypebots([typebotId])
await deleteWebhooks([
'failing-webhook',
'partial-body-webhook',
'full-body-webhook',
])
})
test('should execute webhooks properly', async ({ page }) => {
await page.goto(`/${typebotId}-public`)
await typebotViewer(page).locator('text=Send failing webhook').click()
await typebotViewer(page)

View File

@ -1,5 +1,5 @@
{
"version": "2.8.2",
"version": "2.8.3",
"name": "typebot-os",
"private": true,
"license": "AGPL-3.0-or-later",
@ -12,23 +12,24 @@
"docker:nuke": "docker compose -f docker-compose.dev.yml down --volumes --remove-orphans",
"dev": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=false turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
"dev:mocking": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
"build": "pnpm docker:up && turbo run build",
"build:builder": "turbo run build --filter=builder... && ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash env.sh",
"build:viewer": "turbo run build --filter=viewer... && ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash env.sh",
"build": "pnpm docker:up && TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build",
"build:builder": "TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build --filter=builder... && ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash env.sh",
"build:viewer": "TURBO_CI_VENDOR_ENV_KEY=NEXT_PUBLIC_ turbo run build --filter=viewer... && ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash env.sh",
"build:landing-page": "turbo run build --filter=landing-page... && ENVSH_ENV=./apps/landing-page/.env.docker ENVSH_OUTPUT=./apps/landing-page/public/__env.js bash env.sh",
"test:builder": "cd apps/builder && pnpm test",
"lint": "turbo run lint",
"test:viewer": "cd apps/viewer && pnpm test",
"db:migrate": "cd packages/db && pnpm migration:deploy",
"build:ci": "turbo run build --filter=builder... --filter=viewer... && ENVSH_ENV=./apps/builder/.env.docker ENVSH_OUTPUT=./apps/builder/public/__env.js bash env.sh && ENVSH_ENV=./apps/viewer/.env.docker ENVSH_OUTPUT=./apps/viewer/public/__env.js bash env.sh",
"generate-change-log": "pnpx gitmoji-changelog"
},
"devDependencies": {
"cz-emoji": "1.3.2-canary.2",
"turbo": "1.5.6"
"turbo": "1.6.3"
},
"config": {
"commitizen": {
"path": "node_modules/cz-emoji"
}
},
"packageManager": "pnpm@7.12.2"
"packageManager": "pnpm@7.14.0"
}

View File

@ -11,30 +11,30 @@
"lint": "eslint --fix -c ./.eslintrc.js \"./src/**/*.ts*\""
},
"dependencies": {
"@stripe/react-stripe-js": "1.13.0",
"@stripe/stripe-js": "1.41.0",
"@stripe/react-stripe-js": "1.14.1",
"@stripe/stripe-js": "1.42.1",
"prop-types": "15.8.1",
"qs": "6.11.0",
"react-frame-component": "5.2.3",
"react-phone-number-input": "3.2.11",
"react-scroll": "1.8.7",
"react-phone-number-input": "3.2.12",
"react-scroll": "1.8.8",
"react-transition-group": "4.4.5",
"resize-observer": "1.0.4"
},
"devDependencies": {
"@types/node": "18.11.0",
"@types/node": "18.11.9",
"@types/qs": "6.9.7",
"@types/react": "18.0.21",
"@types/react": "18.0.24",
"@types/react-phone-number-input": "3.0.14",
"@types/react-scroll": "1.8.4",
"@types/react-transition-group": "4.4.5",
"@typescript-eslint/eslint-plugin": "5.40.0",
"@typescript-eslint/parser": "5.40.0",
"autoprefixer": "10.4.12",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"autoprefixer": "10.4.13",
"baptistearno-tsup": "^0.1.0",
"db": "workspace:*",
"eslint": "8.25.0",
"eslint-config-next": "12.3.1",
"eslint": "8.26.0",
"eslint-config-next": "13.0.1",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-react": "7.31.10",
@ -43,7 +43,7 @@
"prettier": "2.7.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.1.8",
"tailwindcss": "3.2.1",
"typescript": "4.8.4",
"utils": "workspace:*"
},

View File

@ -35,7 +35,7 @@ export const InputChatBlock = ({
) => void
onSkip: () => void
}) => {
const { typebot } = useTypebot()
const { typebot, isLoading } = useTypebot()
const { addAnswer } = useAnswers()
const [answer, setAnswer] = useState<string>()
const [isEditting, setIsEditting] = useState(false)
@ -66,6 +66,8 @@ export const InputChatBlock = ({
setIsEditting(true)
}
if (isLoading) return null
if (answer) {
const avatarUrl = typebot.theme.chat.guestAvatar?.url
return (

View File

@ -0,0 +1,14 @@
{
"name": "configs",
"version": "1.0.0",
"main": "./index.ts",
"types": "./index.ts",
"license": "AGPL-3.0-or-later",
"private": true,
"devDependencies": {
"@playwright/test": "1.27.1",
"@types/node": "18.11.9",
"dotenv": "16.0.3",
"utils": "workspace:*"
}
}

View File

@ -0,0 +1,47 @@
import { PlaywrightTestConfig } from '@playwright/test'
import path from 'path'
import fs from 'fs'
const builderLocalEnvPath = path.join(
__dirname,
'../../../apps/builder/.env.local'
)
const localViewerEnvPath = path.join(
__dirname,
'../../../apps/viewer/.env.local'
)
if (fs.existsSync(builderLocalEnvPath))
require('dotenv').config({
path: builderLocalEnvPath,
})
if (fs.existsSync(localViewerEnvPath))
require('dotenv').config({
path: localViewerEnvPath,
})
export const playwrightBaseConfig: PlaywrightTestConfig = {
globalSetup: require.resolve(path.join(__dirname, 'globalSetup')),
timeout: process.env.CI ? 50 * 1000 : 20 * 1000,
expect: {
timeout: process.env.CI ? 10 * 1000 : 5 * 1000,
},
retries: process.env.NO_RETRIES ? 0 : 1,
workers: process.env.CI ? 2 : 3,
reporter: [[process.env.CI ? 'github' : 'list'], ['html']],
maxFailures: process.env.CI ? 10 : undefined,
webServer: process.env.CI
? {
command: 'pnpm run start',
timeout: 60_000,
reuseExistingServer: true,
}
: undefined,
use: {
trace: 'on-first-retry',
video: 'retain-on-failure',
locale: 'en-US',
browserName: 'chromium',
viewport: { width: 1400, height: 1000 },
},
}

View File

@ -0,0 +1 @@
export { playwrightBaseConfig } from './baseConfig'

View File

@ -0,0 +1,6 @@
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true
}
}

View File

@ -5,7 +5,7 @@
"main": "./index.ts",
"types": "./index.ts",
"scripts": {
"dev": "dotenv -e ../../apps/builder/.env.local prisma db push && pnpm generate:schema && pnpm start:sutdio ",
"dev": "dotenv -e ../../apps/builder/.env.local prisma db push && pnpm generate:schema",
"build": "pnpm generate:schema",
"start:sutdio": "dotenv -e ../../apps/builder/.env.local -v BROWSER=none prisma studio",
"generate:schema": "dotenv -e ../../apps/builder/.env.local prisma generate",
@ -16,10 +16,10 @@
"migration:deploy": "prisma migrate deploy"
},
"dependencies": {
"@prisma/client": "4.4.0"
"@prisma/client": "4.5.0"
},
"devDependencies": {
"prisma": "4.4.0",
"prisma": "4.5.0",
"typescript": "4.8.4",
"dotenv-cli": "6.0.0"
}

View File

@ -14,15 +14,15 @@
"license": "ISC",
"devDependencies": {
"@faire/mjml-react": "2.1.4",
"@types/node": "18.11.0",
"@types/node": "18.11.9",
"@types/nodemailer": "6.4.6",
"@types/react": "18.0.21",
"concurrently": "7.4.0",
"@types/react": "18.0.24",
"concurrently": "7.5.0",
"http-server": "14.1.1",
"nodemailer": "6.8.0",
"react": "18.2.0",
"serve": "14.0.1",
"tsx": "3.10.1",
"tsx": "3.11.0",
"utils": "workspace:*"
},
"peerDependencies": {

View File

@ -10,7 +10,7 @@
},
"devDependencies": {
"typescript": "4.8.4",
"next": "12.3.1",
"next": "13.0.1",
"db": "workspace:*"
},
"peerDependencies": {

View File

@ -5,17 +5,19 @@
"license": "AGPL-3.0-or-later",
"private": true,
"scripts": {
"start:local": "ts-node index.ts",
"start:staging": "NODE_ENV=staging ts-node index.ts",
"start:prod": "NODE_ENV=production ts-node index.ts"
"start:local": "tsx index.ts",
"start:staging": "NODE_ENV=staging tsx index.ts",
"start:prod": "NODE_ENV=production tsx index.ts"
},
"devDependencies": {
"@types/node": "18.11.0",
"@types/node": "18.11.9",
"axios": "^1.1.3",
"db": "workspace:*",
"emails": "workspace:*",
"got": "12.5.2",
"models": "workspace:*",
"ts-node": "10.9.1",
"tsx": "3.11.0",
"typescript": "4.8.4",
"utils": "workspace:*",
"emails": "workspace:*"
"utils": "workspace:*"
}
}

View File

@ -11,16 +11,16 @@
"test": "pnpm jest"
},
"devDependencies": {
"@types/jest": "29.1.2",
"@typescript-eslint/eslint-plugin": "5.40.0",
"@typescript-eslint/parser": "5.40.0",
"@types/jest": "29.2.1",
"@typescript-eslint/eslint-plugin": "5.42.0",
"@typescript-eslint/parser": "5.42.0",
"baptistearno-tsup": "^0.1.0",
"eslint": "8.25.0",
"eslint": "8.26.0",
"eslint-plugin-functional": "4.4.1",
"eslint-plugin-jest": "27.1.2",
"eslint-plugin-jest": "27.1.3",
"eslint-plugin-prettier": "4.2.1",
"jest": "29.2.0",
"jest-environment-jsdom": "29.2.0",
"jest": "29.2.2",
"jest-environment-jsdom": "29.2.2",
"prettier": "2.7.1",
"ts-jest": "29.0.3",
"typescript": "4.8.4"

View File

@ -8,11 +8,11 @@
"devDependencies": {
"@playwright/test": "1.27.1",
"@types/nodemailer": "6.4.6",
"aws-sdk": "2.1233.0",
"aws-sdk": "2.1245.0",
"cuid": "2.1.8",
"db": "workspace:*",
"models": "workspace:*",
"next": "12.3.1",
"next": "13.0.1",
"nodemailer": "6.8.0",
"typescript": "4.8.4"
},

View File

@ -62,7 +62,7 @@ const createAnswers = ({
resultId: `${resultIdPrefix}-result${idx}`,
content: `content${idx}`,
blockId: 'block1',
groupId: 'block1',
groupId: 'group1',
storageUsed: fakeStorage ? Math.round(fakeStorage / count) : null,
})),
],
@ -95,6 +95,24 @@ export const deleteWorkspaces = async (workspaceIds: string[]) => {
})
}
export const deleteTypebots = async (typebotIds: string[]) => {
await prisma.typebot.deleteMany({
where: { id: { in: typebotIds } },
})
}
export const deleteCredentials = async (credentialIds: string[]) => {
await prisma.credentials.deleteMany({
where: { id: { in: credentialIds } },
})
}
export const deleteWebhooks = async (webhookIds: string[]) => {
await prisma.webhook.deleteMany({
where: { id: { in: webhookIds } },
})
}
export const createWorkspaces = async (workspaces: Partial<Workspace>[]) => {
const workspaceIds = workspaces.map((workspace) => workspace.id ?? cuid())
await prisma.workspace.createMany({

View File

@ -6,7 +6,7 @@
"author": "baptisteArno",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@prettier/plugin-php": "0.19.1",
"@prettier/plugin-php": "0.19.2",
"prettier": "2.7.1"
},
"scripts": {

4496
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
#!/bin/bash
echo "VERCEL_GIT_COMMIT_REF: $VERCEL_GIT_COMMIT_REF"
if [[ "$VERCEL_GIT_COMMIT_REF" == "dev" || "$VERCEL_GIT_COMMIT_REF" == "main" ]] ; then
echo "✅ - Build can proceed"
exit 1;
else
echo "🛑 - Build cancelled"
exit 0;
fi

View File

@ -9,15 +9,9 @@
"db#build": {
"cache": false
},
"test": {
"dependsOn": [],
"outputs": []
},
"lint": {
"outputs": []
},
"dev": {
"dependsOn": ["^dev"]
"dependsOn": ["^dev"],
"cache": false
}
}
}