Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support deployment in custom subpaths by NEXT_PUBLIC_BASE_PATH #13394

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ NEXT_PUBLIC_TOP_K_MAX_VALUE=10

# The maximum number of tokens for segmentation
NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000

# Configure base path for self-hosting, optional
# NEXT_PUBLIC_BASE_PATH=/custom-dify-sub-path
4 changes: 4 additions & 0 deletions web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ WORKDIR /app/web
COPY --from=packages /app/web/ .
COPY . .

# set base path
ARG NEXT_PUBLIC_BASE_PATH
ENV NEXT_PUBLIC_BASE_PATH=${NEXT_PUBLIC_BASE_PATH}

RUN yarn build


Expand Down
4 changes: 2 additions & 2 deletions web/app/(commonLayout)/apps/AppCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import CustomPopover from '@/app/components/base/popover'
import Divider from '@/app/components/base/divider'
import { getRedirection } from '@/utils/app-redirection'
import { useProviderContext } from '@/context/provider-context'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { BASE_PATH, NEED_REFRESH_APP_LIST_KEY } from '@/config'
import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal'
import EditAppModal from '@/app/components/explore/create-app-modal'
import SwitchAppModal from '@/app/components/app/switch-app-modal'
Expand Down Expand Up @@ -216,7 +216,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
try {
const { installed_apps }: any = await fetchInstalledAppList(app.id) || {}
if (installed_apps?.length > 0)
window.open(`/explore/installed/${installed_apps[0].id}`, '_blank')
window.open(`${BASE_PATH}/explore/installed/${installed_apps[0].id}`, '_blank')
else
throw new Error('No app found in Explore')
}
Expand Down
5 changes: 3 additions & 2 deletions web/app/(commonLayout)/datasets/NewDatasetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RiAddLine,
RiArrowRightLine,
} from '@remixicon/react'
import { BASE_PATH } from '@/config'

const CreateAppCard = forwardRef<HTMLAnchorElement>((_, ref) => {
const { t } = useTranslation()
Expand All @@ -14,7 +15,7 @@ const CreateAppCard = forwardRef<HTMLAnchorElement>((_, ref) => {
<div className='flex flex-col bg-background-default-dimm border-[0.5px] border-components-panel-border rounded-xl
min-h-[160px] transition-all duration-200 ease-in-out'
>
<a ref={ref} className='group flex flex-grow items-start p-4 cursor-pointer' href='/datasets/create'>
<a ref={ref} className='group flex flex-grow items-start p-4 cursor-pointer' href={`${BASE_PATH}/datasets/create`}>
<div className='flex items-center gap-3'>
<div className='w-10 h-10 p-2 flex items-center justify-center border border-dashed border-divider-regular rounded-lg
bg-background-default-lighter group-hover:border-solid group-hover:border-effects-highlight group-hover:bg-background-default-dodge'
Expand All @@ -25,7 +26,7 @@ const CreateAppCard = forwardRef<HTMLAnchorElement>((_, ref) => {
</div>
</a>
<div className='p-4 pt-0 text-text-tertiary system-xs-regular'>{t('dataset.createDatasetIntro')}</div>
<a className='group flex p-4 items-center gap-1 border-t-[0.5px] border-divider-subtle rounded-b-xl cursor-pointer' href='/datasets/connect'>
<a className='group flex p-4 items-center gap-1 border-t-[0.5px] border-divider-subtle rounded-b-xl cursor-pointer' href={`${BASE_PATH}/datasets/connect`}>
<div className='system-xs-medium text-text-tertiary group-hover:text-text-accent'>{t('dataset.connectDataset')}</div>
<RiArrowRightLine className='w-3.5 h-3.5 text-text-tertiary group-hover:text-text-accent' />
</a>
Expand Down
3 changes: 2 additions & 1 deletion web/app/account/delete-account/components/feed-back.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import CustomDialog from '@/app/components/base/dialog'
import Textarea from '@/app/components/base/textarea'
import Toast from '@/app/components/base/toast'
import { logout } from '@/service/common'
import { BASE_PATH } from '@/config'

type DeleteAccountProps = {
onCancel: () => void
Expand All @@ -25,7 +26,7 @@ export default function FeedBack(props: DeleteAccountProps) {
const handleSuccess = useCallback(async () => {
try {
await logout({
url: '/logout',
url: `${BASE_PATH}/logout`,
params: {},
})
localStorage.removeItem('refresh_token')
Expand Down
4 changes: 2 additions & 2 deletions web/app/components/app/app-publisher/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { LeftIndent02 } from '@/app/components/base/icons/src/vender/line/editor
import { FileText } from '@/app/components/base/icons/src/vender/line/files'
import WorkflowToolConfigureButton from '@/app/components/tools/workflow-tool/configure-button'
import type { InputVar } from '@/app/components/workflow/types'
import { appDefaultIconBackground } from '@/config'
import { BASE_PATH, appDefaultIconBackground } from '@/config'

export type AppPublisherProps = {
disabled?: boolean
Expand Down Expand Up @@ -111,7 +111,7 @@ const AppPublisher = ({
try {
const { installed_apps }: any = await fetchInstalledAppList(appDetail?.id) || {}
if (installed_apps?.length > 0)
window.open(`/explore/installed/${installed_apps[0].id}`, '_blank')
window.open(`${BASE_PATH}/explore/installed/${installed_apps[0].id}`, '_blank')
else
throw new Error('No app found in Explore')
}
Expand Down
10 changes: 5 additions & 5 deletions web/app/components/app/create-app-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Textarea from '@/app/components/base/textarea'
import AppIcon from '@/app/components/base/app-icon'
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
import { BubbleTextMod, ChatBot, ListSparkle, Logic } from '@/app/components/base/icons/src/vender/solid/communication'
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { BASE_PATH, NEED_REFRESH_APP_LIST_KEY } from '@/config'
import { getRedirection } from '@/utils/app-redirection'
import FullScreenModal from '@/app/components/base/fullscreen-modal'

Expand Down Expand Up @@ -355,11 +355,11 @@ function AppScreenShot({ mode, show }: { mode: AppMode; show: boolean }) {
'workflow': 'Workflow',
}
return <picture>
<source media="(resolution: 1x)" srcSet={`/screenshots/${theme}/${modeToImageMap[mode]}.png`} />
<source media="(resolution: 2x)" srcSet={`/screenshots/${theme}/${modeToImageMap[mode]}@2x.png`} />
<source media="(resolution: 3x)" srcSet={`/screenshots/${theme}/${modeToImageMap[mode]}@3x.png`} />
<source media="(resolution: 1x)" srcSet={`${BASE_PATH}/screenshots/${theme}/${modeToImageMap[mode]}.png`} />
<source media="(resolution: 2x)" srcSet={`${BASE_PATH}/screenshots/${theme}/${modeToImageMap[mode]}@2x.png`} />
<source media="(resolution: 3x)" srcSet={`${BASE_PATH}/screenshots/${theme}/${modeToImageMap[mode]}@3x.png`} />
<Image className={show ? '' : 'hidden'}
src={`/screenshots/${theme}/${modeToImageMap[mode]}.png`}
src={`${BASE_PATH}/screenshots/${theme}/${modeToImageMap[mode]}.png`}
alt='App Screen Shot'
width={664} height={448} />
</picture>
Expand Down
3 changes: 2 additions & 1 deletion web/app/components/base/file-uploader/pdf-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useHotkeys } from 'react-hotkeys-hook'
import Loading from '@/app/components/base/loading'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import Tooltip from '@/app/components/base/tooltip'
import { BASE_PATH } from '@/config'

type PdfPreviewProps = {
url: string
Expand Down Expand Up @@ -56,7 +57,7 @@ const PdfPreview: FC<PdfPreviewProps> = ({
style={{ transform: `scale(${scale})`, transformOrigin: 'center', scrollbarWidth: 'none', msOverflowStyle: 'none' }}
>
<PdfLoader
workerSrc='/pdf.worker.min.mjs'
workerSrc={`${BASE_PATH}/pdf.worker.min.mjs`}
url={url}
beforeLoad={<div className='flex justify-center items-center h-64'><Loading type='app' /></div>}
>
Expand Down
3 changes: 2 additions & 1 deletion web/app/components/base/logo/logo-embedded-chat-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FC } from 'react'
import { BASE_PATH } from '@/config'

type LogoEmbeddedChatAvatarProps = {
className?: string
Expand All @@ -8,7 +9,7 @@ const LogoEmbeddedChatAvatar: FC<LogoEmbeddedChatAvatarProps> = ({
}) => {
return (
<img
src='/logo/logo-embedded-chat-avatar.png'
src={`${BASE_PATH}/logo/logo-embedded-chat-avatar.png`}
className={`block w-10 h-10 ${className}`}
alt='logo'
/>
Expand Down
3 changes: 2 additions & 1 deletion web/app/components/base/logo/logo-embedded-chat-header.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { FC } from 'react'
import { BASE_PATH } from '@/config'

type LogoEmbeddedChatHeaderProps = {
className?: string
Expand All @@ -9,7 +10,7 @@ const LogoEmbeddedChatHeader: FC<LogoEmbeddedChatHeaderProps> = ({
}) => {
return (
<img
src='/logo/logo-embedded-chat-header.png'
src={`${BASE_PATH}/logo/logo-embedded-chat-header.png`}
className={`block w-auto h-6 ${className}`}
alt='logo'
/>
Expand Down
3 changes: 2 additions & 1 deletion web/app/components/base/logo/logo-site.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { FC } from 'react'
import classNames from '@/utils/classnames'
import { useSelector } from '@/context/app-context'
import { BASE_PATH } from '@/config'

type LogoSiteProps = {
className?: string
Expand All @@ -16,7 +17,7 @@ const LogoSite: FC<LogoSiteProps> = ({
}
})

const src = theme === 'light' ? '/logo/logo-site.png' : `/logo/logo-site-${theme}.png`
const src = theme === 'light' ? `${BASE_PATH}/logo/logo-site.png` : `${BASE_PATH}/logo/logo-site-${theme}.png`
return (
<img
src={src}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows
import { Check } from '@/app/components/base/icons/src/vender/line/general'
import { ToastContext } from '@/app/components/base/toast'
import classNames from '@/utils/classnames'
import { BASE_PATH } from '@/config'

const itemClassName = `
flex items-center px-3 py-2 h-10 cursor-pointer
Expand All @@ -36,7 +37,7 @@ const WorkplaceSelector = () => {
return
await switchWorkspace({ url: '/workspaces/switch', body: { tenant_id } })
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
location.assign(`${location.origin}`)
location.assign(`${location.origin}${BASE_PATH}`)
}
catch (e) {
notify({ type: 'error', message: t('common.provider.saveFailed') })
Expand Down
2 changes: 1 addition & 1 deletion web/app/components/header/nav/nav-selector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const NavSelector = ({ curNav, navs, createText, isApp, onCreate, onLoadmore }:
if (curNav?.id === nav.id)
return
setAppDetail()
router.push(nav.link)
router.push(`${nav.link}`)
}} title={nav.name}>
<div className='relative w-6 h-6 mr-2 rounded-md'>
<AppIcon size='tiny' iconType={nav.icon_type} icon={nav.icon} background={nav.icon_background} imageUrl={nav.icon_url}/>
Expand Down
4 changes: 2 additions & 2 deletions web/app/components/tools/add-tool-modal/tools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Empty from '@/app/components/tools/add-tool-modal/empty'
import type { Tool } from '@/app/components/tools/types'
import { CollectionType } from '@/app/components/tools/types'
import type { AgentTool } from '@/types/app'
import { MAX_TOOLS_NUM } from '@/config'
import { BASE_PATH, MAX_TOOLS_NUM } from '@/config'

type ToolsProps = {
showWorkflowEmpty: boolean
Expand Down Expand Up @@ -53,7 +53,7 @@ const Blocks = ({
>
<div className='flex items-center justify-between w-full pl-3 pr-1 h-[22px] text-xs font-medium text-gray-500'>
{toolWithProvider.label[language]}
<a className='hidden cursor-pointer items-center group-hover:flex' href={`/tools?category=${toolWithProvider.type}`} target='_blank'>{t('tools.addToolModal.manageInTools')}<ArrowUpRight className='ml-0.5 w-3 h-3' /></a>
<a className='hidden cursor-pointer items-center group-hover:flex' href={`${BASE_PATH}/tools?category=${toolWithProvider.type}`} target='_blank'>{t('tools.addToolModal.manageInTools')}<ArrowUpRight className='ml-0.5 w-3 h-3' /></a>
</div>
{list.map((tool) => {
const labelContent = (() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import {
getFilesInLogs,
} from '@/app/components/base/file-uploader/utils'
import { BASE_PATH } from '@/config'

import './style.css'

// load file from local instead of cdn https://github.com/suren-atoyan/monaco-react/issues/482
loader.config({ paths: { vs: '/vs' } })
loader.config({ paths: { vs: `${BASE_PATH}/vs` } })

const CODE_EDITOR_LINE_HEIGHT = 18

Expand Down
3 changes: 2 additions & 1 deletion web/app/forgot-password/ChangePasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Button from '@/app/components/base/button'
import { changePasswordWithToken, verifyForgotPasswordToken } from '@/service/common'
import Toast from '@/app/components/base/toast'
import Loading from '@/app/components/base/loading'
import { BASE_PATH } from '@/config'

const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/

Expand Down Expand Up @@ -163,7 +164,7 @@ const ChangePasswordForm = () => {
</div>
<div className="w-full mx-auto mt-6">
<Button variant='primary' className='w-full'>
<a href="/signin">{t('login.passwordChanged')}</a>
<a href={`${BASE_PATH}/signin`}>{t('login.passwordChanged')}</a>
</Button>
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions web/app/install/installForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { zodResolver } from '@hookform/resolvers/zod'
import Loading from '../components/base/loading'
import classNames from '@/utils/classnames'
import Button from '@/app/components/base/button'
import { BASE_PATH } from '@/config'

import { fetchInitValidateStatus, fetchSetupStatus, setup } from '@/service/common'
import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common'
Expand Down Expand Up @@ -66,12 +67,12 @@ const InstallForm = () => {
fetchSetupStatus().then((res: SetupStatusResponse) => {
if (res.step === 'finished') {
localStorage.setItem('setup_status', 'finished')
window.location.href = '/signin'
window.location.href = `${BASE_PATH}/signin`
}
else {
fetchInitValidateStatus().then((res: InitValidateStatusResponse) => {
if (res.status === 'not_started')
window.location.href = '/init'
window.location.href = `${BASE_PATH}/init`
})
}
setLoading(false)
Expand Down
2 changes: 2 additions & 0 deletions web/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getLocaleOnServer } from '@/i18n/server'
import { TanstackQueryIniter } from '@/context/query-client'
import './styles/globals.css'
import './styles/markdown.scss'
import { BASE_PATH } from '@/config'

export const metadata = {
title: 'Dify',
Expand Down Expand Up @@ -33,6 +34,7 @@ const LocaleLayout = ({
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<link rel="icon" type="image/x-icon" href={`${BASE_PATH}/favicon.ico`} />
</head>
<body
className="h-full select-auto color-scheme"
Expand Down
2 changes: 2 additions & 0 deletions web/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,5 @@ export const TEXT_GENERATION_TIMEOUT_MS = textGenerationTimeoutMs
export const DISABLE_UPLOAD_IMAGE_AS_ICON = process.env.NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON === 'true'

export const FULL_DOC_PREVIEW_LENGTH = 50

export const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || ''
1 change: 1 addition & 0 deletions web/docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ export NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS=${TEXT_GENERATION_TIMEOUT_MS}
export NEXT_PUBLIC_CSP_WHITELIST=${CSP_WHITELIST}
export NEXT_PUBLIC_TOP_K_MAX_VALUE=${TOP_K_MAX_VALUE}
export NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH}
export NEXT_PUBLIC_BASE_PATH=${NEXT_PUBLIC_BASE_PATH}

pm2 start ./pm2.json --no-daemon
3 changes: 2 additions & 1 deletion web/hooks/use-tab-searchparams.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { usePathname, useSearchParams } from 'next/navigation'
import { useState } from 'react'
import { BASE_PATH } from '@/config'

type UseTabSearchParamsOptions = {
defaultTab: string
Expand Down Expand Up @@ -36,7 +37,7 @@ export const useTabSearchParams = ({
setTab(newActiveTab)
if (disableSearchParams)
return
history[`${routingBehavior}State`](null, '', `${pathName}?${searchParamName}=${newActiveTab}`)
history[`${routingBehavior}State`](null, '', `${BASE_PATH}${pathName}?${searchParamName}=${newActiveTab}`)
}

return [activeTab, setActiveTab] as const
Expand Down
1 change: 1 addition & 0 deletions web/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const nextConfig = {
ignoreBuildErrors: true,
},
reactStrictMode: true,
basePath: process.env.NEXT_PUBLIC_BASE_PATH || '',
async redirects() {
return [
{
Expand Down