mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 22:55:54 +08:00
chore: use global zustand manage systemFeatures and share between all pages
This commit is contained in:
parent
d89034d913
commit
24fce3cc64
@ -15,17 +15,17 @@ import {
|
|||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useShallow } from 'zustand/react/shallow'
|
import { useShallow } from 'zustand/react/shallow'
|
||||||
import { useContextSelector } from 'use-context-selector'
|
|
||||||
import s from './style.module.css'
|
import s from './style.module.css'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useStore } from '@/app/components/app/store'
|
import { useStore } from '@/app/components/app/store'
|
||||||
import AppSideBar from '@/app/components/app-sidebar'
|
import AppSideBar from '@/app/components/app-sidebar'
|
||||||
import type { NavIcon } from '@/app/components/app-sidebar/navLink'
|
import type { NavIcon } from '@/app/components/app-sidebar/navLink'
|
||||||
import { fetchAppDetail, fetchAppSSO } from '@/service/apps'
|
import { fetchAppDetail, fetchAppSSO } from '@/service/apps'
|
||||||
import AppContext, { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import type { App } from '@/types/app'
|
import type { App } from '@/types/app'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
export type IAppDetailLayoutProps = {
|
export type IAppDetailLayoutProps = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@ -56,7 +56,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||||||
icon: NavIcon
|
icon: NavIcon
|
||||||
selectedIcon: NavIcon
|
selectedIcon: NavIcon
|
||||||
}>>([])
|
}>>([])
|
||||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => {
|
const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => {
|
||||||
const navs = [
|
const navs = [
|
||||||
@ -98,7 +98,11 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appDetail) {
|
if (appDetail) {
|
||||||
document.title = `${(appDetail.name || 'App')} - Dify`
|
if (systemFeatures.branding.enabled)
|
||||||
|
document.title = `${(appDetail.name || 'App')} - ${systemFeatures.branding.application_title}`
|
||||||
|
else
|
||||||
|
document.title = `${(appDetail.name || 'App')} - Dify`
|
||||||
|
|
||||||
const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
|
const localeMode = localStorage.getItem('app-detail-collapse-or-expand') || 'expand'
|
||||||
const mode = isMobile ? 'collapse' : 'expand'
|
const mode = isMobile ? 'collapse' : 'expand'
|
||||||
setAppSiderbarExpand(isMobile ? mode : localeMode)
|
setAppSiderbarExpand(isMobile ? mode : localeMode)
|
||||||
@ -106,7 +110,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||||||
// if ((appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && (pathname).endsWith('workflow'))
|
// if ((appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && (pathname).endsWith('workflow'))
|
||||||
// setAppSiderbarExpand('collapse')
|
// setAppSiderbarExpand('collapse')
|
||||||
}
|
}
|
||||||
}, [appDetail, isMobile])
|
}, [appDetail, isMobile, pathname, setAppSiderbarExpand, systemFeatures])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAppDetail()
|
setAppDetail()
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useContext, useContextSelector } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import AppCard from '@/app/components/app/overview/appCard'
|
import AppCard from '@/app/components/app/overview/appCard'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import { ToastContext } from '@/app/components/base/toast'
|
import { ToastContext } from '@/app/components/base/toast'
|
||||||
@ -20,7 +20,7 @@ import { asyncRunSafe } from '@/utils'
|
|||||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||||
import type { IAppCardProps } from '@/app/components/app/overview/appCard'
|
import type { IAppCardProps } from '@/app/components/app/overview/appCard'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import AppContext from '@/context/app-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
export type ICardViewProps = {
|
export type ICardViewProps = {
|
||||||
appId: string
|
appId: string
|
||||||
@ -31,7 +31,7 @@ const CardView: FC<ICardViewProps> = ({ appId }) => {
|
|||||||
const { notify } = useContext(ToastContext)
|
const { notify } = useContext(ToastContext)
|
||||||
const appDetail = useAppStore(state => state.appDetail)
|
const appDetail = useAppStore(state => state.appDetail)
|
||||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
const updateAppDetail = async () => {
|
const updateAppDetail = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -26,6 +26,7 @@ import { useStore as useTagStore } from '@/app/components/base/tag-management/st
|
|||||||
import TagManagementModal from '@/app/components/base/tag-management'
|
import TagManagementModal from '@/app/components/base/tag-management'
|
||||||
import TagFilter from '@/app/components/base/tag-management/filter'
|
import TagFilter from '@/app/components/base/tag-management/filter'
|
||||||
import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
|
import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const getKey = (
|
const getKey = (
|
||||||
pageIndex: number,
|
pageIndex: number,
|
||||||
@ -55,6 +56,7 @@ const Apps = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
|
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
|
||||||
const [activeTab, setActiveTab] = useTabSearchParams({
|
const [activeTab, setActiveTab] = useTabSearchParams({
|
||||||
defaultTab: 'all',
|
defaultTab: 'all',
|
||||||
@ -85,12 +87,16 @@ const Apps = () => {
|
|||||||
]
|
]
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = `${t('common.menus.apps')} - Dify`
|
if (systemFeatures.branding.enabled)
|
||||||
|
document.title = `${t('common.menus.apps')} - ${systemFeatures.branding.application_title}`
|
||||||
|
else
|
||||||
|
document.title = `${t('common.menus.apps')} - Dify`
|
||||||
|
|
||||||
if (localStorage.getItem(NEED_REFRESH_APP_LIST_KEY) === '1') {
|
if (localStorage.getItem(NEED_REFRESH_APP_LIST_KEY) === '1') {
|
||||||
localStorage.removeItem(NEED_REFRESH_APP_LIST_KEY)
|
localStorage.removeItem(NEED_REFRESH_APP_LIST_KEY)
|
||||||
mutate()
|
mutate()
|
||||||
}
|
}
|
||||||
}, [mutate, t])
|
}, [mutate, t, systemFeatures])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { useContextSelector } from 'use-context-selector'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
|
import { RiDiscordFill, RiGithubFill } from '@remixicon/react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import style from '../list.module.css'
|
import style from '../list.module.css'
|
||||||
import Apps from './Apps'
|
import Apps from './Apps'
|
||||||
import AppContext from '@/context/app-context'
|
|
||||||
import { LicenseStatus } from '@/types/feature'
|
import { LicenseStatus } from '@/types/feature'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const AppList = () => {
|
const AppList = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative flex flex-col overflow-y-auto bg-background-body shrink-0 h-0 grow'>
|
<div className='relative flex flex-col overflow-y-auto bg-background-body shrink-0 h-0 grow'>
|
||||||
|
@ -30,9 +30,4 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata = {
|
|
||||||
title: 'Dify',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Layout
|
export default Layout
|
||||||
|
@ -16,6 +16,7 @@ import { ToastContext } from '@/app/components/base/toast'
|
|||||||
import AppIcon from '@/app/components/base/app-icon'
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
import { IS_CE_EDITION } from '@/config'
|
import { IS_CE_EDITION } from '@/config'
|
||||||
import Input from '@/app/components/base/input'
|
import Input from '@/app/components/base/input'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const titleClassName = `
|
const titleClassName = `
|
||||||
system-sm-semibold text-text-secondary
|
system-sm-semibold text-text-secondary
|
||||||
@ -28,7 +29,7 @@ const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/
|
|||||||
|
|
||||||
export default function AccountPage() {
|
export default function AccountPage() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { systemFeatures } = useAppContext()
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const { mutateUserProfile, userProfile, apps } = useAppContext()
|
const { mutateUserProfile, userProfile, apps } = useAppContext()
|
||||||
const { notify } = useContext(ToastContext)
|
const { notify } = useContext(ToastContext)
|
||||||
const [editNameModalVisible, setEditNameModalVisible] = useState(false)
|
const [editNameModalVisible, setEditNameModalVisible] = useState(false)
|
||||||
@ -133,7 +134,7 @@ export default function AccountPage() {
|
|||||||
<h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4>
|
<h4 className='title-2xl-semi-bold text-text-primary'>{t('common.account.myAccount')}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'>
|
<div className='mb-8 p-6 rounded-xl flex items-center bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1'>
|
||||||
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={ mutateUserProfile } size={64} />
|
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={mutateUserProfile} size={64} />
|
||||||
<div className='ml-4'>
|
<div className='ml-4'>
|
||||||
<p className='system-xl-semibold text-text-primary'>{userProfile.name}</p>
|
<p className='system-xl-semibold text-text-primary'>{userProfile.name}</p>
|
||||||
<p className='system-xs-regular text-text-tertiary'>{userProfile.email}</p>
|
<p className='system-xs-regular text-text-tertiary'>{userProfile.email}</p>
|
||||||
|
@ -4,7 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react'
|
|||||||
import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react'
|
import { RiArrowRightSLine, RiCloseLine } from '@remixicon/react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { useContext, useContextSelector } from 'use-context-selector'
|
import { useContext } from 'use-context-selector'
|
||||||
import { SparklesSoft } from '@/app/components/base/icons/src/public/common'
|
import { SparklesSoft } from '@/app/components/base/icons/src/public/common'
|
||||||
import Modal from '@/app/components/base/modal'
|
import Modal from '@/app/components/base/modal'
|
||||||
import ActionButton from '@/app/components/base/action-button'
|
import ActionButton from '@/app/components/base/action-button'
|
||||||
@ -21,13 +21,14 @@ import type { AppIconType, AppSSO, Language } from '@/types/app'
|
|||||||
import { useToastContext } from '@/app/components/base/toast'
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
import { LanguagesSupported, languages } from '@/i18n/language'
|
import { LanguagesSupported, languages } from '@/i18n/language'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import AppContext, { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useModalContext } from '@/context/modal-context'
|
import { useModalContext } from '@/context/modal-context'
|
||||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||||
import I18n from '@/context/i18n'
|
import I18n from '@/context/i18n'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
export type ISettingsModalProps = {
|
export type ISettingsModalProps = {
|
||||||
isChat: boolean
|
isChat: boolean
|
||||||
@ -65,7 +66,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
|||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
}) => {
|
}) => {
|
||||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
const { isCurrentWorkspaceEditor } = useAppContext()
|
||||||
const { notify } = useToastContext()
|
const { notify } = useToastContext()
|
||||||
const [isShowMore, setIsShowMore] = useState(false)
|
const [isShowMore, setIsShowMore] = useState(false)
|
||||||
@ -354,7 +355,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
|||||||
<div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.entry`)}</div>
|
<div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.entry`)}</div>
|
||||||
<p className={cn('pb-0.5 text-text-tertiary body-xs-regular')}>{t(`${prefixSettings}.more.copyRightPlaceholder`)} & {t(`${prefixSettings}.more.privacyPolicyPlaceholder`)}</p>
|
<p className={cn('pb-0.5 text-text-tertiary body-xs-regular')}>{t(`${prefixSettings}.more.copyRightPlaceholder`)} & {t(`${prefixSettings}.more.privacyPolicyPlaceholder`)}</p>
|
||||||
</div>
|
</div>
|
||||||
<RiArrowRightSLine className='shrink-0 ml-1 w-4 h-4 text-text-secondary'/>
|
<RiArrowRightSLine className='shrink-0 ml-1 w-4 h-4 text-text-secondary' />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* more settings */}
|
{/* more settings */}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import classNames from '@/utils/classnames'
|
import classNames from '@/utils/classnames'
|
||||||
import { useSelector } from '@/context/app-context'
|
import { useSelector } from '@/context/app-context'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
type LogoSiteProps = {
|
type LogoSiteProps = {
|
||||||
className?: string
|
className?: string
|
||||||
@ -10,13 +11,17 @@ type LogoSiteProps = {
|
|||||||
const LogoSite: FC<LogoSiteProps> = ({
|
const LogoSite: FC<LogoSiteProps> = ({
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const { theme } = useSelector((s) => {
|
const { theme } = useSelector((s) => {
|
||||||
return {
|
return {
|
||||||
theme: s.theme,
|
theme: s.theme,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const src = theme === 'light' ? '/logo/logo-site.png' : `/logo/logo-site-${theme}.png`
|
let src = theme === 'light' ? '/logo/logo-site.png' : `/logo/logo-site-${theme}.png`
|
||||||
|
if (systemFeatures.branding.enabled)
|
||||||
|
src = systemFeatures.branding.login_page_logo
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<img
|
<img
|
||||||
src={src}
|
src={src}
|
||||||
|
@ -21,6 +21,7 @@ import { Plan } from '@/app/components/billing/type'
|
|||||||
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
|
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
|
||||||
import { NUM_INFINITE } from '@/app/components/billing/config'
|
import { NUM_INFINITE } from '@/app/components/billing/config'
|
||||||
import { LanguagesSupported } from '@/i18n/language'
|
import { LanguagesSupported } from '@/i18n/language'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
const MembersPage = () => {
|
const MembersPage = () => {
|
||||||
@ -34,7 +35,8 @@ const MembersPage = () => {
|
|||||||
}
|
}
|
||||||
const { locale } = useContext(I18n)
|
const { locale } = useContext(I18n)
|
||||||
|
|
||||||
const { userProfile, currentWorkspace, isCurrentWorkspaceOwner, isCurrentWorkspaceManager, systemFeatures } = useAppContext()
|
const { userProfile, currentWorkspace, isCurrentWorkspaceOwner, isCurrentWorkspaceManager } = useAppContext()
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const { data, mutate } = useSWR({ url: '/workspaces/current/members' }, fetchMembers)
|
const { data, mutate } = useSWR({ url: '/workspaces/current/members' }, fetchMembers)
|
||||||
const [inviteModalVisible, setInviteModalVisible] = useState(false)
|
const [inviteModalVisible, setInviteModalVisible] = useState(false)
|
||||||
const [invitationResults, setInvitationResults] = useState<InvitationResult[]>([])
|
const [invitationResults, setInvitationResults] = useState<InvitationResult[]>([])
|
||||||
|
@ -4,7 +4,6 @@ import Link from 'next/link'
|
|||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import { useSelectedLayoutSegment } from 'next/navigation'
|
import { useSelectedLayoutSegment } from 'next/navigation'
|
||||||
import { Bars3Icon } from '@heroicons/react/20/solid'
|
import { Bars3Icon } from '@heroicons/react/20/solid'
|
||||||
import { useContextSelector } from 'use-context-selector'
|
|
||||||
import HeaderBillingBtn from '../billing/header-billing-btn'
|
import HeaderBillingBtn from '../billing/header-billing-btn'
|
||||||
import AccountDropdown from './account-dropdown'
|
import AccountDropdown from './account-dropdown'
|
||||||
import AppNav from './app-nav'
|
import AppNav from './app-nav'
|
||||||
@ -15,12 +14,13 @@ import ToolsNav from './tools-nav'
|
|||||||
import GithubStar from './github-star'
|
import GithubStar from './github-star'
|
||||||
import LicenseNav from './license-env'
|
import LicenseNav from './license-env'
|
||||||
import { WorkspaceProvider } from '@/context/workspace-context'
|
import { WorkspaceProvider } from '@/context/workspace-context'
|
||||||
import AppContext, { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import LogoSite from '@/app/components/base/logo/logo-site'
|
import LogoSite from '@/app/components/base/logo/logo-site'
|
||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useModalContext } from '@/context/modal-context'
|
import { useModalContext } from '@/context/modal-context'
|
||||||
import { LicenseStatus } from '@/types/feature'
|
import { LicenseStatus } from '@/types/feature'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const navClassName = `
|
const navClassName = `
|
||||||
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
|
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
|
||||||
@ -30,7 +30,7 @@ const navClassName = `
|
|||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const selectedSegment = useSelectedLayoutSegment()
|
const selectedSegment = useSelectedLayoutSegment()
|
||||||
const media = useBreakpoints()
|
const media = useBreakpoints()
|
||||||
const isMobile = media === MediaType.mobile
|
const isMobile = media === MediaType.mobile
|
||||||
|
@ -5,10 +5,11 @@ import { LicenseStatus } from '@/types/feature'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useContextSelector } from 'use-context-selector'
|
import { useContextSelector } from 'use-context-selector'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const LicenseNav = () => {
|
const LicenseNav = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const systemFeatures = useContextSelector(AppContext, s => s.systemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
if (systemFeatures.license?.status === LicenseStatus.EXPIRING) {
|
if (systemFeatures.license?.status === LicenseStatus.EXPIRING) {
|
||||||
const expiredAt = systemFeatures.license?.expired_at
|
const expiredAt = systemFeatures.license?.expired_at
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { Viewport } from 'next'
|
import type { Metadata, Viewport } from 'next'
|
||||||
import I18nServer from './components/i18n-server'
|
import I18nServer from './components/i18n-server'
|
||||||
import BrowserInitor from './components/browser-initor'
|
import BrowserInitor from './components/browser-initor'
|
||||||
import SentryInitor from './components/sentry-initor'
|
import SentryInitor from './components/sentry-initor'
|
||||||
@ -6,10 +6,8 @@ import { getLocaleOnServer } from '@/i18n/server'
|
|||||||
import { TanstackQueryIniter } from '@/context/query-client'
|
import { TanstackQueryIniter } from '@/context/query-client'
|
||||||
import './styles/globals.css'
|
import './styles/globals.css'
|
||||||
import './styles/markdown.scss'
|
import './styles/markdown.scss'
|
||||||
|
import GlobalPublicStoreProvider from '@/context/global-public-context'
|
||||||
export const metadata = {
|
import { fetchSystemFeatures } from '@/service/share'
|
||||||
title: 'Dify',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const viewport: Viewport = {
|
export const viewport: Viewport = {
|
||||||
width: 'device-width',
|
width: 'device-width',
|
||||||
@ -19,6 +17,16 @@ export const viewport: Viewport = {
|
|||||||
userScalable: false,
|
userScalable: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
|
const config = await fetchSystemFeatures()
|
||||||
|
if (config.branding.enabled)
|
||||||
|
return { title: config.branding.application_title ?? '-', icons: config.branding.favicon }
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: 'Dify',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const LocaleLayout = ({
|
const LocaleLayout = ({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
@ -50,7 +58,11 @@ const LocaleLayout = ({
|
|||||||
<BrowserInitor>
|
<BrowserInitor>
|
||||||
<SentryInitor>
|
<SentryInitor>
|
||||||
<TanstackQueryIniter>
|
<TanstackQueryIniter>
|
||||||
<I18nServer>{children}</I18nServer>
|
<I18nServer>
|
||||||
|
<GlobalPublicStoreProvider>
|
||||||
|
{children}
|
||||||
|
</GlobalPublicStoreProvider>
|
||||||
|
</I18nServer>
|
||||||
</TanstackQueryIniter>
|
</TanstackQueryIniter>
|
||||||
</SentryInitor>
|
</SentryInitor>
|
||||||
</BrowserInitor>
|
</BrowserInitor>
|
||||||
|
@ -2,8 +2,10 @@ import Header from './_header'
|
|||||||
import style from './page.module.css'
|
import style from './page.module.css'
|
||||||
|
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
export default async function SignInLayout({ children }: any) {
|
export default function SignInLayout({ children }: any) {
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
return <>
|
return <>
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
style.background,
|
style.background,
|
||||||
@ -30,9 +32,9 @@ export default async function SignInLayout({ children }: any) {
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='px-8 py-6 system-xs-regular text-text-tertiary'>
|
{systemFeatures.branding.enabled === false && <div className='px-8 py-6 system-xs-regular text-text-tertiary'>
|
||||||
© {new Date().getFullYear()} LangGenius, Inc. All rights reserved.
|
© {new Date().getFullYear()} LangGenius, Inc. All rights reserved.
|
||||||
</div>
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -9,10 +9,11 @@ import MailAndPasswordAuth from './components/mail-and-password-auth'
|
|||||||
import SocialAuth from './components/social-auth'
|
import SocialAuth from './components/social-auth'
|
||||||
import SSOAuth from './components/sso-auth'
|
import SSOAuth from './components/sso-auth'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { getSystemFeatures, invitationCheck } from '@/service/common'
|
import { invitationCheck } from '@/service/common'
|
||||||
import { LicenseStatus, defaultSystemFeatures } from '@/types/feature'
|
import { LicenseStatus } from '@/types/feature'
|
||||||
import Toast from '@/app/components/base/toast'
|
import Toast from '@/app/components/base/toast'
|
||||||
import { IS_CE_EDITION } from '@/config'
|
import { IS_CE_EDITION } from '@/config'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const NormalForm = () => {
|
const NormalForm = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -23,7 +24,7 @@ const NormalForm = () => {
|
|||||||
const message = decodeURIComponent(searchParams.get('message') || '')
|
const message = decodeURIComponent(searchParams.get('message') || '')
|
||||||
const invite_token = decodeURIComponent(searchParams.get('invite_token') || '')
|
const invite_token = decodeURIComponent(searchParams.get('invite_token') || '')
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [systemFeatures, setSystemFeatures] = useState(defaultSystemFeatures)
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const [authType, updateAuthType] = useState<'code' | 'password'>('password')
|
const [authType, updateAuthType] = useState<'code' | 'password'>('password')
|
||||||
const [showORLine, setShowORLine] = useState(false)
|
const [showORLine, setShowORLine] = useState(false)
|
||||||
const [allMethodsAreDisabled, setAllMethodsAreDisabled] = useState(false)
|
const [allMethodsAreDisabled, setAllMethodsAreDisabled] = useState(false)
|
||||||
@ -46,12 +47,9 @@ const NormalForm = () => {
|
|||||||
message,
|
message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const features = await getSystemFeatures()
|
setAllMethodsAreDisabled(!systemFeatures.enable_social_oauth_login && !systemFeatures.enable_email_code_login && !systemFeatures.enable_email_password_login && !systemFeatures.sso_enforced_for_signin)
|
||||||
const allFeatures = { ...defaultSystemFeatures, ...features }
|
setShowORLine((systemFeatures.enable_social_oauth_login || systemFeatures.sso_enforced_for_signin) && (systemFeatures.enable_email_code_login || systemFeatures.enable_email_password_login))
|
||||||
setSystemFeatures(allFeatures)
|
updateAuthType(systemFeatures.enable_email_password_login ? 'password' : 'code')
|
||||||
setAllMethodsAreDisabled(!allFeatures.enable_social_oauth_login && !allFeatures.enable_email_code_login && !allFeatures.enable_email_password_login && !allFeatures.sso_enforced_for_signin)
|
|
||||||
setShowORLine((allFeatures.enable_social_oauth_login || allFeatures.sso_enforced_for_signin) && (allFeatures.enable_email_code_login || allFeatures.enable_email_password_login))
|
|
||||||
updateAuthType(allFeatures.enable_email_password_login ? 'password' : 'code')
|
|
||||||
if (isInviteLink) {
|
if (isInviteLink) {
|
||||||
const checkRes = await invitationCheck({
|
const checkRes = await invitationCheck({
|
||||||
url: '/activate/check',
|
url: '/activate/check',
|
||||||
@ -65,10 +63,9 @@ const NormalForm = () => {
|
|||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
setAllMethodsAreDisabled(true)
|
setAllMethodsAreDisabled(true)
|
||||||
setSystemFeatures(defaultSystemFeatures)
|
|
||||||
}
|
}
|
||||||
finally { setIsLoading(false) }
|
finally { setIsLoading(false) }
|
||||||
}, [consoleToken, refreshToken, message, router, invite_token, isInviteLink])
|
}, [consoleToken, refreshToken, message, router, invite_token, isInviteLink, systemFeatures])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
init()
|
init()
|
||||||
}, [init])
|
}, [init])
|
||||||
@ -83,7 +80,7 @@ const NormalForm = () => {
|
|||||||
<Loading type='area' />
|
<Loading type='area' />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
if (systemFeatures.license?.status === LicenseStatus.LOST) {
|
if (systemFeatures.license.status === LicenseStatus.LOST) {
|
||||||
return <div className='w-full mx-auto mt-8'>
|
return <div className='w-full mx-auto mt-8'>
|
||||||
<div className='bg-white'>
|
<div className='bg-white'>
|
||||||
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
||||||
@ -97,7 +94,7 @@ const NormalForm = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
if (systemFeatures.license?.status === LicenseStatus.EXPIRED) {
|
if (systemFeatures.license.status === LicenseStatus.EXPIRED) {
|
||||||
return <div className='w-full mx-auto mt-8'>
|
return <div className='w-full mx-auto mt-8'>
|
||||||
<div className='bg-white'>
|
<div className='bg-white'>
|
||||||
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
||||||
@ -111,7 +108,7 @@ const NormalForm = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
if (systemFeatures.license?.status === LicenseStatus.INACTIVE) {
|
if (systemFeatures.license.status === LicenseStatus.INACTIVE) {
|
||||||
return <div className='w-full mx-auto mt-8'>
|
return <div className='w-full mx-auto mt-8'>
|
||||||
<div className='bg-white'>
|
<div className='bg-white'>
|
||||||
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
<div className="p-4 rounded-lg bg-gradient-to-r from-workflow-workflow-progress-bg-1 to-workflow-workflow-progress-bg-2">
|
||||||
@ -132,11 +129,11 @@ const NormalForm = () => {
|
|||||||
{isInviteLink
|
{isInviteLink
|
||||||
? <div className="w-full mx-auto">
|
? <div className="w-full mx-auto">
|
||||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.join')}{workspaceName}</h2>
|
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.join')}{workspaceName}</h2>
|
||||||
<p className='mt-2 body-md-regular text-text-tertiary'>{t('login.joinTipStart')}{workspaceName}{t('login.joinTipEnd')}</p>
|
{!systemFeatures.branding.enabled && <p className='mt-2 body-md-regular text-text-tertiary'>{t('login.joinTipStart')}{workspaceName}{t('login.joinTipEnd')}</p>}
|
||||||
</div>
|
</div>
|
||||||
: <div className="w-full mx-auto">
|
: <div className="w-full mx-auto">
|
||||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.pageTitle')}</h2>
|
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.pageTitle')}</h2>
|
||||||
<p className='mt-2 body-md-regular text-text-tertiary'>{t('login.welcome')}</p>
|
{!systemFeatures.branding.enabled && <p className='mt-2 body-md-regular text-text-tertiary'>{t('login.welcome')}</p>}
|
||||||
</div>}
|
</div>}
|
||||||
<div className="bg-white">
|
<div className="bg-white">
|
||||||
<div className="flex flex-col gap-3 mt-6">
|
<div className="flex flex-col gap-3 mt-6">
|
||||||
@ -184,29 +181,31 @@ const NormalForm = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>}
|
</>}
|
||||||
<div className="w-full block mt-2 system-xs-regular text-text-tertiary">
|
{!systemFeatures.branding.enabled && <>
|
||||||
{t('login.tosDesc')}
|
<div className="w-full block mt-2 system-xs-regular text-text-tertiary">
|
||||||
|
{t('login.tosDesc')}
|
||||||
<Link
|
|
||||||
className='system-xs-medium text-text-secondary hover:underline'
|
<Link
|
||||||
target='_blank' rel='noopener noreferrer'
|
className='system-xs-medium text-text-secondary hover:underline'
|
||||||
href='https://dify.ai/terms'
|
target='_blank' rel='noopener noreferrer'
|
||||||
>{t('login.tos')}</Link>
|
href='https://dify.ai/terms'
|
||||||
&
|
>{t('login.tos')}</Link>
|
||||||
<Link
|
&
|
||||||
className='system-xs-medium text-text-secondary hover:underline'
|
<Link
|
||||||
target='_blank' rel='noopener noreferrer'
|
className='system-xs-medium text-text-secondary hover:underline'
|
||||||
href='https://dify.ai/privacy'
|
target='_blank' rel='noopener noreferrer'
|
||||||
>{t('login.pp')}</Link>
|
href='https://dify.ai/privacy'
|
||||||
</div>
|
>{t('login.pp')}</Link>
|
||||||
{IS_CE_EDITION && <div className="w-hull block mt-2 system-xs-regular text-text-tertiary">
|
</div>
|
||||||
{t('login.goToInit')}
|
{IS_CE_EDITION && <div className="w-hull block mt-2 system-xs-regular text-text-tertiary">
|
||||||
|
{t('login.goToInit')}
|
||||||
<Link
|
|
||||||
className='system-xs-medium text-text-secondary hover:underline'
|
<Link
|
||||||
href='/install'
|
className='system-xs-medium text-text-secondary hover:underline'
|
||||||
>{t('login.setAdminAccount')}</Link>
|
href='/install'
|
||||||
</div>}
|
>{t('login.setAdminAccount')}</Link>
|
||||||
|
</div>}
|
||||||
|
</>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,19 +6,16 @@ import { createContext, useContext, useContextSelector } from 'use-context-selec
|
|||||||
import type { FC, ReactNode } from 'react'
|
import type { FC, ReactNode } from 'react'
|
||||||
import { fetchAppList } from '@/service/apps'
|
import { fetchAppList } from '@/service/apps'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile, getSystemFeatures } from '@/service/common'
|
import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile } from '@/service/common'
|
||||||
import type { App } from '@/types/app'
|
import type { App } from '@/types/app'
|
||||||
import { Theme } from '@/types/app'
|
import { Theme } from '@/types/app'
|
||||||
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
|
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
|
||||||
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
|
||||||
import type { SystemFeatures } from '@/types/feature'
|
|
||||||
import { defaultSystemFeatures } from '@/types/feature'
|
|
||||||
|
|
||||||
export type AppContextValue = {
|
export type AppContextValue = {
|
||||||
theme: Theme
|
theme: Theme
|
||||||
setTheme: (theme: Theme) => void
|
setTheme: (theme: Theme) => void
|
||||||
apps: App[]
|
apps: App[]
|
||||||
systemFeatures: SystemFeatures
|
|
||||||
mutateApps: VoidFunction
|
mutateApps: VoidFunction
|
||||||
userProfile: UserProfileResponse
|
userProfile: UserProfileResponse
|
||||||
mutateUserProfile: VoidFunction
|
mutateUserProfile: VoidFunction
|
||||||
@ -57,7 +54,6 @@ const initialWorkspaceInfo: ICurrentWorkspace = {
|
|||||||
|
|
||||||
const AppContext = createContext<AppContextValue>({
|
const AppContext = createContext<AppContextValue>({
|
||||||
theme: Theme.light,
|
theme: Theme.light,
|
||||||
systemFeatures: defaultSystemFeatures,
|
|
||||||
setTheme: () => { },
|
setTheme: () => { },
|
||||||
apps: [],
|
apps: [],
|
||||||
mutateApps: () => { },
|
mutateApps: () => { },
|
||||||
@ -96,10 +92,6 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
|||||||
const { data: userProfileResponse, mutate: mutateUserProfile } = useSWR({ url: '/account/profile', params: {} }, fetchUserProfile)
|
const { data: userProfileResponse, mutate: mutateUserProfile } = useSWR({ url: '/account/profile', params: {} }, fetchUserProfile)
|
||||||
const { data: currentWorkspaceResponse, mutate: mutateCurrentWorkspace, isLoading: isLoadingCurrentWorkspace } = useSWR({ url: '/workspaces/current', params: {} }, fetchCurrentWorkspace)
|
const { data: currentWorkspaceResponse, mutate: mutateCurrentWorkspace, isLoading: isLoadingCurrentWorkspace } = useSWR({ url: '/workspaces/current', params: {} }, fetchCurrentWorkspace)
|
||||||
|
|
||||||
const { data: systemFeatures } = useSWR({ url: '/console/system-features' }, getSystemFeatures, {
|
|
||||||
fallbackData: defaultSystemFeatures,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [userProfile, setUserProfile] = useState<UserProfileResponse>()
|
const [userProfile, setUserProfile] = useState<UserProfileResponse>()
|
||||||
const [langeniusVersionInfo, setLangeniusVersionInfo] = useState<LangGeniusVersionResponse>(initialLangeniusVersionInfo)
|
const [langeniusVersionInfo, setLangeniusVersionInfo] = useState<LangGeniusVersionResponse>(initialLangeniusVersionInfo)
|
||||||
const [currentWorkspace, setCurrentWorkspace] = useState<ICurrentWorkspace>(initialWorkspaceInfo)
|
const [currentWorkspace, setCurrentWorkspace] = useState<ICurrentWorkspace>(initialWorkspaceInfo)
|
||||||
@ -146,7 +138,6 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
|
|||||||
theme,
|
theme,
|
||||||
setTheme: handleSetTheme,
|
setTheme: handleSetTheme,
|
||||||
apps: appList.data,
|
apps: appList.data,
|
||||||
systemFeatures: { ...defaultSystemFeatures, ...systemFeatures },
|
|
||||||
mutateApps,
|
mutateApps,
|
||||||
userProfile,
|
userProfile,
|
||||||
mutateUserProfile,
|
mutateUserProfile,
|
||||||
|
34
web/context/global-public-context.tsx
Normal file
34
web/context/global-public-context.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
'use client'
|
||||||
|
import { create } from 'zustand'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
import type { FC, PropsWithChildren } from 'react'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import type { SystemFeatures } from '@/types/feature'
|
||||||
|
import { defaultSystemFeatures } from '@/types/feature'
|
||||||
|
import { fetchSystemFeatures } from '@/service/share'
|
||||||
|
|
||||||
|
type GlobalPublicStore = {
|
||||||
|
systemFeatures: SystemFeatures
|
||||||
|
setSystemFeatures: (systemFeatures: SystemFeatures) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGlobalPublicStore = create<GlobalPublicStore>(set => ({
|
||||||
|
systemFeatures: defaultSystemFeatures,
|
||||||
|
setSystemFeatures: (systemFeatures: SystemFeatures) => set(() => ({ systemFeatures })),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const GlobalPublicStoreProvider: FC<PropsWithChildren> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const { data } = useQuery({
|
||||||
|
queryKey: ['systemFeatures'],
|
||||||
|
queryFn: fetchSystemFeatures,
|
||||||
|
})
|
||||||
|
const { setSystemFeatures } = useGlobalPublicStore()
|
||||||
|
useEffect(() => {
|
||||||
|
if (data)
|
||||||
|
setSystemFeatures({ ...defaultSystemFeatures, ...data })
|
||||||
|
}, [data, setSystemFeatures])
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
|
export default GlobalPublicStoreProvider
|
@ -36,11 +36,10 @@ import type {
|
|||||||
ModelTypeEnum,
|
ModelTypeEnum,
|
||||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||||
import type { RETRIEVE_METHOD } from '@/types/app'
|
import type { RETRIEVE_METHOD } from '@/types/app'
|
||||||
import type { SystemFeatures } from '@/types/feature'
|
|
||||||
|
|
||||||
type LoginSuccess = {
|
type LoginSuccess = {
|
||||||
result: 'success'
|
result: 'success'
|
||||||
data: { access_token: string;refresh_token: string }
|
data: { access_token: string; refresh_token: string }
|
||||||
}
|
}
|
||||||
type LoginFail = {
|
type LoginFail = {
|
||||||
result: 'fail'
|
result: 'fail'
|
||||||
@ -304,10 +303,6 @@ export const fetchSupportRetrievalMethods: Fetcher<RetrievalMethodsRes, string>
|
|||||||
return get<RetrievalMethodsRes>(url)
|
return get<RetrievalMethodsRes>(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSystemFeatures = () => {
|
|
||||||
return get<SystemFeatures>('/system-features')
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enableModel = (url: string, body: { model: string; model_type: ModelTypeEnum }) =>
|
export const enableModel = (url: string, body: { model: string; model_type: ModelTypeEnum }) =>
|
||||||
patch<CommonResponse>(url, { body })
|
patch<CommonResponse>(url, { body })
|
||||||
|
|
||||||
@ -331,20 +326,20 @@ export const uploadRemoteFileInfo = (url: string, isPublic?: boolean) => {
|
|||||||
export const sendEMailLoginCode = (email: string, language = 'en-US') =>
|
export const sendEMailLoginCode = (email: string, language = 'en-US') =>
|
||||||
post<CommonResponse & { data: string }>('/email-code-login', { body: { email, language } })
|
post<CommonResponse & { data: string }>('/email-code-login', { body: { email, language } })
|
||||||
|
|
||||||
export const emailLoginWithCode = (data: { email: string;code: string;token: string }) =>
|
export const emailLoginWithCode = (data: { email: string; code: string; token: string }) =>
|
||||||
post<LoginResponse>('/email-code-login/validity', { body: data })
|
post<LoginResponse>('/email-code-login/validity', { body: data })
|
||||||
|
|
||||||
export const sendResetPasswordCode = (email: string, language = 'en-US') =>
|
export const sendResetPasswordCode = (email: string, language = 'en-US') =>
|
||||||
post<CommonResponse & { data: string;message?: string ;code?: string }>('/forgot-password', { body: { email, language } })
|
post<CommonResponse & { data: string; message?: string; code?: string }>('/forgot-password', { body: { email, language } })
|
||||||
|
|
||||||
export const verifyResetPasswordCode = (body: { email: string;code: string;token: string }) =>
|
export const verifyResetPasswordCode = (body: { email: string; code: string; token: string }) =>
|
||||||
post<CommonResponse & { is_valid: boolean }>('/forgot-password/validity', { body })
|
post<CommonResponse & { is_valid: boolean }>('/forgot-password/validity', { body })
|
||||||
|
|
||||||
export const sendDeleteAccountCode = () =>
|
export const sendDeleteAccountCode = () =>
|
||||||
get<CommonResponse & { data: string }>('/account/delete/verify')
|
get<CommonResponse & { data: string }>('/account/delete/verify')
|
||||||
|
|
||||||
export const verifyDeleteAccountCode = (body: { code: string;token: string }) =>
|
export const verifyDeleteAccountCode = (body: { code: string; token: string }) =>
|
||||||
post<CommonResponse & { is_valid: boolean }>('/account/delete', { body })
|
post<CommonResponse & { is_valid: boolean }>('/account/delete', { body })
|
||||||
|
|
||||||
export const submitDeleteAccountFeedback = (body: { feedback: string;email: string }) =>
|
export const submitDeleteAccountFeedback = (body: { feedback: string; email: string }) =>
|
||||||
post<CommonResponse>('/account/delete/feedback', { body })
|
post<CommonResponse>('/account/delete/feedback', { body })
|
||||||
|
@ -31,6 +31,13 @@ export type SystemFeatures = {
|
|||||||
is_allow_register: boolean
|
is_allow_register: boolean
|
||||||
is_email_setup: boolean
|
is_email_setup: boolean
|
||||||
license: License
|
license: License
|
||||||
|
branding: {
|
||||||
|
enabled: boolean
|
||||||
|
login_page_logo: string
|
||||||
|
workspace_logo: string
|
||||||
|
favicon: string
|
||||||
|
application_title: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultSystemFeatures: SystemFeatures = {
|
export const defaultSystemFeatures: SystemFeatures = {
|
||||||
@ -49,4 +56,11 @@ export const defaultSystemFeatures: SystemFeatures = {
|
|||||||
status: LicenseStatus.NONE,
|
status: LicenseStatus.NONE,
|
||||||
expired_at: '',
|
expired_at: '',
|
||||||
},
|
},
|
||||||
|
branding: {
|
||||||
|
enabled: false,
|
||||||
|
login_page_logo: '',
|
||||||
|
workspace_logo: '',
|
||||||
|
favicon: '',
|
||||||
|
application_title: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user