Revert "fix(docker): 🐛 Runtime public environment"
This reverts commit e03fe9f7d9
.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,5 +24,3 @@ firebaseServiceAccount.json
|
|||||||
tags
|
tags
|
||||||
|
|
||||||
dump.sql
|
dump.sql
|
||||||
|
|
||||||
__env.js
|
|
||||||
|
@ -36,10 +36,10 @@ COPY --from=builder /app/apps/${SCOPE}/.next/static ./.next/static
|
|||||||
COPY --from=builder /app/apps/${SCOPE}/.env.docker ./.env.production
|
COPY --from=builder /app/apps/${SCOPE}/.env.docker ./.env.production
|
||||||
RUN apt-get -qy update && apt-get -qy install openssl
|
RUN apt-get -qy update && apt-get -qy install openssl
|
||||||
|
|
||||||
COPY env.sh ./
|
COPY entrypoint.sh ./
|
||||||
COPY ${SCOPE}-entrypoint.sh ./
|
COPY ${SCOPE}-entrypoint.sh ./
|
||||||
RUN chmod +x ./${SCOPE}-entrypoint.sh
|
RUN chmod +x ./${SCOPE}-entrypoint.sh
|
||||||
RUN chmod +x ./env.sh
|
RUN chmod +x ./entrypoint.sh
|
||||||
ENTRYPOINT ./${SCOPE}-entrypoint.sh
|
ENTRYPOINT ./${SCOPE}-entrypoint.sh
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Don't edit this file
|
# Don't edit this file
|
||||||
NEXT_PUBLIC_VIEWER_URL=
|
NEXT_PUBLIC_VIEWER_URL=DOCKER_NEXT_PUBLIC_VIEWER_URL
|
||||||
NEXT_PUBLIC_SMTP_FROM=
|
NEXT_PUBLIC_SMTP_FROM=DOCKER_NEXT_PUBLIC_SMTP_FROM
|
||||||
NEXT_PUBLIC_GOOGLE_API_KEY=
|
NEXT_PUBLIC_GOOGLE_API_KEY=DOCKER_NEXT_PUBLIC_GOOGLE_API_KEY
|
||||||
NEXT_PUBLIC_GIPHY_API_KEY=
|
NEXT_PUBLIC_GIPHY_API_KEY=DOCKER_NEXT_PUBLIC_GIPHY_API_KEY
|
||||||
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=
|
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=DOCKER_NEXT_PUBLIC_STRIPE_PUBLIC_KEY
|
||||||
NEXT_PUBLIC_SENTRY_DSN=
|
NEXT_PUBLIC_SENTRY_DSN=DOCKER_NEXT_PUBLIC_SENTRY_DSN
|
||||||
|
@ -20,7 +20,6 @@ import { isDefined, isNotDefined } from 'utils'
|
|||||||
import { CustomDomainsDropdown } from './customDomain/CustomDomainsDropdown'
|
import { CustomDomainsDropdown } from './customDomain/CustomDomainsDropdown'
|
||||||
import { EditableUrl } from './EditableUrl'
|
import { EditableUrl } from './EditableUrl'
|
||||||
import { integrationsList } from './integrations/EmbedButton'
|
import { integrationsList } from './integrations/EmbedButton'
|
||||||
import { env } from 'utils'
|
|
||||||
|
|
||||||
export const ShareContent = () => {
|
export const ShareContent = () => {
|
||||||
const { workspace } = useWorkspace()
|
const { workspace } = useWorkspace()
|
||||||
@ -59,7 +58,9 @@ export const ShareContent = () => {
|
|||||||
</Heading>
|
</Heading>
|
||||||
{typebot && (
|
{typebot && (
|
||||||
<EditableUrl
|
<EditableUrl
|
||||||
hostname={env('VIEWER_URL') ?? 'https://typebot.io'}
|
hostname={
|
||||||
|
process.env.NEXT_PUBLIC_VIEWER_URL ?? 'https://typebot.io'
|
||||||
|
}
|
||||||
pathname={publicId}
|
pathname={publicId}
|
||||||
onPathnameChange={handlePublicIdChange}
|
onPathnameChange={handlePublicIdChange}
|
||||||
/>
|
/>
|
||||||
|
@ -5,7 +5,7 @@ import { BubbleParams } from 'typebot-js'
|
|||||||
import { parseInitBubbleCode, typebotJsHtml } from '../params'
|
import { parseInitBubbleCode, typebotJsHtml } from '../params'
|
||||||
import { useTypebot } from 'contexts/TypebotContext'
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
type ChatEmbedCodeProps = {
|
type ChatEmbedCodeProps = {
|
||||||
withStarterVariables?: boolean
|
withStarterVariables?: boolean
|
||||||
@ -21,9 +21,9 @@ export const ChatEmbedCode = ({
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
createSnippet({
|
createSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
button,
|
button,
|
||||||
proactiveMessage,
|
proactiveMessage,
|
||||||
|
@ -5,7 +5,7 @@ import { parseInitContainerCode, typebotJsHtml } from '../params'
|
|||||||
import { IframeParams } from 'typebot-js'
|
import { IframeParams } from 'typebot-js'
|
||||||
import { useTypebot } from 'contexts/TypebotContext'
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
type ContainerEmbedCodeProps = {
|
type ContainerEmbedCodeProps = {
|
||||||
widthLabel: string
|
widthLabel: string
|
||||||
@ -23,9 +23,9 @@ export const ContainerEmbedCode = ({
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
parseSnippet({
|
parseSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
heightLabel,
|
heightLabel,
|
||||||
widthLabel,
|
widthLabel,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FlexProps } from '@chakra-ui/react'
|
import { FlexProps } from '@chakra-ui/react'
|
||||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||||
import { useTypebot } from 'contexts/TypebotContext'
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
widthLabel: string
|
widthLabel: string
|
||||||
@ -14,9 +14,9 @@ export const IframeEmbedCode = ({
|
|||||||
}: Props & FlexProps) => {
|
}: Props & FlexProps) => {
|
||||||
const { typebot } = useTypebot()
|
const { typebot } = useTypebot()
|
||||||
const src = `${
|
const src = `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`
|
}/${typebot?.publicId}`
|
||||||
const code = `<iframe src="${src}" width="${widthLabel}" height="${heightLabel}" />`
|
const code = `<iframe src="${src}" width="${widthLabel}" height="${heightLabel}" />`
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { useTypebot } from 'contexts/TypebotContext'
|
|||||||
import parserHtml from 'prettier/parser-html'
|
import parserHtml from 'prettier/parser-html'
|
||||||
import prettier from 'prettier/standalone'
|
import prettier from 'prettier/standalone'
|
||||||
import { PopupParams } from 'typebot-js'
|
import { PopupParams } from 'typebot-js'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { parseInitPopupCode, typebotJsHtml } from '../params'
|
import { parseInitPopupCode, typebotJsHtml } from '../params'
|
||||||
|
|
||||||
type PopupEmbedCodeProps = {
|
type PopupEmbedCodeProps = {
|
||||||
@ -18,9 +18,9 @@ export const PopupEmbedCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
createSnippet({
|
createSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
delay,
|
delay,
|
||||||
}),
|
}),
|
||||||
|
@ -10,7 +10,7 @@ import parserBabel from 'prettier/parser-babel'
|
|||||||
import prettier from 'prettier/standalone'
|
import prettier from 'prettier/standalone'
|
||||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||||
import { useTypebot } from 'contexts/TypebotContext'
|
import { useTypebot } from 'contexts/TypebotContext'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
type StandardReactDivProps = { widthLabel: string; heightLabel: string }
|
type StandardReactDivProps = { widthLabel: string; heightLabel: string }
|
||||||
export const StandardReactDiv = ({
|
export const StandardReactDiv = ({
|
||||||
@ -21,9 +21,9 @@ export const StandardReactDiv = ({
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
parseContainerSnippet({
|
parseContainerSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
heightLabel,
|
heightLabel,
|
||||||
widthLabel,
|
widthLabel,
|
||||||
@ -73,9 +73,9 @@ export const PopupReactCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
parsePopupSnippet({
|
parsePopupSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
delay,
|
delay,
|
||||||
}),
|
}),
|
||||||
@ -124,9 +124,9 @@ export const ChatReactCode = ({
|
|||||||
const snippet = prettier.format(
|
const snippet = prettier.format(
|
||||||
parseBubbleSnippet({
|
parseBubbleSnippet({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${typebot?.publicId}`,
|
}/${typebot?.publicId}`,
|
||||||
button,
|
button,
|
||||||
proactiveMessage,
|
proactiveMessage,
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
import { useToast } from 'components/shared/hooks/useToast'
|
import { useToast } from 'components/shared/hooks/useToast'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { createCustomDomain } from 'services/user'
|
import { createCustomDomain } from 'services/user'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
const hostnameRegex =
|
const hostnameRegex =
|
||||||
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
|
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
|
||||||
@ -118,9 +118,9 @@ export const CustomDomainModal = ({
|
|||||||
<Stack>
|
<Stack>
|
||||||
<Text fontWeight="bold">Value</Text>
|
<Text fontWeight="bold">Value</Text>
|
||||||
<Text>
|
<Text>
|
||||||
{isEmpty(env('VIEWER_INTERNAL_URL'))
|
{isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')}
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL}
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
@ -11,7 +11,7 @@ import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSet
|
|||||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { BubbleParams } from 'typebot-js'
|
import { BubbleParams } from 'typebot-js'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { ModalProps } from '../../EmbedButton'
|
import { ModalProps } from '../../EmbedButton'
|
||||||
|
|
||||||
type GtmInstructionsProps = {
|
type GtmInstructionsProps = {
|
||||||
@ -41,9 +41,9 @@ const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
|
|||||||
|
|
||||||
const jsCode = parseInitContainerCode({
|
const jsCode = parseInitContainerCode({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`,
|
}/${publicId}`,
|
||||||
})
|
})
|
||||||
const headCode = `${typebotJsHtml}
|
const headCode = `${typebotJsHtml}
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
} from '@chakra-ui/react'
|
} from '@chakra-ui/react'
|
||||||
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
||||||
import { PublishFirstInfo } from 'components/shared/Info'
|
import { PublishFirstInfo } from 'components/shared/Info'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { ModalProps } from '../EmbedButton'
|
import { ModalProps } from '../EmbedButton'
|
||||||
|
|
||||||
export const NotionModal = ({
|
export const NotionModal = ({
|
||||||
@ -46,17 +46,17 @@ export const NotionModal = ({
|
|||||||
pr="4.5rem"
|
pr="4.5rem"
|
||||||
type={'text'}
|
type={'text'}
|
||||||
defaultValue={`${
|
defaultValue={`${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`}
|
}/${publicId}`}
|
||||||
/>
|
/>
|
||||||
<InputRightElement width="4.5rem">
|
<InputRightElement width="4.5rem">
|
||||||
<CopyButton
|
<CopyButton
|
||||||
textToCopy={`${
|
textToCopy={`${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`}
|
}/${publicId}`}
|
||||||
/>
|
/>
|
||||||
</InputRightElement>
|
</InputRightElement>
|
||||||
|
@ -14,7 +14,7 @@ import { BubbleParams } from 'typebot-js'
|
|||||||
import { ModalProps } from '../../EmbedButton'
|
import { ModalProps } from '../../EmbedButton'
|
||||||
import parserHtml from 'prettier/parser-html'
|
import parserHtml from 'prettier/parser-html'
|
||||||
import prettier from 'prettier/standalone'
|
import prettier from 'prettier/standalone'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
type ShopifyInstructionsProps = {
|
type ShopifyInstructionsProps = {
|
||||||
type: 'standard' | 'popup' | 'bubble'
|
type: 'standard' | 'popup' | 'bubble'
|
||||||
@ -46,9 +46,9 @@ const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
|
|||||||
|
|
||||||
const jsCode = parseInitContainerCode({
|
const jsCode = parseInitContainerCode({
|
||||||
url: `${
|
url: `${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`,
|
}/${publicId}`,
|
||||||
})
|
})
|
||||||
const headCode = prettier.format(
|
const headCode = prettier.format(
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
import { ExternalLinkIcon } from 'assets/icons'
|
import { ExternalLinkIcon } from 'assets/icons'
|
||||||
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
import { CopyButton } from 'components/shared/buttons/CopyButton'
|
||||||
import { PublishFirstInfo } from 'components/shared/Info'
|
import { PublishFirstInfo } from 'components/shared/Info'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { ModalProps } from '../EmbedButton'
|
import { ModalProps } from '../EmbedButton'
|
||||||
|
|
||||||
export const WordpressModal = ({
|
export const WordpressModal = ({
|
||||||
@ -55,17 +55,17 @@ export const WordpressModal = ({
|
|||||||
pr="4.5rem"
|
pr="4.5rem"
|
||||||
type={'text'}
|
type={'text'}
|
||||||
defaultValue={`${
|
defaultValue={`${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`}
|
}/${publicId}`}
|
||||||
/>
|
/>
|
||||||
<InputRightElement width="4.5rem">
|
<InputRightElement width="4.5rem">
|
||||||
<CopyButton
|
<CopyButton
|
||||||
textToCopy={`${
|
textToCopy={`${
|
||||||
isEmpty(env('VIEWER_INTERNAL_URL'))
|
isEmpty(process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL)
|
||||||
? env('VIEWER_URL')
|
? process.env.NEXT_PUBLIC_VIEWER_URL
|
||||||
: env('VIEWER_INTERNAL_URL')
|
: process.env.NEXT_PUBLIC_VIEWER_INTERNAL_URL
|
||||||
}/${publicId}`}
|
}/${publicId}`}
|
||||||
/>
|
/>
|
||||||
</InputRightElement>
|
</InputRightElement>
|
||||||
|
@ -9,7 +9,7 @@ import { useDebouncedCallback } from 'use-debounce'
|
|||||||
import { linter } from '@codemirror/lint'
|
import { linter } from '@codemirror/lint'
|
||||||
import { VariablesButton } from './buttons/VariablesButton'
|
import { VariablesButton } from './buttons/VariablesButton'
|
||||||
import { Variable } from 'models'
|
import { Variable } from 'models'
|
||||||
import { env } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
const linterExtension = linter(jsonParseLinter())
|
const linterExtension = linter(jsonParseLinter())
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ export const CodeEditor = ({
|
|||||||
setPlainTextValue(value)
|
setPlainTextValue(value)
|
||||||
onChange && onChange(value)
|
onChange && onChange(value)
|
||||||
},
|
},
|
||||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? debounceTimeout : 0
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
|
@ -12,7 +12,6 @@ import { SwitchWithLabel } from 'components/shared/SwitchWithLabel'
|
|||||||
import { Input, Textarea } from 'components/shared/Textbox'
|
import { Input, Textarea } from 'components/shared/Textbox'
|
||||||
import { CredentialsType, SendEmailOptions } from 'models'
|
import { CredentialsType, SendEmailOptions } from 'models'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { env } from 'utils'
|
|
||||||
import { SmtpConfigModal } from './SmtpConfigModal'
|
import { SmtpConfigModal } from './SmtpConfigModal'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -97,9 +96,9 @@ export const SendEmailSettings = ({ options, onOptionsChange }: Props) => {
|
|||||||
currentCredentialsId={options.credentialsId}
|
currentCredentialsId={options.credentialsId}
|
||||||
onCredentialsSelect={handleCredentialsSelect}
|
onCredentialsSelect={handleCredentialsSelect}
|
||||||
onCreateNewClick={onOpen}
|
onCreateNewClick={onOpen}
|
||||||
defaultCredentialLabel={env('SMTP_FROM')
|
defaultCredentialLabel={process.env.NEXT_PUBLIC_SMTP_FROM?.match(
|
||||||
?.match(/\<(.*)\>/)
|
/\<(.*)\>/
|
||||||
?.pop()}
|
)?.pop()}
|
||||||
refreshDropdownKey={refreshCredentialsKey}
|
refreshDropdownKey={refreshCredentialsKey}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
@ -4,13 +4,14 @@ import { Grid, SearchContext } from '@giphy/react-components'
|
|||||||
import { GiphyLogo } from 'assets/logos'
|
import { GiphyLogo } from 'assets/logos'
|
||||||
import React, { useContext, useState, useEffect } from 'react'
|
import React, { useContext, useState, useEffect } from 'react'
|
||||||
import { useDebounce } from 'use-debounce'
|
import { useDebounce } from 'use-debounce'
|
||||||
import { env } from 'utils'
|
|
||||||
|
|
||||||
type GiphySearchProps = {
|
type GiphySearchProps = {
|
||||||
onSubmit: (url: string) => void
|
onSubmit: (url: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const giphyFetch = new GiphyFetch(env('GIPHY_API_KEY') as string)
|
const giphyFetch = new GiphyFetch(
|
||||||
|
process.env.NEXT_PUBLIC_GIPHY_API_KEY as string
|
||||||
|
)
|
||||||
|
|
||||||
export const GiphySearch = ({ onSubmit }: GiphySearchProps) => {
|
export const GiphySearch = ({ onSubmit }: GiphySearchProps) => {
|
||||||
const { fetchGifs, searchKey, setSearch } = useContext(SearchContext)
|
const { fetchGifs, searchKey, setSearch } = useContext(SearchContext)
|
||||||
|
@ -16,7 +16,12 @@ import { useTypebot } from 'contexts/TypebotContext'
|
|||||||
import { BaseEmoji, emojiIndex } from 'emoji-mart'
|
import { BaseEmoji, emojiIndex } from 'emoji-mart'
|
||||||
import { emojis } from './emojis'
|
import { emojis } from './emojis'
|
||||||
import { Input } from '../Textbox/Input'
|
import { Input } from '../Textbox/Input'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
|
||||||
|
const {
|
||||||
|
publicRuntimeConfig: { NEXT_PUBLIC_GIPHY_API_KEY },
|
||||||
|
} = getConfig()
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
url?: string
|
url?: string
|
||||||
@ -183,10 +188,10 @@ const EmojiContent = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const GiphyContent = ({ onNewUrl }: ContentProps) => {
|
const GiphyContent = ({ onNewUrl }: ContentProps) => {
|
||||||
if (isEmpty(env('GIPHY_API_KEY')))
|
if (isEmpty(NEXT_PUBLIC_GIPHY_API_KEY))
|
||||||
return <Text>NEXT_PUBLIC_GIPHY_API_KEY is missing in environment</Text>
|
return <Text>NEXT_PUBLIC_GIPHY_API_KEY is missing in environment</Text>
|
||||||
return (
|
return (
|
||||||
<SearchContextManager apiKey={env('GIPHY_API_KEY') as string}>
|
<SearchContextManager apiKey={NEXT_PUBLIC_GIPHY_API_KEY}>
|
||||||
<GiphySearch onSubmit={onNewUrl} />
|
<GiphySearch onSubmit={onNewUrl} />
|
||||||
</SearchContextManager>
|
</SearchContextManager>
|
||||||
)
|
)
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
import { Variable } from 'models'
|
import { Variable } from 'models'
|
||||||
import { useState, useRef, useEffect, ChangeEvent } from 'react'
|
import { useState, useRef, useEffect, ChangeEvent } from 'react'
|
||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
import { env } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { VariablesButton } from './buttons/VariablesButton'
|
import { VariablesButton } from './buttons/VariablesButton'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -38,7 +38,7 @@ export const SearchableDropdown = ({
|
|||||||
const debounced = useDebouncedCallback(
|
const debounced = useDebouncedCallback(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
onValueChange ? onValueChange : () => {},
|
onValueChange ? onValueChange : () => {},
|
||||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? debounceTimeout : 0
|
||||||
)
|
)
|
||||||
const [filteredItems, setFilteredItems] = useState([
|
const [filteredItems, setFilteredItems] = useState([
|
||||||
...items
|
...items
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
} from '@chakra-ui/react'
|
} from '@chakra-ui/react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
import { env } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
export const SmartNumberInput = ({
|
export const SmartNumberInput = ({
|
||||||
value,
|
value,
|
||||||
@ -23,7 +23,7 @@ export const SmartNumberInput = ({
|
|||||||
const [currentValue, setCurrentValue] = useState(value?.toString() ?? '')
|
const [currentValue, setCurrentValue] = useState(value?.toString() ?? '')
|
||||||
const debounced = useDebouncedCallback(
|
const debounced = useDebouncedCallback(
|
||||||
onValueChange,
|
onValueChange,
|
||||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? debounceTimeout : 0
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
import { Variable } from 'models'
|
import { Variable } from 'models'
|
||||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react'
|
import React, { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
import { env } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
import { VariablesButton } from '../buttons/VariablesButton'
|
import { VariablesButton } from '../buttons/VariablesButton'
|
||||||
|
|
||||||
export type TextBoxProps = {
|
export type TextBoxProps = {
|
||||||
@ -36,7 +36,7 @@ export const TextBox = ({
|
|||||||
(value) => {
|
(value) => {
|
||||||
onChange(value)
|
onChange(value)
|
||||||
},
|
},
|
||||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? debounceTimeout : 0
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -17,7 +17,7 @@ import cuid from 'cuid'
|
|||||||
import { Variable } from 'models'
|
import { Variable } from 'models'
|
||||||
import React, { useState, useRef, ChangeEvent, useEffect } from 'react'
|
import React, { useState, useRef, ChangeEvent, useEffect } from 'react'
|
||||||
import { useDebouncedCallback } from 'use-debounce'
|
import { useDebouncedCallback } from 'use-debounce'
|
||||||
import { byId, env, isNotDefined } from 'utils'
|
import { byId, isEmpty, isNotDefined } from 'utils'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialVariableId?: string
|
initialVariableId?: string
|
||||||
@ -47,7 +47,7 @@ export const VariableSearchInput = ({
|
|||||||
const variable = variables.find((v) => v.name === value)
|
const variable = variables.find((v) => v.name === value)
|
||||||
if (variable) onSelectVariable(variable)
|
if (variable) onSelectVariable(variable)
|
||||||
},
|
},
|
||||||
env('E2E_TEST') === 'enabled' ? 0 : debounceTimeout
|
isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? debounceTimeout : 0
|
||||||
)
|
)
|
||||||
const [filteredItems, setFilteredItems] = useState<Variable[]>(
|
const [filteredItems, setFilteredItems] = useState<Variable[]>(
|
||||||
variables ?? []
|
variables ?? []
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Text, HStack } from '@chakra-ui/react'
|
import { Text, HStack } from '@chakra-ui/react'
|
||||||
import { SearchableDropdown } from '../../../shared/SearchableDropdown'
|
import { SearchableDropdown } from '../../../shared/SearchableDropdown'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
|
||||||
type FontSelectorProps = {
|
type FontSelectorProps = {
|
||||||
activeFont?: string
|
activeFont?: string
|
||||||
@ -20,11 +21,12 @@ export const FontSelector = ({
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const fetchPopularFonts = async () => {
|
const fetchPopularFonts = async () => {
|
||||||
if (isEmpty(env('GOOGLE_API_KEY'))) return []
|
const {
|
||||||
|
publicRuntimeConfig: { NEXT_PUBLIC_GOOGLE_API_KEY },
|
||||||
|
} = getConfig()
|
||||||
|
if (isEmpty(NEXT_PUBLIC_GOOGLE_API_KEY)) return []
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://www.googleapis.com/webfonts/v1/webfonts?key=${env(
|
`https://www.googleapis.com/webfonts/v1/webfonts?key=${NEXT_PUBLIC_GOOGLE_API_KEY}&sort=popularity`
|
||||||
'GOOGLE_API_KEY'
|
|
||||||
)}&sort=popularity`
|
|
||||||
)
|
)
|
||||||
return (await response.json()).items.map(
|
return (await response.json()).items.map(
|
||||||
(item: { family: string }) => item.family
|
(item: { family: string }) => item.family
|
||||||
|
@ -29,7 +29,7 @@ import {
|
|||||||
} from 'services/typebots/typebots'
|
} from 'services/typebots/typebots'
|
||||||
import { fetcher, preventUserFromRefreshing } from 'services/utils'
|
import { fetcher, preventUserFromRefreshing } from 'services/utils'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { env, isDefined, isNotDefined, omit } from 'utils'
|
import { isDefined, isEmpty, isNotDefined, omit } from 'utils'
|
||||||
import { GroupsActions, groupsActions } from './actions/groups'
|
import { GroupsActions, groupsActions } from './actions/groups'
|
||||||
import { blocksAction, BlocksActions } from './actions/blocks'
|
import { blocksAction, BlocksActions } from './actions/blocks'
|
||||||
import { variablesAction, VariablesActions } from './actions/variables'
|
import { variablesAction, VariablesActions } from './actions/variables'
|
||||||
@ -395,7 +395,7 @@ export const useFetchedTypebot = ({
|
|||||||
},
|
},
|
||||||
Error
|
Error
|
||||||
>(`/api/typebots/${typebotId}`, fetcher, {
|
>(`/api/typebots/${typebotId}`, fetcher, {
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? undefined : 0,
|
||||||
})
|
})
|
||||||
if (error) onError(error)
|
if (error) onError(error)
|
||||||
return {
|
return {
|
||||||
|
@ -6,6 +6,11 @@ const moduleExports = {
|
|||||||
outputStandalone: true,
|
outputStandalone: true,
|
||||||
},
|
},
|
||||||
optimizeFonts: false,
|
optimizeFonts: false,
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
NEXT_PUBLIC_GOOGLE_API_KEY: process.env.NEXT_PUBLIC_GOOGLE_API_KEY,
|
||||||
|
NEXT_PUBLIC_GIPHY_API_KEY: process.env.NEXT_PUBLIC_GIPHY_API_KEY,
|
||||||
|
NEXT_PUBLIC_STRIPE_PUBLIC_KEY: process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const sentryWebpackPluginOptions = {
|
const sentryWebpackPluginOptions = {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dx": "yarn dev",
|
"dx": "yarn dev",
|
||||||
"dev": "ENVSH_ENV=.env.local bash ../../env.sh next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
@ -22,8 +22,6 @@ class MyDocument extends Document {
|
|||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
<meta name="google" content="notranslate" />
|
<meta name="google" content="notranslate" />
|
||||||
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
|
|
||||||
<script src="/__env.js" />
|
|
||||||
</Head>
|
</Head>
|
||||||
<body>
|
<body>
|
||||||
<Main />
|
<Main />
|
||||||
|
@ -11,7 +11,7 @@ import { NextApiRequest, NextApiResponse } from 'next'
|
|||||||
import { withSentry } from '@sentry/nextjs'
|
import { withSentry } from '@sentry/nextjs'
|
||||||
import { CustomAdapter } from './adapter'
|
import { CustomAdapter } from './adapter'
|
||||||
import { User } from 'db'
|
import { User } from 'db'
|
||||||
import { env, isNotEmpty } from 'utils'
|
import { isNotEmpty } from 'utils'
|
||||||
|
|
||||||
const providers: Provider[] = []
|
const providers: Provider[] = []
|
||||||
|
|
||||||
@ -23,7 +23,10 @@ if (isNotEmpty(process.env.GITHUB_CLIENT_ID))
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isNotEmpty(env('SMTP_FROM')) && process.env.SMTP_AUTH_DISABLED !== 'true')
|
if (
|
||||||
|
isNotEmpty(process.env.NEXT_PUBLIC_SMTP_FROM) &&
|
||||||
|
process.env.SMTP_AUTH_DISABLED !== 'true'
|
||||||
|
)
|
||||||
providers.push(
|
providers.push(
|
||||||
EmailProvider({
|
EmailProvider({
|
||||||
server: {
|
server: {
|
||||||
@ -35,7 +38,7 @@ if (isNotEmpty(env('SMTP_FROM')) && process.env.SMTP_AUTH_DISABLED !== 'true')
|
|||||||
},
|
},
|
||||||
ignoreTLS: process.env.SMTP_IGNORE_TLS === 'true',
|
ignoreTLS: process.env.SMTP_IGNORE_TLS === 'true',
|
||||||
},
|
},
|
||||||
from: env('SMTP_FROM'),
|
from: process.env.NEXT_PUBLIC_SMTP_FROM,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ import { sendEmailNotification } from 'services/api/emails'
|
|||||||
import { getAuthenticatedUser } from 'services/api/utils'
|
import { getAuthenticatedUser } from 'services/api/utils'
|
||||||
import {
|
import {
|
||||||
badRequest,
|
badRequest,
|
||||||
env,
|
|
||||||
forbidden,
|
forbidden,
|
||||||
|
isEmpty,
|
||||||
methodNotAllowed,
|
methodNotAllowed,
|
||||||
notAuthenticated,
|
notAuthenticated,
|
||||||
} from 'utils'
|
} from 'utils'
|
||||||
@ -66,7 +66,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
await prisma.invitation.create({
|
await prisma.invitation.create({
|
||||||
data: { email: email.toLowerCase(), type, typebotId },
|
data: { email: email.toLowerCase(), type, typebotId },
|
||||||
})
|
})
|
||||||
if (env('E2E_TEST') !== 'enabled')
|
if (isEmpty(process.env.NEXT_PUBLIC_E2E_TEST))
|
||||||
await sendEmailNotification({
|
await sendEmailNotification({
|
||||||
to: email,
|
to: email,
|
||||||
subject: "You've been invited to collaborate 🤝",
|
subject: "You've been invited to collaborate 🤝",
|
||||||
|
@ -8,7 +8,6 @@ import path from 'path'
|
|||||||
import {
|
import {
|
||||||
createResults,
|
createResults,
|
||||||
createTypebots,
|
createTypebots,
|
||||||
freeWorkspaceId,
|
|
||||||
importTypebotInDatabase,
|
importTypebotInDatabase,
|
||||||
parseDefaultGroupWithBlock,
|
parseDefaultGroupWithBlock,
|
||||||
} from '../services/database'
|
} from '../services/database'
|
||||||
@ -124,7 +123,7 @@ test.describe('Results page', () => {
|
|||||||
test("Incomplete results shouldn't be displayed", async ({ page }) => {
|
test("Incomplete results shouldn't be displayed", async ({ page }) => {
|
||||||
await prisma.typebot.update({
|
await prisma.typebot.update({
|
||||||
where: { id: typebotId },
|
where: { id: typebotId },
|
||||||
data: { workspaceId: freeWorkspaceId },
|
data: { workspaceId: 'free' },
|
||||||
})
|
})
|
||||||
await page.goto(`/typebots/${typebotId}/results`)
|
await page.goto(`/typebots/${typebotId}/results`)
|
||||||
await page.click('text=Unlock')
|
await page.click('text=Unlock')
|
||||||
|
@ -2,7 +2,7 @@ import test, { expect } from '@playwright/test'
|
|||||||
import cuid from 'cuid'
|
import cuid from 'cuid'
|
||||||
import { defaultTextInputOptions } from 'models'
|
import { defaultTextInputOptions } from 'models'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { freeWorkspaceId, importTypebotInDatabase } from '../services/database'
|
import { importTypebotInDatabase } from '../services/database'
|
||||||
import { typebotViewer } from '../services/selectorUtils'
|
import { typebotViewer } from '../services/selectorUtils'
|
||||||
|
|
||||||
test.describe.parallel('Settings page', () => {
|
test.describe.parallel('Settings page', () => {
|
||||||
@ -127,7 +127,7 @@ test.describe.parallel('Settings page', () => {
|
|||||||
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
path.join(__dirname, '../fixtures/typebots/settings.json'),
|
||||||
{
|
{
|
||||||
id: typebotId,
|
id: typebotId,
|
||||||
workspaceId: freeWorkspaceId,
|
workspaceId: 'free',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await page.goto(`/typebots/${typebotId}/settings`)
|
await page.goto(`/typebots/${typebotId}/settings`)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { CollaborationType, Plan, Prisma, User, WorkspaceRole } from 'db'
|
import { CollaborationType, Plan, Prisma, User, WorkspaceRole } from 'db'
|
||||||
import prisma from 'libs/prisma'
|
import prisma from 'libs/prisma'
|
||||||
import { NextApiResponse } from 'next'
|
import { NextApiResponse } from 'next'
|
||||||
import { env, forbidden, isNotEmpty } from 'utils'
|
import { forbidden, isNotEmpty } from 'utils'
|
||||||
|
|
||||||
const parseWhereFilter = (
|
const parseWhereFilter = (
|
||||||
typebotIds: string[] | string,
|
typebotIds: string[] | string,
|
||||||
@ -22,7 +22,7 @@ const parseWhereFilter = (
|
|||||||
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
||||||
workspace:
|
workspace:
|
||||||
(type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
(type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
||||||
isNotEmpty(env('E2E_TEST'))
|
isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
members: {
|
members: {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { createTransport } from 'nodemailer'
|
import { createTransport } from 'nodemailer'
|
||||||
import { env } from 'utils'
|
|
||||||
|
|
||||||
export const sendEmailNotification = ({
|
export const sendEmailNotification = ({
|
||||||
to,
|
to,
|
||||||
@ -20,7 +19,7 @@ export const sendEmailNotification = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return transporter.sendMail({
|
return transporter.sendMail({
|
||||||
from: env('SMTP_FORM'),
|
from: process.env.NEXT_PUBLIC_SMTP_FROM,
|
||||||
to,
|
to,
|
||||||
subject,
|
subject,
|
||||||
html: content,
|
html: content,
|
||||||
|
@ -2,7 +2,7 @@ import { DashboardFolder } from 'db'
|
|||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { fetcher } from './utils'
|
import { fetcher } from './utils'
|
||||||
import { stringify } from 'qs'
|
import { stringify } from 'qs'
|
||||||
import { env, sendRequest } from 'utils'
|
import { isNotEmpty, sendRequest } from 'utils'
|
||||||
|
|
||||||
export const useFolders = ({
|
export const useFolders = ({
|
||||||
parentId,
|
parentId,
|
||||||
@ -18,7 +18,9 @@ export const useFolders = ({
|
|||||||
workspaceId ? `/api/folders?${params}` : null,
|
workspaceId ? `/api/folders?${params}` : null,
|
||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
|
? 0
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (error) onError(error)
|
if (error) onError(error)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { env, sendRequest } from 'utils'
|
import { sendRequest } from 'utils'
|
||||||
import { stringify } from 'qs'
|
import { stringify } from 'qs'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { fetcher } from './utils'
|
import { fetcher } from './utils'
|
||||||
@ -78,9 +78,7 @@ export const executeWebhook = (
|
|||||||
{ blockId }: { blockId: string }
|
{ blockId }: { blockId: string }
|
||||||
) =>
|
) =>
|
||||||
sendRequest<WebhookResponse>({
|
sendRequest<WebhookResponse>({
|
||||||
url: `${env(
|
url: `${process.env.NEXT_PUBLIC_VIEWER_URL}/api/typebots/${typebotId}/blocks/${blockId}/executeWebhook`,
|
||||||
'VIEWER_URL'
|
|
||||||
)}/api/typebots/${typebotId}/blocks/${blockId}/executeWebhook`,
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: {
|
body: {
|
||||||
variables,
|
variables,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Plan, User } from 'db'
|
import { Plan, User } from 'db'
|
||||||
import { loadStripe } from '@stripe/stripe-js/pure'
|
import { loadStripe } from '@stripe/stripe-js/pure'
|
||||||
import { env, isDefined, isEmpty, sendRequest } from 'utils'
|
import { isDefined, isEmpty, sendRequest } from 'utils'
|
||||||
|
import getConfig from 'next/config'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User
|
user: User
|
||||||
@ -39,7 +40,10 @@ const redirectToCheckout = async ({
|
|||||||
plan,
|
plan,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
}: Omit<Props, 'customerId'>) => {
|
}: Omit<Props, 'customerId'>) => {
|
||||||
if (isEmpty(env('STRIPE_PUBLIC_KEY')))
|
const {
|
||||||
|
publicRuntimeConfig: { NEXT_PUBLIC_STRIPE_PUBLIC_KEY },
|
||||||
|
} = getConfig()
|
||||||
|
if (isEmpty(NEXT_PUBLIC_STRIPE_PUBLIC_KEY))
|
||||||
throw new Error('NEXT_PUBLIC_STRIPE_PUBLIC_KEY is missing in env')
|
throw new Error('NEXT_PUBLIC_STRIPE_PUBLIC_KEY is missing in env')
|
||||||
const { data, error } = await sendRequest<{ sessionId: string }>({
|
const { data, error } = await sendRequest<{ sessionId: string }>({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -53,7 +57,7 @@ const redirectToCheckout = async ({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (error || !data) return
|
if (error || !data) return
|
||||||
const stripe = await loadStripe(env('STRIPE_PUBLIC_KEY') as string)
|
const stripe = await loadStripe(NEXT_PUBLIC_STRIPE_PUBLIC_KEY)
|
||||||
await stripe?.redirectToCheckout({
|
await stripe?.redirectToCheckout({
|
||||||
sessionId: data?.sessionId,
|
sessionId: data?.sessionId,
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { CollaborationType, Invitation } from 'db'
|
import { CollaborationType, Invitation } from 'db'
|
||||||
import { fetcher } from 'services/utils'
|
import { fetcher } from 'services/utils'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { env, sendRequest } from 'utils'
|
import { isNotEmpty, sendRequest } from 'utils'
|
||||||
|
|
||||||
export const useInvitations = ({
|
export const useInvitations = ({
|
||||||
typebotId,
|
typebotId,
|
||||||
@ -14,7 +14,9 @@ export const useInvitations = ({
|
|||||||
typebotId ? `/api/typebots/${typebotId}/invitations` : null,
|
typebotId ? `/api/typebots/${typebotId}/invitations` : null,
|
||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
|
? 0
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (error) onError(error)
|
if (error) onError(error)
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
import useSWRInfinite from 'swr/infinite'
|
import useSWRInfinite from 'swr/infinite'
|
||||||
import { stringify } from 'qs'
|
import { stringify } from 'qs'
|
||||||
import { Answer } from 'db'
|
import { Answer } from 'db'
|
||||||
import { env, isDefined, sendRequest } from 'utils'
|
import { isDefined, isEmpty, sendRequest } from 'utils'
|
||||||
import { fetcher } from 'services/utils'
|
import { fetcher } from 'services/utils'
|
||||||
import { HStack, Text, Wrap, WrapItem } from '@chakra-ui/react'
|
import { HStack, Text, Wrap, WrapItem } from '@chakra-ui/react'
|
||||||
import { CodeIcon, CalendarIcon, FileIcon } from 'assets/icons'
|
import { CodeIcon, CalendarIcon, FileIcon } from 'assets/icons'
|
||||||
@ -54,7 +54,9 @@ export const useResults = ({
|
|||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
revalidateAll: true,
|
revalidateAll: true,
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
|
? undefined
|
||||||
|
: 0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,13 +46,13 @@ import useSWR from 'swr'
|
|||||||
import { fetcher, toKebabCase } from '../utils'
|
import { fetcher, toKebabCase } from '../utils'
|
||||||
import {
|
import {
|
||||||
isBubbleBlockType,
|
isBubbleBlockType,
|
||||||
|
isNotEmpty,
|
||||||
isWebhookBlock,
|
isWebhookBlock,
|
||||||
omit,
|
omit,
|
||||||
blockHasItems,
|
blockHasItems,
|
||||||
blockTypeHasItems,
|
blockTypeHasItems,
|
||||||
blockTypeHasOption,
|
blockTypeHasOption,
|
||||||
blockTypeHasWebhook,
|
blockTypeHasWebhook,
|
||||||
env,
|
|
||||||
} from 'utils'
|
} from 'utils'
|
||||||
import { dequal } from 'dequal'
|
import { dequal } from 'dequal'
|
||||||
import { stringify } from 'qs'
|
import { stringify } from 'qs'
|
||||||
@ -83,7 +83,9 @@ export const useTypebots = ({
|
|||||||
{ typebots: TypebotInDashboard[] },
|
{ typebots: TypebotInDashboard[] },
|
||||||
Error
|
Error
|
||||||
>(workspaceId ? `/api/typebots?${params}` : null, fetcher, {
|
>(workspaceId ? `/api/typebots?${params}` : null, fetcher, {
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
|
? 0
|
||||||
|
: undefined,
|
||||||
})
|
})
|
||||||
if (error) onError(error)
|
if (error) onError(error)
|
||||||
return {
|
return {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ApiToken } from 'db'
|
import { ApiToken } from 'db'
|
||||||
import { fetcher } from 'services/utils'
|
import { fetcher } from 'services/utils'
|
||||||
import useSWR, { KeyedMutator } from 'swr'
|
import useSWR, { KeyedMutator } from 'swr'
|
||||||
import { env, sendRequest } from 'utils'
|
import { isNotEmpty, sendRequest } from 'utils'
|
||||||
|
|
||||||
export type ApiTokenFromServer = { id: string; name: string; createdAt: string }
|
export type ApiTokenFromServer = { id: string; name: string; createdAt: string }
|
||||||
|
|
||||||
@ -25,7 +25,9 @@ export const useApiTokens = ({
|
|||||||
userId ? `/api/users/${userId}/api-tokens` : null,
|
userId ? `/api/users/${userId}/api-tokens` : null,
|
||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
|
? 0
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (error) onError(error)
|
if (error) onError(error)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MemberInWorkspace, WorkspaceInvitation } from 'db'
|
import { MemberInWorkspace, WorkspaceInvitation } from 'db'
|
||||||
import { fetcher } from 'services/utils'
|
import { fetcher } from 'services/utils'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { env, sendRequest } from 'utils'
|
import { isEmpty, sendRequest } from 'utils'
|
||||||
|
|
||||||
export type Member = MemberInWorkspace & {
|
export type Member = MemberInWorkspace & {
|
||||||
name: string | null
|
name: string | null
|
||||||
@ -14,7 +14,7 @@ export const useMembers = ({ workspaceId }: { workspaceId?: string }) => {
|
|||||||
{ members: Member[]; invitations: WorkspaceInvitation[] },
|
{ members: Member[]; invitations: WorkspaceInvitation[] },
|
||||||
Error
|
Error
|
||||||
>(workspaceId ? `/api/workspaces/${workspaceId}/members` : null, fetcher, {
|
>(workspaceId ? `/api/workspaces/${workspaceId}/members` : null, fetcher, {
|
||||||
dedupingInterval: env('E2E_TEST') === 'enabled' ? 0 : undefined,
|
dedupingInterval: isEmpty(process.env.NEXT_PUBLIC_E2E_TEST) ? undefined : 0,
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
members: data?.members,
|
members: data?.members,
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
# Don't edit this file
|
# Don't edit this file
|
||||||
NEXT_PUBLIC_VIEWER_URL=
|
NEXT_PUBLIC_VIEWER_URL=DOCKER_NEXT_PUBLIC_VIEWER_URL
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
export const ErrorPage = ({ error }: { error: Error }) => {
|
export const ErrorPage = ({ error }: { error: Error }) => {
|
||||||
return (
|
return (
|
||||||
@ -12,7 +12,7 @@ export const ErrorPage = ({ error }: { error: Error }) => {
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isEmpty(env('VIEWER_URL')) ? (
|
{isEmpty(process.env.NEXT_PUBLIC_VIEWER_URL) ? (
|
||||||
<>
|
<>
|
||||||
<h1 style={{ fontWeight: 'bold', fontSize: '30px' }}>
|
<h1 style={{ fontWeight: 'bold', fontSize: '30px' }}>
|
||||||
NEXT_PUBLIC_VIEWER_URL is missing
|
NEXT_PUBLIC_VIEWER_URL is missing
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dx": "yarn dev",
|
"dx": "yarn dev",
|
||||||
"dev": "ENVSH_ENV=.env.local bash ../../env.sh next dev -p 3001",
|
"dev": "next dev -p 3001",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
@ -3,7 +3,7 @@ import { NotFoundPage } from 'layouts/NotFoundPage'
|
|||||||
import { PublicTypebot } from 'models'
|
import { PublicTypebot } from 'models'
|
||||||
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
|
||||||
import sanitizeHtml from 'sanitize-html'
|
import sanitizeHtml from 'sanitize-html'
|
||||||
import { env, isDefined, isNotDefined, omit } from 'utils'
|
import { isDefined, isNotDefined, omit } from 'utils'
|
||||||
import { TypebotPage, TypebotPageProps } from '../layouts/TypebotPage'
|
import { TypebotPage, TypebotPageProps } from '../layouts/TypebotPage'
|
||||||
import prisma from '../libs/prisma'
|
import prisma from '../libs/prisma'
|
||||||
|
|
||||||
@ -16,9 +16,9 @@ export const getServerSideProps: GetServerSideProps = async (
|
|||||||
const { host, forwardedHost } = getHost(context.req)
|
const { host, forwardedHost } = getHost(context.req)
|
||||||
try {
|
try {
|
||||||
if (!host) return { props: {} }
|
if (!host) return { props: {} }
|
||||||
const viewerUrls = (env('VIEWER_URL') ?? '').split(',')
|
const viewerUrls = (process.env.NEXT_PUBLIC_VIEWER_URL ?? '').split(',')
|
||||||
const isMatchingViewerUrl =
|
const isMatchingViewerUrl =
|
||||||
env('E2E_TEST') === 'enabled'
|
process.env.NEXT_PUBLIC_E2E_TEST === 'enabled'
|
||||||
? true
|
? true
|
||||||
: viewerUrls.some(
|
: viewerUrls.some(
|
||||||
(url) =>
|
(url) =>
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import Document, {
|
|
||||||
Html,
|
|
||||||
Head,
|
|
||||||
Main,
|
|
||||||
NextScript,
|
|
||||||
DocumentContext,
|
|
||||||
} from 'next/document'
|
|
||||||
|
|
||||||
class MyDocument extends Document {
|
|
||||||
static async getInitialProps(ctx: DocumentContext) {
|
|
||||||
const initialProps = await Document.getInitialProps(ctx)
|
|
||||||
return { ...initialProps }
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Head>
|
|
||||||
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
|
|
||||||
<script src="/__env.js" />
|
|
||||||
</Head>
|
|
||||||
<body>
|
|
||||||
<Main />
|
|
||||||
<NextScript />
|
|
||||||
</body>
|
|
||||||
</Html>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MyDocument
|
|
@ -1,5 +1,5 @@
|
|||||||
import { CollaborationType, Prisma, User, WorkspaceRole } from 'db'
|
import { CollaborationType, Prisma, User, WorkspaceRole } from 'db'
|
||||||
import { env } from 'utils'
|
import { isNotEmpty } from 'utils'
|
||||||
|
|
||||||
const parseWhereFilter = (
|
const parseWhereFilter = (
|
||||||
typebotIds: string[] | string,
|
typebotIds: string[] | string,
|
||||||
@ -20,7 +20,7 @@ const parseWhereFilter = (
|
|||||||
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
id: typeof typebotIds === 'string' ? typebotIds : { in: typebotIds },
|
||||||
workspace:
|
workspace:
|
||||||
(type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
(type === 'read' && user.email === process.env.ADMIN_EMAIL) ||
|
||||||
env('E2E_TEST') === 'enabled'
|
isNotEmpty(process.env.NEXT_PUBLIC_E2E_TEST)
|
||||||
? undefined
|
? undefined
|
||||||
: {
|
: {
|
||||||
members: {
|
members: {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
./env.sh
|
./entrypoint.sh
|
||||||
|
|
||||||
./node_modules/.bin/prisma generate;
|
./node_modules/.bin/prisma generate;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ services:
|
|||||||
image: postgres:13
|
image: postgres:13
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- build_db_data:/var/lib/postgresql/data
|
- db_data:/var/lib/postgresql/data
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_DB=typebot
|
- POSTGRES_DB=typebot
|
||||||
- POSTGRES_PASSWORD=typebot
|
- POSTGRES_PASSWORD=typebot
|
||||||
@ -28,6 +28,7 @@ services:
|
|||||||
- ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
|
- ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
|
||||||
- ADMIN_EMAIL=me@email.com
|
- ADMIN_EMAIL=me@email.com
|
||||||
- NEXTAUTH_URL_INTERNAL=http://host.docker.internal:8080
|
- NEXTAUTH_URL_INTERNAL=http://host.docker.internal:8080
|
||||||
|
- NEXT_PUBLIC_GOOGLE_CLIENT_ID=fnejwkn
|
||||||
typebot-viewer:
|
typebot-viewer:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
@ -42,4 +43,4 @@ services:
|
|||||||
- NEXT_PUBLIC_VIEWER_URL=http://localhost:8081
|
- NEXT_PUBLIC_VIEWER_URL=http://localhost:8081
|
||||||
- ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
|
- ENCRYPTION_SECRET=SgVkYp2s5v8y/B?E(H+MbQeThWmZq4t6
|
||||||
volumes:
|
volumes:
|
||||||
build_db_data:
|
db_data:
|
||||||
|
161
env.sh
161
env.sh
@ -1,161 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# env.sh - Dead-simple .env file reader and generator
|
|
||||||
# Tunghsiao Liu (t@sparanoid.com)
|
|
||||||
#
|
|
||||||
# Inspired by:
|
|
||||||
# - https://github.com/andrewmclagan/react-env
|
|
||||||
# - https://www.freecodecamp.org/news/7f9d42a91d70/
|
|
||||||
# - https://github.com/kunokdev/cra-runtime-environment-variables
|
|
||||||
#
|
|
||||||
# Features:
|
|
||||||
# - Designed to be used for Next.js app inside a Docker container (General
|
|
||||||
# React app should also work)
|
|
||||||
# - Read env file and generate __env.js file for runtime client use
|
|
||||||
# - Merge current environment variables passing to it (Useful for Docker images)
|
|
||||||
# - No dependencies (More like a lite version of react-env). This is important
|
|
||||||
# to keep our container image as small as possible.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# - General usage:
|
|
||||||
# $ ./env.sh
|
|
||||||
#
|
|
||||||
# - Replacing varaible:
|
|
||||||
# $ NEXT_PUBLIC_API_BASE=xxx ./env.sh
|
|
||||||
#
|
|
||||||
# - Enviroment variable not in whitelist will be discarded:
|
|
||||||
# $ BAD_ENV=zzz ./env.sh
|
|
||||||
#
|
|
||||||
# - Change script options:
|
|
||||||
# $ ENVSH_ENV="./.env.staging" ENVSH_OUTPUT="./public/config.js" ./env.sh
|
|
||||||
#
|
|
||||||
# - Use it inside Dockerfile:
|
|
||||||
# RUN chmod +x ./env.sh
|
|
||||||
# ENTRYPOINT ["./env.sh"]
|
|
||||||
#
|
|
||||||
# Debug:
|
|
||||||
# NEXT_PUBLIC_OB_ENV=123_from_fish NEXT_BAD_ENV=zzz NEXT_PUBLIC_OB_TESTNEW=testenv NEXT_PUBLIC_CODE_UPLOAD_SIZE_LIMIT=6666 ./env.sh
|
|
||||||
|
|
||||||
echo -e "env.sh loaded"
|
|
||||||
|
|
||||||
# Config
|
|
||||||
ENVSH_ENV="${ENVSH_ENV:-"./.env.production"}"
|
|
||||||
ENVSH_PREFIX="${ENVSH_PREFIX:-"NEXT_PUBLIC_"}"
|
|
||||||
ENVSH_PREFIX_STRIP="${ENVSH_PREFIX_STRIP:-true}"
|
|
||||||
|
|
||||||
# Can be `window.__env = {` or `const ENV = {` or whatever you want
|
|
||||||
ENVSH_PREPEND="${ENVSH_PREPEND:-"window.__env = {"}"
|
|
||||||
ENVSH_APPEND="${ENVSH_APPEND:-"}"}"
|
|
||||||
ENVSH_OUTPUT="${ENVSH_OUTPUT:-"./public/__env.js"}"
|
|
||||||
|
|
||||||
# Utils
|
|
||||||
__green() {
|
|
||||||
printf '\033[1;31;32m%b\033[0m' "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
__yellow() {
|
|
||||||
printf '\033[1;31;33m%b\033[0m' "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
__red() {
|
|
||||||
printf '\033[1;31;40m%b\033[0m' "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
__info() {
|
|
||||||
printf "%s\n" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
__debug() {
|
|
||||||
ENVSH_VERBOSE="${ENVSH_VERBOSE:-"false"}"
|
|
||||||
if [ "$ENVSH_VERBOSE" == "true" ]; then
|
|
||||||
printf "ENVSH_VERBOSE: %s\n" "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
ENVSH_SED="sed"
|
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
||||||
echo "macOS detected, switching to gsed"
|
|
||||||
|
|
||||||
if command -v gsed >/dev/null 2>&1 ; then
|
|
||||||
__info "$(__green "Found"): $(gsed --version | head -n 1)"
|
|
||||||
else
|
|
||||||
__info "gsed not found, trying to install..."
|
|
||||||
|
|
||||||
if command -v brew >/dev/null 2>&1 ; then
|
|
||||||
__info "$(__green "Found"): $(brew --version | head -n 1)"
|
|
||||||
brew install gnu-sed
|
|
||||||
else
|
|
||||||
__info "$(__red "Homebrew not found, install it first: https://brew.sh/")"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
ENVSH_SED="gsed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Recreate config file
|
|
||||||
rm -f "$ENVSH_OUTPUT"
|
|
||||||
touch "$ENVSH_OUTPUT"
|
|
||||||
|
|
||||||
# Create an array from inline variables
|
|
||||||
matched_envs=$(env | grep ${ENVSH_PREFIX})
|
|
||||||
IFS=$'\n' read -r -d '' -a matched_envs_arr <<< "$matched_envs"
|
|
||||||
__info "Matched inline env:"
|
|
||||||
for matched_env in "${matched_envs_arr[@]}"; do
|
|
||||||
echo $matched_env
|
|
||||||
done
|
|
||||||
|
|
||||||
# Add assignment
|
|
||||||
echo "$ENVSH_PREPEND" >> "$ENVSH_OUTPUT"
|
|
||||||
|
|
||||||
# Check if file exists
|
|
||||||
[[ -f "$ENVSH_ENV" ]] || { echo "$ENVSH_ENV does not exist" ; exit 1 ;}
|
|
||||||
|
|
||||||
# Process .env for runtime client use
|
|
||||||
__info "$(__green "Reading ${ENVSH_ENV}...")"
|
|
||||||
while IFS= read -r line
|
|
||||||
do
|
|
||||||
# Check if this line is a valid environment variable and matches our prefix
|
|
||||||
if printf '%s' "$line" | grep -e "=" | grep -e "$ENVSH_PREFIX"; then
|
|
||||||
|
|
||||||
# Read and apply environment variable if exists
|
|
||||||
# NOTE: <<< here operator not working with `sh`
|
|
||||||
awk -F '=' '{print $1 ": \"" (ENVIRON[$1] ? ENVIRON[$1] : $2) "\","}' \
|
|
||||||
<<< "$line" >> "$ENVSH_OUTPUT"
|
|
||||||
fi
|
|
||||||
done < "$ENVSH_ENV"
|
|
||||||
echo "$ENVSH_APPEND" >> "$ENVSH_OUTPUT"
|
|
||||||
|
|
||||||
# Strip prefix if needed
|
|
||||||
$ENVSH_PREFIX_STRIP && $ENVSH_SED -i'' -e "s~$ENVSH_PREFIX~~g" "$ENVSH_OUTPUT"
|
|
||||||
|
|
||||||
# NOTE: This step is not necessary because variables on pages inside the
|
|
||||||
# Next.js prod server won't be changed. They're already inlined during the
|
|
||||||
# build time.
|
|
||||||
for matched_env in "${matched_envs_arr[@]}"; do
|
|
||||||
echo $matched_env
|
|
||||||
done
|
|
||||||
|
|
||||||
for i in "${!matched_envs_arr[@]}"; do
|
|
||||||
IFS='=' read -ra key_arr <<< "${matched_envs_arr[$i]}"
|
|
||||||
key=${key_arr[0]}
|
|
||||||
|
|
||||||
if [[ "${matched_envs_arr[$i]}" = *"${key}"* ]]; then
|
|
||||||
index="$i"
|
|
||||||
__info "Got index from inline env: ${index}, replacing ${key}"
|
|
||||||
find "$ENVSH_ENV" -type f -exec $ENVSH_SED -i'' \
|
|
||||||
-e "s~$key=.*~${matched_envs_arr[$index]}~g" {} \;
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Print result
|
|
||||||
__debug "$(__green "Done! Final result in ${ENVSH_OUTPUT}:")"
|
|
||||||
__debug "`cat "$ENVSH_OUTPUT"`"
|
|
||||||
|
|
||||||
__debug "$(__green "Done! Modified ${ENVSH_ENV}:")"
|
|
||||||
__debug "`cat "$ENVSH_ENV"`"
|
|
||||||
|
|
||||||
__info "$(__green "env.sh done\n")"
|
|
||||||
|
|
||||||
# Accepting commands (for Docker)
|
|
||||||
exec "$@"
|
|
@ -11,7 +11,7 @@
|
|||||||
"docker:up": "docker compose -f docker-compose.dev.yml up -d",
|
"docker:up": "docker compose -f docker-compose.dev.yml up -d",
|
||||||
"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:prepare": "turbo run build --scope=bot-engine --no-deps --include-dependencies && turbo run build --scope=typebot-js --no-deps",
|
"dev:prepare": "turbo run build --scope=bot-engine --no-deps --include-dependencies && turbo run build --scope=typebot-js --no-deps",
|
||||||
"dev": "yarn docker:up && yarn dev:prepare && NEXT_PUBLIC_E2E_TEST=false turbo run dx --parallel",
|
"dev": "yarn docker:up && yarn dev:prepare && turbo run dx --parallel",
|
||||||
"dev:mocking": "yarn docker:up && NEXT_PUBLIC_E2E_TEST=enabled turbo run dx --parallel",
|
"dev:mocking": "yarn docker:up && NEXT_PUBLIC_E2E_TEST=enabled turbo run dx --parallel",
|
||||||
"build": "yarn docker:up && turbo run build",
|
"build": "yarn docker:up && turbo run build",
|
||||||
"test:builder": "cd apps/builder && yarn test",
|
"test:builder": "cd apps/builder && yarn test",
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
} from 'models'
|
} from 'models'
|
||||||
import { Log } from 'db'
|
import { Log } from 'db'
|
||||||
import { LiteBadge } from './LiteBadge'
|
import { LiteBadge } from './LiteBadge'
|
||||||
import { env, isEmpty } from 'utils'
|
import { isEmpty } from 'utils'
|
||||||
|
|
||||||
export type TypebotViewerProps = {
|
export type TypebotViewerProps = {
|
||||||
typebot: PublicTypebot
|
typebot: PublicTypebot
|
||||||
@ -41,7 +41,7 @@ export type TypebotViewerProps = {
|
|||||||
|
|
||||||
export const TypebotViewer = ({
|
export const TypebotViewer = ({
|
||||||
typebot,
|
typebot,
|
||||||
apiHost = env('VIEWER_URL')?.split(',')[0],
|
apiHost = process.env.NEXT_PUBLIC_VIEWER_URL?.split(',')[0],
|
||||||
isPreview = false,
|
isPreview = false,
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
style,
|
style,
|
||||||
|
@ -243,19 +243,3 @@ export const uploadFiles = async ({
|
|||||||
}
|
}
|
||||||
return urls
|
return urls
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const window: any
|
|
||||||
|
|
||||||
const isBrowser = () => {
|
|
||||||
return Boolean(typeof window !== 'undefined' && window.__env)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const env = (key = ''): string | undefined => {
|
|
||||||
if (isBrowser() && window.__env) {
|
|
||||||
return window.__env[key] === "''" ? undefined : window.__env[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
return process.env['NEXT_PUBLIC_' + key] === "''"
|
|
||||||
? undefined
|
|
||||||
: (process.env['NEXT_PUBLIC_' + key] as string)
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
./env.sh
|
./entrypoint.sh
|
||||||
|
|
||||||
./node_modules/.bin/prisma generate;
|
./node_modules/.bin/prisma generate;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user