Co-authored-by: qingguo <qingguo@lexin.com>tags/1.4.1
| @@ -6,12 +6,10 @@ NEXT_PUBLIC_EDITION=SELF_HOSTED | |||
| # different from api or web app domain. | |||
| # example: http://cloud.dify.ai/console/api | |||
| NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api | |||
| NEXT_PUBLIC_WEB_PREFIX=http://localhost:3000 | |||
| # The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from | |||
| # console or api domain. | |||
| # example: http://udify.app/api | |||
| NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api | |||
| NEXT_PUBLIC_PUBLIC_WEB_PREFIX=http://localhost:3000 | |||
| # The API PREFIX for MARKETPLACE | |||
| NEXT_PUBLIC_MARKETPLACE_API_PREFIX=https://marketplace.dify.ai/api/v1 | |||
| # The URL for MARKETPLACE | |||
| @@ -31,12 +31,10 @@ NEXT_PUBLIC_EDITION=SELF_HOSTED | |||
| # different from api or web app domain. | |||
| # example: http://cloud.dify.ai/console/api | |||
| NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api | |||
| NEXT_PUBLIC_WEB_PREFIX=http://localhost:3000 | |||
| # The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from | |||
| # console or api domain. | |||
| # example: http://udify.app/api | |||
| NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api | |||
| NEXT_PUBLIC_PUBLIC_WEB_PREFIX=http://localhost:3000 | |||
| # SENTRY | |||
| NEXT_PUBLIC_SENTRY_DSN= | |||
| @@ -16,7 +16,7 @@ import AppsContext, { useAppContext } from '@/context/app-context' | |||
| import type { HtmlContentProps } from '@/app/components/base/popover' | |||
| import CustomPopover from '@/app/components/base/popover' | |||
| import Divider from '@/app/components/base/divider' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import { getRedirection } from '@/utils/app-redirection' | |||
| import { useProviderContext } from '@/context/provider-context' | |||
| import { NEED_REFRESH_APP_LIST_KEY } from '@/config' | |||
| @@ -217,7 +217,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { | |||
| try { | |||
| const { installed_apps }: any = await fetchInstalledAppList(app.id) || {} | |||
| if (installed_apps?.length > 0) | |||
| window.open(`${WEB_PREFIX}/explore/installed/${installed_apps[0].id}`, '_blank') | |||
| window.open(`${basePath}/explore/installed/${installed_apps[0].id}`, '_blank') | |||
| else | |||
| throw new Error('No app found in Explore') | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| 'use client' | |||
| import { useTranslation } from 'react-i18next' | |||
| import Link from 'next/link' | |||
| import { basePath } from '@/utils/var' | |||
| import { | |||
| RiAddLine, | |||
| RiArrowRightLine, | |||
| @@ -18,7 +18,7 @@ const CreateAppCard = ( | |||
| <div className='bg-background-default-dimm flex min-h-[160px] flex-col rounded-xl border-[0.5px] | |||
| border-components-panel-border transition-all duration-200 ease-in-out' | |||
| > | |||
| <Link ref={ref} className='group flex grow cursor-pointer items-start p-4' href={'/datasets/create'}> | |||
| <a ref={ref} className='group flex grow cursor-pointer items-start p-4' href={`${basePath}/datasets/create`}> | |||
| <div className='flex items-center gap-3'> | |||
| <div className='flex h-10 w-10 items-center justify-center rounded-lg border border-dashed border-divider-regular bg-background-default-lighter | |||
| p-2 group-hover:border-solid group-hover:border-effects-highlight group-hover:bg-background-default-dodge' | |||
| @@ -27,12 +27,12 @@ const CreateAppCard = ( | |||
| </div> | |||
| <div className='system-md-semibold text-text-secondary group-hover:text-text-accent'>{t('dataset.createDataset')}</div> | |||
| </div> | |||
| </Link> | |||
| </a> | |||
| <div className='system-xs-regular p-4 pt-0 text-text-tertiary'>{t('dataset.createDatasetIntro')}</div> | |||
| <Link className='group flex cursor-pointer items-center gap-1 rounded-b-xl border-t-[0.5px] border-divider-subtle p-4' href={'datasets/connect'}> | |||
| <a className='group flex cursor-pointer items-center gap-1 rounded-b-xl border-t-[0.5px] border-divider-subtle p-4' href={`${basePath}/datasets/connect`}> | |||
| <div className='system-xs-medium text-text-tertiary group-hover:text-text-accent'>{t('dataset.connectDataset')}</div> | |||
| <RiArrowRightLine className='h-3.5 w-3.5 text-text-tertiary group-hover:text-text-accent' /> | |||
| </Link> | |||
| </a> | |||
| </div> | |||
| ) | |||
| } | |||
| @@ -24,7 +24,7 @@ import { | |||
| PortalToFollowElemContent, | |||
| PortalToFollowElemTrigger, | |||
| } from '@/app/components/base/portal-to-follow-elem' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import { fetchInstalledAppList } from '@/service/explore' | |||
| import EmbeddedModal from '@/app/components/app/overview/embedded' | |||
| import { useStore as useAppStore } from '@/app/components/app/store' | |||
| @@ -76,7 +76,7 @@ const AppPublisher = ({ | |||
| const appDetail = useAppStore(state => state.appDetail) | |||
| const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {} | |||
| const appMode = (appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow') ? 'chat' : appDetail.mode | |||
| const appURL = `${appBaseURL}/${appMode}/${accessToken}` | |||
| const appURL = `${appBaseURL}${basePath}/${appMode}/${accessToken}` | |||
| const isChatApp = ['chat', 'agent-chat', 'completion'].includes(appDetail?.mode || '') | |||
| const language = useGetLanguage() | |||
| @@ -121,7 +121,7 @@ const AppPublisher = ({ | |||
| try { | |||
| const { installed_apps }: any = await fetchInstalledAppList(appDetail?.id) || {} | |||
| if (installed_apps?.length > 0) | |||
| window.open(`${WEB_PREFIX}/explore/installed/${installed_apps[0].id}`, '_blank') | |||
| window.open(`${basePath}/explore/installed/${installed_apps[0].id}`, '_blank') | |||
| else | |||
| throw new Error('No app found in Explore') | |||
| } | |||
| @@ -14,6 +14,7 @@ import Loading from '@/app/components/base/loading' | |||
| import Badge from '@/app/components/base/badge' | |||
| import { useKnowledge } from '@/hooks/use-knowledge' | |||
| import cn from '@/utils/classnames' | |||
| import { basePath } from '@/utils/var' | |||
| export type ISelectDataSetProps = { | |||
| isShow: boolean | |||
| @@ -111,7 +112,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({ | |||
| }} | |||
| > | |||
| <span className='text-text-tertiary'>{t('appDebug.feature.dataSet.noDataSet')}</span> | |||
| <Link href={'/datasets/create'} className='font-normal text-text-accent'>{t('appDebug.feature.dataSet.toCreate')}</Link> | |||
| <Link href={`${basePath}/datasets/create`} className='font-normal text-text-accent'>{t('appDebug.feature.dataSet.toCreate')}</Link> | |||
| </div> | |||
| )} | |||
| @@ -14,7 +14,7 @@ import type { AppIconSelection } from '../../base/app-icon-picker' | |||
| import Button from '@/app/components/base/button' | |||
| import Divider from '@/app/components/base/divider' | |||
| import cn from '@/utils/classnames' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import AppsContext, { useAppContext } from '@/context/app-context' | |||
| import { useProviderContext } from '@/context/provider-context' | |||
| import { ToastContext } from '@/app/components/base/toast' | |||
| @@ -353,11 +353,11 @@ function AppScreenShot({ mode, show }: { mode: AppMode; show: boolean }) { | |||
| 'workflow': 'Workflow', | |||
| } | |||
| return <picture> | |||
| <source media="(resolution: 1x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}.png`} /> | |||
| <source media="(resolution: 2x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}@2x.png`} /> | |||
| <source media="(resolution: 3x)" srcSet={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}@3x.png`} /> | |||
| <source media="(resolution: 1x)" srcSet={`${basePath}/screenshots/${theme}/${modeToImageMap[mode]}.png`} /> | |||
| <source media="(resolution: 2x)" srcSet={`${basePath}/screenshots/${theme}/${modeToImageMap[mode]}@2x.png`} /> | |||
| <source media="(resolution: 3x)" srcSet={`${basePath}/screenshots/${theme}/${modeToImageMap[mode]}@3x.png`} /> | |||
| <Image className={show ? '' : 'hidden'} | |||
| src={`${WEB_PREFIX}/screenshots/${theme}/${modeToImageMap[mode]}.png`} | |||
| src={`${basePath}/screenshots/${theme}/${modeToImageMap[mode]}.png`} | |||
| alt='App Screen Shot' | |||
| width={664} height={448} /> | |||
| </picture> | |||
| @@ -7,6 +7,7 @@ import { usePathname } from 'next/navigation' | |||
| import { useDebounce } from 'ahooks' | |||
| import { omit } from 'lodash-es' | |||
| import dayjs from 'dayjs' | |||
| import { basePath } from '@/utils/var' | |||
| import { Trans, useTranslation } from 'react-i18next' | |||
| import List from './list' | |||
| import Filter, { TIME_PERIOD_MAPPING } from './filter' | |||
| @@ -109,7 +110,7 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => { | |||
| ? <Loading type='app' /> | |||
| : total > 0 | |||
| ? <List logs={isChatMode ? chatConversations : completionConversations} appDetail={appDetail} onRefresh={isChatMode ? mutateChatList : mutateCompletionList} /> | |||
| : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} /> | |||
| : <EmptyElement appUrl={`${appDetail.site.app_base_url}${basePath}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} /> | |||
| } | |||
| {/* Show Pagination only if the total is more than the limit */} | |||
| {(total && total > APP_PAGE_LIMIT) | |||
| @@ -17,6 +17,7 @@ import type { ConfigParams } from './settings' | |||
| import Tooltip from '@/app/components/base/tooltip' | |||
| import AppBasic from '@/app/components/app-sidebar/basic' | |||
| import { asyncRunSafe, randomString } from '@/utils' | |||
| import { basePath } from '@/utils/var' | |||
| import Button from '@/app/components/base/button' | |||
| import Switch from '@/app/components/base/switch' | |||
| import Divider from '@/app/components/base/divider' | |||
| @@ -88,7 +89,7 @@ function AppCard({ | |||
| const runningStatus = isApp ? appInfo.enable_site : appInfo.enable_api | |||
| const { app_base_url, access_token } = appInfo.site ?? {} | |||
| const appMode = (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') ? 'chat' : appInfo.mode | |||
| const appUrl = `${app_base_url}/${appMode}/${access_token}` | |||
| const appUrl = `${app_base_url}${basePath}/${appMode}/${access_token}` | |||
| const apiUrl = appInfo?.api_base_url | |||
| const genClickFuncByName = (opName: string) => { | |||
| @@ -13,6 +13,7 @@ import { IS_CE_EDITION } from '@/config' | |||
| import type { SiteInfo } from '@/models/share' | |||
| import { useThemeContext } from '@/app/components/base/chat/embedded-chatbot/theme/theme-context' | |||
| import ActionButton from '@/app/components/base/action-button' | |||
| import { basePath } from '@/utils/var' | |||
| import cn from '@/utils/classnames' | |||
| type Props = { | |||
| @@ -28,7 +29,7 @@ const OPTION_MAP = { | |||
| iframe: { | |||
| getContent: (url: string, token: string) => | |||
| `<iframe | |||
| src="${url}/chatbot/${token}" | |||
| src="${url}${basePath}/chatbot/${token}" | |||
| style="width: 100%; height: 100%; min-height: 700px" | |||
| frameborder="0" | |||
| allow="microphone"> | |||
| @@ -43,7 +44,7 @@ const OPTION_MAP = { | |||
| isDev: true` | |||
| : ''}${IS_CE_EDITION | |||
| ? `, | |||
| baseUrl: '${url}'` | |||
| baseUrl: '${url}${basePath}'` | |||
| : ''}, | |||
| systemVariables: { | |||
| // user_id: 'YOU CAN DEFINE USER ID HERE', | |||
| @@ -52,7 +53,7 @@ const OPTION_MAP = { | |||
| } | |||
| </script> | |||
| <script | |||
| src="${url}/embed.min.js" | |||
| src="${url}${basePath}/embed.min.js" | |||
| id="${token}" | |||
| defer> | |||
| </script> | |||
| @@ -67,7 +68,7 @@ const OPTION_MAP = { | |||
| </style>`, | |||
| }, | |||
| chromePlugin: { | |||
| getContent: (url: string, token: string) => `ChatBot URL: ${url}/chatbot/${token}`, | |||
| getContent: (url: string, token: string) => `ChatBot URL: ${url}${basePath}/chatbot/${token}`, | |||
| }, | |||
| } | |||
| const prefixEmbedded = 'appOverview.overview.appInfo.embedded' | |||
| @@ -11,6 +11,7 @@ import timezone from 'dayjs/plugin/timezone' | |||
| import { Trans, useTranslation } from 'react-i18next' | |||
| import Link from 'next/link' | |||
| import List from './list' | |||
| import { basePath } from '@/utils/var' | |||
| import Filter, { TIME_PERIOD_MAPPING } from './filter' | |||
| import Pagination from '@/app/components/base/pagination' | |||
| import Loading from '@/app/components/base/loading' | |||
| @@ -100,7 +101,7 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => { | |||
| ? <Loading type='app' /> | |||
| : total > 0 | |||
| ? <List logs={workflowLogs} appDetail={appDetail} onRefresh={mutate} /> | |||
| : <EmptyElement appUrl={`${appDetail.site.app_base_url}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} /> | |||
| : <EmptyElement appUrl={`${appDetail.site.app_base_url}${basePath}/${getWebAppType(appDetail.mode)}/${appDetail.site.access_token}`} /> | |||
| } | |||
| {/* Show Pagination only if the total is more than the limit */} | |||
| {(total && total > APP_PAGE_LIMIT) | |||
| @@ -1,8 +1,8 @@ | |||
| 'use client' | |||
| import type { FC } from 'react' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import classNames from '@/utils/classnames' | |||
| import useTheme from '@/hooks/use-theme' | |||
| import { basePath } from '@/utils/var' | |||
| export type LogoStyle = 'default' | 'monochromeWhite' | |||
| @@ -35,7 +35,7 @@ const DifyLogo: FC<DifyLogoProps> = ({ | |||
| return ( | |||
| <img | |||
| src={`${WEB_PREFIX}${logoPathMap[themedStyle]}`} | |||
| src={`${basePath}${logoPathMap[themedStyle]}`} | |||
| className={classNames('block object-contain', logoSizeMap[size], className)} | |||
| alt='Dify logo' | |||
| /> | |||
| @@ -1,5 +1,5 @@ | |||
| import type { FC } from 'react' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| type LogoEmbeddedChatAvatarProps = { | |||
| className?: string | |||
| @@ -9,7 +9,7 @@ const LogoEmbeddedChatAvatar: FC<LogoEmbeddedChatAvatarProps> = ({ | |||
| }) => { | |||
| return ( | |||
| <img | |||
| src={`${WEB_PREFIX}/logo/logo-embedded-chat-avatar.png`} | |||
| src={`${basePath}/logo/logo-embedded-chat-avatar.png`} | |||
| className={`block h-10 w-10 ${className}`} | |||
| alt='logo' | |||
| /> | |||
| @@ -1,6 +1,6 @@ | |||
| import classNames from '@/utils/classnames' | |||
| import type { FC } from 'react' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| type LogoEmbeddedChatHeaderProps = { | |||
| className?: string | |||
| @@ -14,7 +14,7 @@ const LogoEmbeddedChatHeader: FC<LogoEmbeddedChatHeaderProps> = ({ | |||
| <source media="(resolution: 2x)" srcSet='/logo/logo-embedded-chat-header@2x.png' /> | |||
| <source media="(resolution: 3x)" srcSet='/logo/logo-embedded-chat-header@3x.png' /> | |||
| <img | |||
| src={`${WEB_PREFIX}/logo/logo-embedded-chat-header.png`} | |||
| src={`${basePath}/logo/logo-embedded-chat-header.png`} | |||
| alt='logo' | |||
| className={classNames('block h-6 w-auto', className)} | |||
| /> | |||
| @@ -0,0 +1,22 @@ | |||
| 'use client' | |||
| import type { FC } from 'react' | |||
| import { basePath } from '@/utils/var' | |||
| import classNames from '@/utils/classnames' | |||
| type LogoSiteProps = { | |||
| className?: string | |||
| } | |||
| const LogoSite: FC<LogoSiteProps> = ({ | |||
| className, | |||
| }) => { | |||
| return ( | |||
| <img | |||
| src={`${basePath}/logo/logo.png`} | |||
| className={classNames('block w-[22.651px] h-[24.5px]', className)} | |||
| alt='logo' | |||
| /> | |||
| ) | |||
| } | |||
| export default LogoSite | |||
| @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next' | |||
| import { Menu, MenuButton, MenuItems, Transition } from '@headlessui/react' | |||
| import { RiArrowDownSLine } from '@remixicon/react' | |||
| import cn from '@/utils/classnames' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import PlanBadge from '@/app/components/header/plan-badge' | |||
| import { switchWorkspace } from '@/service/common' | |||
| import { useWorkspacesContext } from '@/context/workspace-context' | |||
| @@ -23,7 +23,7 @@ const WorkplaceSelector = () => { | |||
| return | |||
| await switchWorkspace({ url: '/workspaces/switch', body: { tenant_id } }) | |||
| notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) | |||
| location.assign(WEB_PREFIX) | |||
| location.assign(`${location.origin}${basePath}`) | |||
| } | |||
| catch { | |||
| notify({ type: 'error', message: t('common.provider.saveFailed') }) | |||
| @@ -2,7 +2,6 @@ | |||
| import cn from '@/utils/classnames' | |||
| import Modal from '@/app/components/base/modal' | |||
| import Input from '@/app/components/base/input' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { useState } from 'react' | |||
| import { useContext } from 'use-context-selector' | |||
| @@ -34,7 +33,7 @@ const EditWorkspaceModal = ({ | |||
| }, | |||
| }) | |||
| notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) | |||
| location.assign(WEB_PREFIX) | |||
| location.assign(`${location.origin}`) | |||
| } | |||
| catch { | |||
| notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) | |||
| @@ -1,5 +1,6 @@ | |||
| import type { FC } from 'react' | |||
| import type { ModelProvider } from '../declarations' | |||
| import { basePath } from '@/utils/var' | |||
| import { useLanguage } from '../hooks' | |||
| import { Openai } from '@/app/components/base/icons/src/vender/other' | |||
| import { AnthropicDark, AnthropicLight } from '@/app/components/base/icons/src/public/llm' | |||
| @@ -40,7 +41,7 @@ const ProviderIcon: FC<ProviderIconProps> = ({ | |||
| <div className={cn('inline-flex items-center gap-2', className)}> | |||
| <img | |||
| alt='provider-icon' | |||
| src={renderI18nObject(provider.icon_small, language)} | |||
| src={basePath + renderI18nObject(provider.icon_small, language)} | |||
| className='h-6 w-6' | |||
| /> | |||
| <div className='system-md-semibold text-text-primary'> | |||
| @@ -14,6 +14,7 @@ import Nav from '../nav' | |||
| import type { NavItem } from '../nav/nav-selector' | |||
| import { fetchDatasetDetail, fetchDatasets } from '@/service/datasets' | |||
| import type { DataSetListResponse } from '@/models/datasets' | |||
| import { basePath } from '@/utils/var' | |||
| const getKey = (pageIndex: number, previousPageData: DataSetListResponse) => { | |||
| if (!pageIndex || previousPageData.has_more) | |||
| @@ -56,7 +57,7 @@ const DatasetNav = () => { | |||
| icon_background: dataset.icon_background, | |||
| })) as NavItem[]} | |||
| createText={t('common.menus.newDataset')} | |||
| onCreate={() => router.push('/datasets/create')} | |||
| onCreate={() => router.push(`${basePath}/datasets/create`)} | |||
| onLoadmore={handleLoadmore} | |||
| /> | |||
| ) | |||
| @@ -2,7 +2,7 @@ import { | |||
| memo, | |||
| useCallback, | |||
| } from 'react' | |||
| import Link from 'next/link' | |||
| import { basePath } from '@/utils/var' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { | |||
| RiAddLine, | |||
| @@ -54,7 +54,7 @@ const Blocks = ({ | |||
| > | |||
| <div className='flex h-[22px] w-full items-center justify-between pl-3 pr-1 text-xs font-medium text-gray-500'> | |||
| {toolWithProvider.label[language]} | |||
| <Link 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 h-3 w-3' /></Link> | |||
| <a className='hidden cursor-pointer items-center group-hover:flex' href={`${basePath}/tools?category=${toolWithProvider.type}`} target='_blank'>{t('tools.addToolModal.manageInTools')}<ArrowUpRight className='ml-0.5 h-3 w-3' /></a> | |||
| </div> | |||
| {list.map((tool) => { | |||
| const labelContent = (() => { | |||
| @@ -6,7 +6,7 @@ import { | |||
| RiCloseLine, | |||
| } from '@remixicon/react' | |||
| import { AuthHeaderPrefix, AuthType, CollectionType } from '../types' | |||
| import Link from 'next/link' | |||
| import { basePath } from '@/utils/var' | |||
| import type { Collection, CustomCollectionBackend, Tool, WorkflowToolProviderRequest, WorkflowToolProviderResponse } from '../types' | |||
| import ToolItem from './tool-item' | |||
| import cn from '@/utils/classnames' | |||
| @@ -279,10 +279,10 @@ const ProviderDetail = ({ | |||
| variant='primary' | |||
| className={cn('my-3 w-[183px] shrink-0')} | |||
| > | |||
| <Link className='flex items-center' href={`/app/${(customCollection as WorkflowToolProviderResponse).workflow_app_id}/workflow`} rel='noreferrer' target='_blank'> | |||
| <a className='flex items-center' href={`${basePath}/app/${(customCollection as WorkflowToolProviderResponse).workflow_app_id}/workflow`} rel='noreferrer' target='_blank'> | |||
| <div className='system-sm-medium'>{t('tools.openInStudio')}</div> | |||
| <LinkExternal02 className='ml-1 h-4 w-4' /> | |||
| </Link> | |||
| </a> | |||
| </Button> | |||
| <Button | |||
| className={cn('my-3 w-[183px] shrink-0')} | |||
| @@ -3,7 +3,6 @@ import type { FC } from 'react' | |||
| import Editor, { loader } from '@monaco-editor/react' | |||
| import React, { useEffect, useMemo, useRef, useState } from 'react' | |||
| import Base from '../base' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import cn from '@/utils/classnames' | |||
| import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' | |||
| import { | |||
| @@ -13,9 +12,10 @@ import { Theme } from '@/types/app' | |||
| import useTheme from '@/hooks/use-theme' | |||
| import './style.css' | |||
| import { noop } from 'lodash-es' | |||
| import { basePath } from '@/utils/var' | |||
| // load file from local instead of cdn https://github.com/suren-atoyan/monaco-react/issues/482 | |||
| loader.config({ paths: { vs: `${WEB_PREFIX}/vs` } }) | |||
| loader.config({ paths: { vs: `${basePath}/vs` } }) | |||
| const CODE_EDITOR_LINE_HEIGHT = 18 | |||
| @@ -112,7 +112,7 @@ const IterationResultPanel: FC<Props> = ({ | |||
| 'transition-all duration-200', | |||
| expandedIterations[index] | |||
| ? 'opacity-100' | |||
| : 'max-h-0 overflow-hidden opacity-0', | |||
| : 'max-h-0 opacity-0 overflow-hidden', | |||
| )}> | |||
| <TracingPanel | |||
| list={iteration} | |||
| @@ -118,7 +118,7 @@ const LoopResultPanel: FC<Props> = ({ | |||
| 'transition-all duration-200', | |||
| expandedLoops[index] | |||
| ? 'opacity-100' | |||
| : 'max-h-0 overflow-hidden opacity-0', | |||
| : 'max-h-0 opacity-0 overflow-hidden', | |||
| )}> | |||
| { | |||
| loopVariableMap?.[index] && ( | |||
| @@ -85,7 +85,7 @@ const LoopResultPanel: FC<Props> = ({ | |||
| 'transition-all duration-200', | |||
| expandedLoops[index] | |||
| ? 'opacity-100' | |||
| : 'max-h-0 overflow-hidden opacity-0', | |||
| : 'max-h-0 opacity-0 overflow-hidden', | |||
| )}> | |||
| <TracingPanel | |||
| list={loop} | |||
| @@ -3,7 +3,7 @@ import { useCallback, useState } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
| import useSWR from 'swr' | |||
| import { useSearchParams } from 'next/navigation' | |||
| import Link from 'next/link' | |||
| import { basePath } from '@/utils/var' | |||
| import cn from 'classnames' | |||
| import { CheckCircleIcon } from '@heroicons/react/24/solid' | |||
| import Input from '../components/base/input' | |||
| @@ -164,7 +164,7 @@ const ChangePasswordForm = () => { | |||
| </div> | |||
| <div className="mx-auto mt-6 w-full"> | |||
| <Button variant='primary' className='w-full'> | |||
| <Link href={'/signin'}>{t('login.passwordChanged')}</Link> | |||
| <a href={`${basePath}/signin`}>{t('login.passwordChanged')}</a> | |||
| </Button> | |||
| </div> | |||
| </div> | |||
| @@ -10,7 +10,7 @@ import { zodResolver } from '@hookform/resolvers/zod' | |||
| import Loading from '../components/base/loading' | |||
| import Input from '../components/base/input' | |||
| import Button from '@/app/components/base/button' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import { | |||
| fetchInitValidateStatus, | |||
| @@ -71,7 +71,7 @@ const ForgotPasswordForm = () => { | |||
| fetchSetupStatus().then(() => { | |||
| fetchInitValidateStatus().then((res: InitValidateStatusResponse) => { | |||
| if (res.status === 'not_started') | |||
| window.location.href = `${WEB_PREFIX}/init` | |||
| window.location.href = `${basePath}/init` | |||
| }) | |||
| setLoading(false) | |||
| @@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation' | |||
| import Toast from '../components/base/toast' | |||
| import Loading from '../components/base/loading' | |||
| import Button from '@/app/components/base/button' | |||
| import { WEB_PREFIX } from '@/config' | |||
| import { basePath } from '@/utils/var' | |||
| import { fetchInitValidateStatus, initValidate } from '@/service/common' | |||
| import type { InitValidateStatusResponse } from '@/models/common' | |||
| @@ -42,7 +42,7 @@ const InitPasswordPopup = () => { | |||
| useEffect(() => { | |||
| fetchInitValidateStatus().then((res: InitValidateStatusResponse) => { | |||
| if (res.status === 'finished') | |||
| window.location.href = `${WEB_PREFIX}/install` | |||
| window.location.href = `${basePath}/install` | |||
| else | |||
| setLoading(false) | |||
| }) | |||
| @@ -39,9 +39,7 @@ const LocaleLayout = async ({ | |||
| <body | |||
| className="color-scheme h-full select-auto" | |||
| data-api-prefix={process.env.NEXT_PUBLIC_API_PREFIX} | |||
| data-web-prefix={process.env.NEXT_PUBLIC_WEB_PREFIX} | |||
| data-pubic-api-prefix={process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX} | |||
| data-pubic-web-prefix={process.env.NEXT_PUBLIC_PUBLIC_WEB_PREFIX} | |||
| data-marketplace-api-prefix={process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX} | |||
| data-marketplace-url-prefix={process.env.NEXT_PUBLIC_MARKETPLACE_URL_PREFIX} | |||
| data-public-edition={process.env.NEXT_PUBLIC_EDITION} | |||
| @@ -3,23 +3,14 @@ import { AgentStrategy } from '@/types/app' | |||
| import { PromptRole } from '@/models/debug' | |||
| export let apiPrefix = '' | |||
| export let webPrefix = '' | |||
| export let publicApiPrefix = '' | |||
| export let publicWebPrefix = '' | |||
| export let marketplaceApiPrefix = '' | |||
| export let marketplaceUrlPrefix = '' | |||
| // NEXT_PUBLIC_API_PREFIX=/console/api NEXT_PUBLIC_PUBLIC_API_PREFIX=/api npm run start | |||
| if ( | |||
| process.env.NEXT_PUBLIC_API_PREFIX | |||
| && process.env.NEXT_PUBLIC_WEB_PREFIX | |||
| && process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX | |||
| && process.env.NEXT_PUBLIC_PUBLIC_WEB_PREFIX | |||
| ) { | |||
| if (process.env.NEXT_PUBLIC_API_PREFIX && process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX) { | |||
| apiPrefix = process.env.NEXT_PUBLIC_API_PREFIX | |||
| webPrefix = process.env.NEXT_PUBLIC_WEB_PREFIX | |||
| publicApiPrefix = process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX | |||
| publicWebPrefix = process.env.NEXT_PUBLIC_PUBLIC_WEB_PREFIX | |||
| } | |||
| else if ( | |||
| globalThis.document?.body?.getAttribute('data-api-prefix') | |||
| @@ -27,18 +18,14 @@ else if ( | |||
| ) { | |||
| // Not build can not get env from process.env.NEXT_PUBLIC_ in browser https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser | |||
| apiPrefix = globalThis.document.body.getAttribute('data-api-prefix') as string | |||
| webPrefix = (globalThis.document.body.getAttribute('data-web-prefix') as string || globalThis.location.origin) | |||
| publicApiPrefix = globalThis.document.body.getAttribute('data-pubic-api-prefix') as string | |||
| publicWebPrefix = (globalThis.document.body.getAttribute('data-pubic-web-prefix') as string || globalThis.location.origin) | |||
| } | |||
| else { | |||
| // const domainParts = globalThis.location?.host?.split('.'); | |||
| // in production env, the host is dify.app . In other env, the host is [dev].dify.app | |||
| // const env = domainParts.length === 2 ? 'ai' : domainParts?.[0]; | |||
| apiPrefix = 'http://localhost:5001/console/api' | |||
| webPrefix = 'http://localhost:3000' | |||
| publicApiPrefix = 'http://localhost:5001/api' // avoid browser private mode api cross origin | |||
| publicWebPrefix = 'http://localhost:3000' | |||
| marketplaceApiPrefix = 'http://localhost:5002/api' | |||
| } | |||
| @@ -52,9 +39,7 @@ else { | |||
| } | |||
| export const API_PREFIX: string = apiPrefix | |||
| export const WEB_PREFIX: string = webPrefix | |||
| export const PUBLIC_API_PREFIX: string = publicApiPrefix | |||
| export const PUBLIC_WEB_PREFIX: string = publicWebPrefix | |||
| export const MARKETPLACE_API_PREFIX: string = marketplaceApiPrefix | |||
| export const MARKETPLACE_URL_PREFIX: string = marketplaceUrlPrefix | |||
| @@ -15,9 +15,7 @@ set -e | |||
| export NEXT_PUBLIC_DEPLOY_ENV=${DEPLOY_ENV} | |||
| export NEXT_PUBLIC_EDITION=${EDITION} | |||
| export NEXT_PUBLIC_API_PREFIX=${CONSOLE_API_URL}/console/api | |||
| export NEXT_PUBLIC_WEB_PREFIX=${CONSOLE_WEB_URL} | |||
| export NEXT_PUBLIC_PUBLIC_API_PREFIX=${APP_API_URL}/api | |||
| export NEXT_PUBLIC_PUBLIC_WEB_PREFIX=${APP_WEB_URL} | |||
| export NEXT_PUBLIC_MARKETPLACE_API_PREFIX=${MARKETPLACE_API_URL}/api/v1 | |||
| export NEXT_PUBLIC_MARKETPLACE_URL_PREFIX=${MARKETPLACE_URL} | |||
| @@ -1,6 +1,7 @@ | |||
| import { API_PREFIX, IS_CE_EDITION, PUBLIC_API_PREFIX, PUBLIC_WEB_PREFIX, WEB_PREFIX } from '@/config' | |||
| import { API_PREFIX, IS_CE_EDITION, PUBLIC_API_PREFIX } from '@/config' | |||
| import { refreshAccessTokenOrRelogin } from './refresh-token' | |||
| import Toast from '@/app/components/base/toast' | |||
| import { basePath } from '@/utils/var' | |||
| import type { AnnotationReply, MessageEnd, MessageReplace, ThoughtItem } from '@/app/components/base/chat/chat/type' | |||
| import type { VisionFile } from '@/types/app' | |||
| import type { | |||
| @@ -108,7 +109,7 @@ function unicodeToChar(text: string) { | |||
| } | |||
| function requiredWebSSOLogin() { | |||
| globalThis.location.href = `${PUBLIC_WEB_PREFIX}/webapp-signin?redirect_url=${globalThis.location.pathname}` | |||
| globalThis.location.href = `/webapp-signin?redirect_url=${globalThis.location.pathname}` | |||
| } | |||
| export function format(text: string) { | |||
| @@ -466,7 +467,7 @@ export const request = async<T>(url: string, options = {}, otherOptions?: IOther | |||
| const errResp: Response = err as any | |||
| if (errResp.status === 401) { | |||
| const [parseErr, errRespData] = await asyncRunSafe<ResponseError>(errResp.json()) | |||
| const loginUrl = `${WEB_PREFIX}/signin` | |||
| const loginUrl = `${globalThis.location.origin}${basePath}/signin` | |||
| if (parseErr) { | |||
| globalThis.location.href = loginUrl | |||
| return Promise.reject(err) | |||
| @@ -498,11 +499,11 @@ export const request = async<T>(url: string, options = {}, otherOptions?: IOther | |||
| return Promise.reject(err) | |||
| } | |||
| if (code === 'not_init_validated' && IS_CE_EDITION) { | |||
| globalThis.location.href = `${WEB_PREFIX}/init` | |||
| globalThis.location.href = `${globalThis.location.origin}${basePath}/init` | |||
| return Promise.reject(err) | |||
| } | |||
| if (code === 'not_setup' && IS_CE_EDITION) { | |||
| globalThis.location.href = `${WEB_PREFIX}/install` | |||
| globalThis.location.href = `${globalThis.location.origin}${basePath}/install` | |||
| return Promise.reject(err) | |||
| } | |||
| @@ -510,7 +511,7 @@ export const request = async<T>(url: string, options = {}, otherOptions?: IOther | |||
| const [refreshErr] = await asyncRunSafe(refreshAccessTokenOrRelogin(TIME_OUT)) | |||
| if (refreshErr === null) | |||
| return baseFetch<T>(url, options, otherOptionsForBaseFetch) | |||
| if (!location.pathname.includes('/signin') || !IS_CE_EDITION) { | |||
| if (location.pathname !== `${basePath}/signin` || !IS_CE_EDITION) { | |||
| globalThis.location.href = loginUrl | |||
| return Promise.reject(err) | |||
| } | |||
| @@ -2,7 +2,7 @@ import type { AfterResponseHook, BeforeErrorHook, BeforeRequestHook, Hooks } fro | |||
| import ky from 'ky' | |||
| import type { IOtherOptions } from './base' | |||
| import Toast from '@/app/components/base/toast' | |||
| import { API_PREFIX, MARKETPLACE_API_PREFIX, PUBLIC_API_PREFIX, WEB_PREFIX } from '@/config' | |||
| import { API_PREFIX, MARKETPLACE_API_PREFIX, PUBLIC_API_PREFIX } from '@/config' | |||
| import { getInitialTokenV2, isTokenV1 } from '@/app/components/share/utils' | |||
| import { getProcessedSystemVariablesFromUrlParams } from '@/app/components/base/chat/utils' | |||
| @@ -44,7 +44,7 @@ const afterResponseErrorCode = (otherOptions: IOtherOptions): AfterResponseHook | |||
| if (!otherOptions.silent) | |||
| Toast.notify({ type: 'error', message: data.message }) | |||
| if (data.code === 'already_setup') | |||
| globalThis.location.href = `${WEB_PREFIX}/signin` | |||
| globalThis.location.href = `${globalThis.location.origin}/signin` | |||
| }) | |||
| break | |||
| case 401: | |||