@ -52,7 +52,7 @@ export const MyAccountForm = () => {
|
|||||||
<Stack>
|
<Stack>
|
||||||
<UploadButton
|
<UploadButton
|
||||||
size="sm"
|
size="sm"
|
||||||
filePath={`public/users/${user?.id}/avatar`}
|
filePath={`users/${user?.id}/avatar`}
|
||||||
leftIcon={<UploadIcon />}
|
leftIcon={<UploadIcon />}
|
||||||
onFileUploaded={handleFileUploaded}
|
onFileUploaded={handleFileUploaded}
|
||||||
>
|
>
|
||||||
|
@ -37,11 +37,14 @@ export const WorkspaceSettingsForm = ({ onClose }: { onClose: () => void }) => {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<FormLabel>Icon</FormLabel>
|
<FormLabel>Icon</FormLabel>
|
||||||
<Flex>
|
<Flex>
|
||||||
<EditableEmojiOrImageIcon
|
{workspace && (
|
||||||
icon={workspace?.icon}
|
<EditableEmojiOrImageIcon
|
||||||
onChangeIcon={handleChangeIcon}
|
uploadFilePath={`workspaces/${workspace.id}/icon`}
|
||||||
boxSize="40px"
|
icon={workspace.icon}
|
||||||
/>
|
onChangeIcon={handleChangeIcon}
|
||||||
|
boxSize="40px"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
@ -16,12 +16,14 @@ import { CodeEditor } from 'components/shared/CodeEditor'
|
|||||||
import { MoreInfoTooltip } from 'components/shared/MoreInfoTooltip'
|
import { MoreInfoTooltip } from 'components/shared/MoreInfoTooltip'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
typebotId: string
|
||||||
typebotName: string
|
typebotName: string
|
||||||
metadata: Metadata
|
metadata: Metadata
|
||||||
onMetadataChange: (metadata: Metadata) => void
|
onMetadataChange: (metadata: Metadata) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MetadataForm = ({
|
export const MetadataForm = ({
|
||||||
|
typebotId,
|
||||||
typebotName,
|
typebotName,
|
||||||
metadata,
|
metadata,
|
||||||
onMetadataChange,
|
onMetadataChange,
|
||||||
@ -57,7 +59,8 @@ export const MetadataForm = ({
|
|||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent p="4">
|
<PopoverContent p="4">
|
||||||
<ImageUploadContent
|
<ImageUploadContent
|
||||||
url={metadata.favIconUrl ?? ''}
|
filePath={`typebots/${typebotId}/favIcon`}
|
||||||
|
defaultUrl={metadata.favIconUrl ?? ''}
|
||||||
onSubmit={handleFavIconSubmit}
|
onSubmit={handleFavIconSubmit}
|
||||||
isGiphyEnabled={false}
|
isGiphyEnabled={false}
|
||||||
/>
|
/>
|
||||||
@ -81,7 +84,8 @@ export const MetadataForm = ({
|
|||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent p="4">
|
<PopoverContent p="4">
|
||||||
<ImageUploadContent
|
<ImageUploadContent
|
||||||
url={metadata.imageUrl}
|
filePath={`typebots/${typebotId}/ogImage`}
|
||||||
|
defaultUrl={metadata.imageUrl}
|
||||||
onSubmit={handleImageSubmit}
|
onSubmit={handleImageSubmit}
|
||||||
isGiphyEnabled={false}
|
isGiphyEnabled={false}
|
||||||
/>
|
/>
|
||||||
|
@ -90,6 +90,7 @@ export const SettingsSideMenu = () => {
|
|||||||
<AccordionPanel pb={4} px="6">
|
<AccordionPanel pb={4} px="6">
|
||||||
{typebot && (
|
{typebot && (
|
||||||
<MetadataForm
|
<MetadataForm
|
||||||
|
typebotId={typebot.id}
|
||||||
typebotName={typebot.name}
|
typebotName={typebot.name}
|
||||||
metadata={typebot.settings.metadata}
|
metadata={typebot.settings.metadata}
|
||||||
onMetadataChange={handleMetadataChange}
|
onMetadataChange={handleMetadataChange}
|
||||||
|
@ -11,12 +11,14 @@ import { EmojiOrImageIcon } from './EmojiOrImageIcon'
|
|||||||
import { ImageUploadContent } from './ImageUploadContent'
|
import { ImageUploadContent } from './ImageUploadContent'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
uploadFilePath: string
|
||||||
icon?: string | null
|
icon?: string | null
|
||||||
onChangeIcon: (icon: string) => void
|
onChangeIcon: (icon: string) => void
|
||||||
boxSize?: string
|
boxSize?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditableEmojiOrImageIcon = ({
|
export const EditableEmojiOrImageIcon = ({
|
||||||
|
uploadFilePath,
|
||||||
icon,
|
icon,
|
||||||
onChangeIcon,
|
onChangeIcon,
|
||||||
boxSize,
|
boxSize,
|
||||||
@ -47,7 +49,8 @@ export const EditableEmojiOrImageIcon = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<PopoverContent p="2">
|
<PopoverContent p="2">
|
||||||
<ImageUploadContent
|
<ImageUploadContent
|
||||||
url={icon ?? ''}
|
filePath={uploadFilePath}
|
||||||
|
defaultUrl={icon ?? ''}
|
||||||
onSubmit={onChangeIcon}
|
onSubmit={onChangeIcon}
|
||||||
isGiphyEnabled={false}
|
isGiphyEnabled={false}
|
||||||
isEmojiEnabled={true}
|
isEmojiEnabled={true}
|
||||||
|
@ -55,7 +55,7 @@ export const BlockNode = ({
|
|||||||
setFocusedGroupId,
|
setFocusedGroupId,
|
||||||
previewingEdge,
|
previewingEdge,
|
||||||
} = useGraph()
|
} = useGraph()
|
||||||
const { updateBlock } = useTypebot()
|
const { typebot, updateBlock } = useTypebot()
|
||||||
const [isConnecting, setIsConnecting] = useState(false)
|
const [isConnecting, setIsConnecting] = useState(false)
|
||||||
const [isPopoverOpened, setIsPopoverOpened] = useState(
|
const [isPopoverOpened, setIsPopoverOpened] = useState(
|
||||||
openedBlockId === block.id
|
openedBlockId === block.id
|
||||||
@ -227,8 +227,9 @@ export const BlockNode = ({
|
|||||||
</SettingsModal>
|
</SettingsModal>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isMediaBubbleBlock(block) && (
|
{typebot && isMediaBubbleBlock(block) && (
|
||||||
<MediaBubblePopoverContent
|
<MediaBubblePopoverContent
|
||||||
|
typebotId={typebot.id}
|
||||||
block={block}
|
block={block}
|
||||||
onContentChange={handleContentChange}
|
onContentChange={handleContentChange}
|
||||||
/>
|
/>
|
||||||
|
@ -16,6 +16,7 @@ import { EmbedUploadContent } from './EmbedUploadContent'
|
|||||||
import { VideoUploadContent } from './VideoUploadContent'
|
import { VideoUploadContent } from './VideoUploadContent'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
typebotId: string
|
||||||
block: Exclude<BubbleBlock, TextBubbleBlock>
|
block: Exclude<BubbleBlock, TextBubbleBlock>
|
||||||
onContentChange: (content: BubbleBlockContent) => void
|
onContentChange: (content: BubbleBlockContent) => void
|
||||||
}
|
}
|
||||||
@ -39,14 +40,19 @@ export const MediaBubblePopoverContent = (props: Props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MediaBubbleContent = ({ block, onContentChange }: Props) => {
|
export const MediaBubbleContent = ({
|
||||||
|
typebotId,
|
||||||
|
block,
|
||||||
|
onContentChange,
|
||||||
|
}: Props) => {
|
||||||
const handleImageUrlChange = (url: string) => onContentChange({ url })
|
const handleImageUrlChange = (url: string) => onContentChange({ url })
|
||||||
|
|
||||||
switch (block.type) {
|
switch (block.type) {
|
||||||
case BubbleBlockType.IMAGE: {
|
case BubbleBlockType.IMAGE: {
|
||||||
return (
|
return (
|
||||||
<ImageUploadContent
|
<ImageUploadContent
|
||||||
url={block.content?.url}
|
filePath={`typebots/${typebotId}/blocks/${block.id}`}
|
||||||
|
defaultUrl={block.content?.url}
|
||||||
onSubmit={handleImageUrlChange}
|
onSubmit={handleImageUrlChange}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -2,12 +2,13 @@ import { useState } from 'react'
|
|||||||
import { Button, Flex, HStack, Stack } from '@chakra-ui/react'
|
import { Button, Flex, HStack, Stack } from '@chakra-ui/react'
|
||||||
import { UploadButton } from '../buttons/UploadButton'
|
import { UploadButton } from '../buttons/UploadButton'
|
||||||
import { GiphySearchForm } from './GiphySearchForm'
|
import { GiphySearchForm } from './GiphySearchForm'
|
||||||
import { useTypebot } from 'contexts/TypebotContext'
|
|
||||||
import { Input } from '../Textbox/Input'
|
import { Input } from '../Textbox/Input'
|
||||||
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
import { EmojiSearchableList } from './emoji/EmojiSearchableList'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url?: string
|
filePath: string
|
||||||
|
includeFileName?: boolean
|
||||||
|
defaultUrl?: string
|
||||||
isEmojiEnabled?: boolean
|
isEmojiEnabled?: boolean
|
||||||
isGiphyEnabled?: boolean
|
isGiphyEnabled?: boolean
|
||||||
onSubmit: (url: string) => void
|
onSubmit: (url: string) => void
|
||||||
@ -15,7 +16,9 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ImageUploadContent = ({
|
export const ImageUploadContent = ({
|
||||||
url,
|
filePath,
|
||||||
|
includeFileName,
|
||||||
|
defaultUrl,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
isEmojiEnabled = false,
|
isEmojiEnabled = false,
|
||||||
isGiphyEnabled = true,
|
isGiphyEnabled = true,
|
||||||
@ -67,25 +70,41 @@ export const ImageUploadContent = ({
|
|||||||
)}
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
<BodyContent tab={currentTab} onSubmit={handleSubmit} url={url} />
|
<BodyContent
|
||||||
|
filePath={filePath}
|
||||||
|
includeFileName={includeFileName}
|
||||||
|
tab={currentTab}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
defaultUrl={defaultUrl}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const BodyContent = ({
|
const BodyContent = ({
|
||||||
|
includeFileName,
|
||||||
|
filePath,
|
||||||
tab,
|
tab,
|
||||||
url,
|
defaultUrl,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
}: {
|
}: {
|
||||||
|
includeFileName?: boolean
|
||||||
|
filePath: string
|
||||||
tab: 'upload' | 'link' | 'giphy' | 'emoji'
|
tab: 'upload' | 'link' | 'giphy' | 'emoji'
|
||||||
url?: string
|
defaultUrl?: string
|
||||||
onSubmit: (url: string) => void
|
onSubmit: (url: string) => void
|
||||||
}) => {
|
}) => {
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'upload':
|
case 'upload':
|
||||||
return <UploadFileContent onNewUrl={onSubmit} />
|
return (
|
||||||
|
<UploadFileContent
|
||||||
|
filePath={filePath}
|
||||||
|
includeFileName={includeFileName}
|
||||||
|
onNewUrl={onSubmit}
|
||||||
|
/>
|
||||||
|
)
|
||||||
case 'link':
|
case 'link':
|
||||||
return <EmbedLinkContent initialUrl={url} onNewUrl={onSubmit} />
|
return <EmbedLinkContent defaultUrl={defaultUrl} onNewUrl={onSubmit} />
|
||||||
case 'giphy':
|
case 'giphy':
|
||||||
return <GiphyContent onNewUrl={onSubmit} />
|
return <GiphyContent onNewUrl={onSubmit} />
|
||||||
case 'emoji':
|
case 'emoji':
|
||||||
@ -93,30 +112,34 @@ const BodyContent = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContentProps = { initialUrl?: string; onNewUrl: (url: string) => void }
|
type ContentProps = { onNewUrl: (url: string) => void }
|
||||||
|
|
||||||
const UploadFileContent = ({ onNewUrl }: ContentProps) => {
|
const UploadFileContent = ({
|
||||||
const { typebot } = useTypebot()
|
filePath,
|
||||||
return (
|
includeFileName,
|
||||||
<Flex justify="center" py="2">
|
onNewUrl,
|
||||||
<UploadButton
|
}: ContentProps & { filePath: string; includeFileName?: boolean }) => (
|
||||||
filePath={`public/typebots/${typebot?.id}`}
|
<Flex justify="center" py="2">
|
||||||
onFileUploaded={onNewUrl}
|
<UploadButton
|
||||||
includeFileName
|
filePath={filePath}
|
||||||
colorScheme="blue"
|
onFileUploaded={onNewUrl}
|
||||||
>
|
includeFileName={includeFileName}
|
||||||
Choose an image
|
colorScheme="blue"
|
||||||
</UploadButton>
|
>
|
||||||
</Flex>
|
Choose an image
|
||||||
)
|
</UploadButton>
|
||||||
}
|
</Flex>
|
||||||
|
)
|
||||||
|
|
||||||
const EmbedLinkContent = ({ initialUrl, onNewUrl }: ContentProps) => (
|
const EmbedLinkContent = ({
|
||||||
|
defaultUrl,
|
||||||
|
onNewUrl,
|
||||||
|
}: ContentProps & { defaultUrl?: string }) => (
|
||||||
<Stack py="2">
|
<Stack py="2">
|
||||||
<Input
|
<Input
|
||||||
placeholder={'Paste the image link...'}
|
placeholder={'Paste the image link...'}
|
||||||
onChange={onNewUrl}
|
onChange={onNewUrl}
|
||||||
defaultValue={initialUrl ?? ''}
|
defaultValue={defaultUrl ?? ''}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
)
|
)
|
||||||
|
@ -140,10 +140,13 @@ export const TypebotHeader = () => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
<HStack spacing={1}>
|
<HStack spacing={1}>
|
||||||
<EditableEmojiOrImageIcon
|
{typebot && (
|
||||||
icon={typebot?.icon}
|
<EditableEmojiOrImageIcon
|
||||||
onChangeIcon={handleChangeIcon}
|
uploadFilePath={`typebots/${typebot.id}/icon`}
|
||||||
/>
|
icon={typebot?.icon}
|
||||||
|
onChangeIcon={handleChangeIcon}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{typebot?.name && (
|
{typebot?.name && (
|
||||||
<EditableTypebotName
|
<EditableTypebotName
|
||||||
name={typebot?.name}
|
name={typebot?.name}
|
||||||
|
@ -25,7 +25,7 @@ export const UploadButton = ({
|
|||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
file: await compressFile(file),
|
file: await compressFile(file),
|
||||||
path: filePath + (includeFileName ? `/${file.name}` : ''),
|
path: `public/${filePath}${includeFileName ? `/${file.name}` : ''}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
@ -17,6 +17,7 @@ import { ImageUploadContent } from 'components/shared/ImageUploadContent'
|
|||||||
import { DefaultAvatar } from 'assets/DefaultAvatar'
|
import { DefaultAvatar } from 'assets/DefaultAvatar'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
uploadFilePath: string
|
||||||
title: string
|
title: string
|
||||||
avatarProps?: AvatarProps
|
avatarProps?: AvatarProps
|
||||||
isDefaultCheck?: boolean
|
isDefaultCheck?: boolean
|
||||||
@ -24,6 +25,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const AvatarForm = ({
|
export const AvatarForm = ({
|
||||||
|
uploadFilePath,
|
||||||
title,
|
title,
|
||||||
avatarProps,
|
avatarProps,
|
||||||
isDefaultCheck = false,
|
isDefaultCheck = false,
|
||||||
@ -71,7 +73,8 @@ export const AvatarForm = ({
|
|||||||
<Portal>
|
<Portal>
|
||||||
<PopoverContent p="4">
|
<PopoverContent p="4">
|
||||||
<ImageUploadContent
|
<ImageUploadContent
|
||||||
url={avatarProps?.url}
|
filePath={uploadFilePath}
|
||||||
|
defaultUrl={avatarProps?.url}
|
||||||
onSubmit={handleImageUrl}
|
onSubmit={handleImageUrl}
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
|
@ -8,11 +8,16 @@ import { HostBubbles } from './HostBubbles'
|
|||||||
import { InputsTheme } from './InputsTheme'
|
import { InputsTheme } from './InputsTheme'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
typebotId: string
|
||||||
chatTheme: ChatTheme
|
chatTheme: ChatTheme
|
||||||
onChatThemeChange: (chatTheme: ChatTheme) => void
|
onChatThemeChange: (chatTheme: ChatTheme) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatThemeSettings = ({ chatTheme, onChatThemeChange }: Props) => {
|
export const ChatThemeSettings = ({
|
||||||
|
typebotId,
|
||||||
|
chatTheme,
|
||||||
|
onChatThemeChange,
|
||||||
|
}: Props) => {
|
||||||
const handleHostBubblesChange = (hostBubbles: ContainerColors) =>
|
const handleHostBubblesChange = (hostBubbles: ContainerColors) =>
|
||||||
onChatThemeChange({ ...chatTheme, hostBubbles })
|
onChatThemeChange({ ...chatTheme, hostBubbles })
|
||||||
const handleGuestBubblesChange = (guestBubbles: ContainerColors) =>
|
const handleGuestBubblesChange = (guestBubbles: ContainerColors) =>
|
||||||
@ -30,12 +35,14 @@ export const ChatThemeSettings = ({ chatTheme, onChatThemeChange }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Stack spacing={6}>
|
<Stack spacing={6}>
|
||||||
<AvatarForm
|
<AvatarForm
|
||||||
|
uploadFilePath={`typebots/${typebotId}/hostAvatar`}
|
||||||
title="Bot avatar"
|
title="Bot avatar"
|
||||||
avatarProps={chatTheme.hostAvatar}
|
avatarProps={chatTheme.hostAvatar}
|
||||||
isDefaultCheck
|
isDefaultCheck
|
||||||
onAvatarChange={handleHostAvatarChange}
|
onAvatarChange={handleHostAvatarChange}
|
||||||
/>
|
/>
|
||||||
<AvatarForm
|
<AvatarForm
|
||||||
|
uploadFilePath={`typebots/${typebotId}/guestAvatar`}
|
||||||
title="User avatar"
|
title="User avatar"
|
||||||
avatarProps={chatTheme.guestAvatar}
|
avatarProps={chatTheme.guestAvatar}
|
||||||
onAvatarChange={handleGuestAvatarChange}
|
onAvatarChange={handleGuestAvatarChange}
|
||||||
|
@ -72,6 +72,7 @@ export const ThemeSideMenu = () => {
|
|||||||
<AccordionPanel pb={4}>
|
<AccordionPanel pb={4}>
|
||||||
{typebot && (
|
{typebot && (
|
||||||
<ChatThemeSettings
|
<ChatThemeSettings
|
||||||
|
typebotId={typebot.id}
|
||||||
chatTheme={typebot.theme.chat}
|
chatTheme={typebot.theme.chat}
|
||||||
onChatThemeChange={handleChatThemeChange}
|
onChatThemeChange={handleChatThemeChange}
|
||||||
/>
|
/>
|
||||||
|
@ -21,7 +21,9 @@ test('should display user info properly', async ({ page }) => {
|
|||||||
await expect(page.locator('img >> nth=1')).toHaveAttribute(
|
await expect(page.locator('img >> nth=1')).toHaveAttribute(
|
||||||
'src',
|
'src',
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
|
`${process.env.S3_ENDPOINT}${
|
||||||
|
process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''
|
||||||
|
}/${process.env.S3_BUCKET}/public/users/${userId}/avatar`,
|
||||||
'gm'
|
'gm'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -32,10 +32,11 @@ test.describe.parallel('Image bubble block', () => {
|
|||||||
)
|
)
|
||||||
await expect(page.locator('img')).toHaveAttribute(
|
await expect(page.locator('img')).toHaveAttribute(
|
||||||
'src',
|
'src',
|
||||||
new RegExp(
|
`${process.env.S3_SSL === 'false' ? 'http://' : 'https://'}${
|
||||||
`${process.env.S3_ENDPOINT}/${process.env.S3_BUCKET}/public/typebots/${typebotId}/avatar.jpg`,
|
process.env.S3_ENDPOINT
|
||||||
'gm'
|
}${process.env.S3_PORT ? `:${process.env.S3_PORT}` : ''}/${
|
||||||
)
|
process.env.S3_BUCKET
|
||||||
|
}/public/typebots/${typebotId}/blocks/block1`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"apps/*"
|
"apps/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d",
|
"docker:up": "docker compose -f docker-compose.dev.yml up -d && sleep 5",
|
||||||
"docker:nuke": "docker compose -f docker-compose.dev.yml down --volumes --remove-orphans",
|
"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": "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",
|
"dev:mocking": "pnpm docker:up && NEXT_PUBLIC_E2E_TEST=true turbo run dev --filter=builder... --filter=viewer... --parallel --no-cache",
|
||||||
|
Reference in New Issue
Block a user