mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-14 05:16:00 +08:00
fix: update document title with system features config
This commit is contained in:
parent
24fce3cc64
commit
00b923651f
@ -2,7 +2,9 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
|
import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
|
|
||||||
export type IAppDetail = {
|
export type IAppDetail = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@ -11,11 +13,13 @@ export type IAppDetail = {
|
|||||||
const AppDetail: FC<IAppDetail> = ({ children }) => {
|
const AppDetail: FC<IAppDetail> = ({ children }) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
useDocumentTitle(t('common.menus.appDetail'))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
return router.replace('/datasets')
|
return router.replace('/datasets')
|
||||||
}, [isCurrentWorkspaceDatasetOperator])
|
}, [isCurrentWorkspaceDatasetOperator, router])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -26,7 +26,6 @@ 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,
|
||||||
@ -56,7 +55,6 @@ 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',
|
||||||
@ -87,16 +85,11 @@ const Apps = () => {
|
|||||||
]
|
]
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
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, systemFeatures])
|
}, [mutate, t])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
|
@ -4,17 +4,17 @@ 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 { LicenseStatus } from '@/types/feature'
|
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
|
|
||||||
const AppList = () => {
|
const AppList = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { systemFeatures } = useGlobalPublicStore()
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
useDocumentTitle(t('common.menus.apps'))
|
||||||
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'>
|
||||||
<Apps />
|
<Apps />
|
||||||
{systemFeatures.license.status === LicenseStatus.NONE && <footer className='px-12 py-6 grow-0 shrink-0'>
|
{!systemFeatures.branding.enabled && <footer className='px-12 py-6 grow-0 shrink-0'>
|
||||||
<h3 className='text-xl font-semibold leading-tight text-gradient'>{t('app.join')}</h3>
|
<h3 className='text-xl font-semibold leading-tight text-gradient'>{t('app.join')}</h3>
|
||||||
<p className='mt-1 system-sm-regular text-text-tertiary'>{t('app.communityIntro')}</p>
|
<p className='mt-1 system-sm-regular text-text-tertiary'>{t('app.communityIntro')}</p>
|
||||||
<div className='flex items-center gap-2 mt-3'>
|
<div className='flex items-center gap-2 mt-3'>
|
||||||
|
@ -29,9 +29,11 @@ import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
|
|||||||
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
import { useStore as useTagStore } from '@/app/components/base/tag-management/store'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
import { useExternalApiPanel } from '@/context/external-api-panel-context'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const Container = () => {
|
const Container = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { currentWorkspace, isCurrentWorkspaceOwner } = useAppContext()
|
const { currentWorkspace, isCurrentWorkspaceOwner } = useAppContext()
|
||||||
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
|
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
|
||||||
@ -123,7 +125,7 @@ const Container = () => {
|
|||||||
{activeTab === 'dataset' && (
|
{activeTab === 'dataset' && (
|
||||||
<>
|
<>
|
||||||
<Datasets containerRef={containerRef} tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
|
<Datasets containerRef={containerRef} tags={tagIDs} keywords={searchKeywords} includeAll={includeAll} />
|
||||||
<DatasetFooter />
|
{!systemFeatures.branding.enabled && <DatasetFooter />}
|
||||||
{showTagManagementModal && (
|
{showTagManagementModal && (
|
||||||
<TagManagementModal type='knowledge' show={showTagManagementModal} />
|
<TagManagementModal type='knowledge' show={showTagManagementModal} />
|
||||||
)}
|
)}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import useSWRInfinite from 'swr/infinite'
|
import useSWRInfinite from 'swr/infinite'
|
||||||
import { debounce } from 'lodash-es'
|
import { debounce } from 'lodash-es'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import NewDatasetCard from './NewDatasetCard'
|
import NewDatasetCard from './NewDatasetCard'
|
||||||
import DatasetCard from './DatasetCard'
|
import DatasetCard from './DatasetCard'
|
||||||
import type { DataSetListResponse, FetchDatasetsParams } from '@/models/datasets'
|
import type { DataSetListResponse, FetchDatasetsParams } from '@/models/datasets'
|
||||||
@ -57,11 +56,8 @@ const Datasets = ({
|
|||||||
const loadingStateRef = useRef(false)
|
const loadingStateRef = useRef(false)
|
||||||
const anchorRef = useRef<HTMLAnchorElement>(null)
|
const anchorRef = useRef<HTMLAnchorElement>(null)
|
||||||
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadingStateRef.current = isLoading
|
loadingStateRef.current = isLoading
|
||||||
document.title = `${t('dataset.knowledge')} - Dify`
|
|
||||||
}, [isLoading])
|
}, [isLoading])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -80,7 +76,7 @@ const Datasets = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
|
<nav className='grid content-start grid-cols-1 gap-4 px-12 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0'>
|
||||||
{ isCurrentWorkspaceEditor && <NewDatasetCard ref={anchorRef} /> }
|
{isCurrentWorkspaceEditor && <NewDatasetCard ref={anchorRef} />}
|
||||||
{data?.map(({ data: datasets }) => datasets.map(dataset => (
|
{data?.map(({ data: datasets }) => datasets.map(dataset => (
|
||||||
<DatasetCard key={dataset.id} dataset={dataset} onSuccess={mutate} />),
|
<DatasetCard key={dataset.id} dataset={dataset} onSuccess={mutate} />),
|
||||||
))}
|
))}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
'use client'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import Container from './Container'
|
import Container from './Container'
|
||||||
|
import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
|
|
||||||
const AppList = async () => {
|
const AppList = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
useDocumentTitle(t('common.menus.datasets'))
|
||||||
return <Container />
|
return <Container />
|
||||||
}
|
}
|
||||||
|
|
||||||
export const metadata = {
|
|
||||||
title: 'Datasets - Dify',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AppList
|
export default AppList
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import type { FC } from 'react'
|
'use client'
|
||||||
|
import type { FC, PropsWithChildren } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import ExploreClient from '@/app/components/explore'
|
import ExploreClient from '@/app/components/explore'
|
||||||
export type IAppDetail = {
|
import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const AppDetail: FC<IAppDetail> = ({ children }) => {
|
const ExploreLayout: FC<PropsWithChildren> = ({ children }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
useDocumentTitle(t('common.menus.explore'))
|
||||||
return (
|
return (
|
||||||
<ExploreClient>
|
<ExploreClient>
|
||||||
{children}
|
{children}
|
||||||
@ -13,4 +15,4 @@ const AppDetail: FC<IAppDetail> = ({ children }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default React.memo(AppDetail)
|
export default React.memo(ExploreLayout)
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
import ToolProviderList from '@/app/components/tools/provider-list'
|
import ToolProviderList from '@/app/components/tools/provider-list'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
|
import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
const Layout: FC = () => {
|
const ToolsList: FC = () => {
|
||||||
const { t } = useTranslation()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
|
const { t } = useTranslation()
|
||||||
useEffect(() => {
|
useDocumentTitle(t('common.menus.tools'))
|
||||||
if (typeof window !== 'undefined')
|
|
||||||
document.title = `${t('tools.title')} - Dify`
|
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
|
||||||
return router.replace('/datasets')
|
|
||||||
}, [isCurrentWorkspaceDatasetOperator, router, t])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
@ -25,4 +19,4 @@ const Layout: FC = () => {
|
|||||||
|
|
||||||
return <ToolProviderList />
|
return <ToolProviderList />
|
||||||
}
|
}
|
||||||
export default React.memo(Layout)
|
export default React.memo(ToolsList)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
|
import { t } from 'i18next'
|
||||||
import Header from './header'
|
import Header from './header'
|
||||||
import SwrInitor from '@/app/components/swr-initor'
|
import SwrInitor from '@/app/components/swr-initor'
|
||||||
import { AppContextProvider } from '@/context/app-context'
|
import { AppContextProvider } from '@/context/app-context'
|
||||||
@ -34,7 +35,7 @@ const Layout = ({ children }: { children: ReactNode }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Dify',
|
title: t('common.menus.account'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Layout
|
export default Layout
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import ExploreContext from '@/context/explore-context'
|
import ExploreContext from '@/context/explore-context'
|
||||||
import Sidebar from '@/app/components/explore/sidebar'
|
import Sidebar from '@/app/components/explore/sidebar'
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
@ -16,7 +15,6 @@ export type IExploreProps = {
|
|||||||
const Explore: FC<IExploreProps> = ({
|
const Explore: FC<IExploreProps> = ({
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [controlUpdateInstalledApps, setControlUpdateInstalledApps] = useState(0)
|
const [controlUpdateInstalledApps, setControlUpdateInstalledApps] = useState(0)
|
||||||
const { userProfile, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { userProfile, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
@ -24,7 +22,6 @@ const Explore: FC<IExploreProps> = ({
|
|||||||
const [installedApps, setInstalledApps] = useState<InstalledApp[]>([])
|
const [installedApps, setInstalledApps] = useState<InstalledApp[]>([])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = `${t('explore.title')} - Dify`;
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const { accounts } = await fetchMembers({ url: '/workspaces/current/members', params: {} })
|
const { accounts } = await fetchMembers({ url: '/workspaces/current/members', params: {} })
|
||||||
if (!accounts)
|
if (!accounts)
|
||||||
|
@ -20,6 +20,7 @@ import { useModalContext } from '@/context/modal-context'
|
|||||||
import { LanguagesSupported } from '@/i18n/language'
|
import { LanguagesSupported } from '@/i18n/language'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { Plan } from '@/app/components/billing/type'
|
import { Plan } from '@/app/components/billing/type'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
export type IAppSelector = {
|
export type IAppSelector = {
|
||||||
isMobile: boolean
|
isMobile: boolean
|
||||||
@ -32,6 +33,7 @@ export default function AppSelector({ isMobile }: IAppSelector) {
|
|||||||
`
|
`
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [aboutVisible, setAboutVisible] = useState(false)
|
const [aboutVisible, setAboutVisible] = useState(false)
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
const { locale } = useContext(I18n)
|
const { locale } = useContext(I18n)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -122,78 +124,80 @@ export default function AppSelector({ isMobile }: IAppSelector) {
|
|||||||
<div>{t('common.userProfile.settings')}</div>
|
<div>{t('common.userProfile.settings')}</div>
|
||||||
</div>}
|
</div>}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
{canEmailSupport && <Menu.Item>
|
{!systemFeatures.branding.enabled && <>
|
||||||
{({ active }) => <a
|
{canEmailSupport && <Menu.Item>
|
||||||
className={classNames(itemClassName, 'group justify-between',
|
{({ active }) => <a
|
||||||
active && 'bg-state-base-hover',
|
className={classNames(itemClassName, 'group justify-between',
|
||||||
)}
|
|
||||||
href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}
|
|
||||||
target='_blank' rel='noopener noreferrer'>
|
|
||||||
<div>{t('common.userProfile.emailSupport')}</div>
|
|
||||||
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
|
||||||
</a>}
|
|
||||||
</Menu.Item>}
|
|
||||||
<Menu.Item>
|
|
||||||
{({ active }) => <Link
|
|
||||||
className={classNames(itemClassName, 'group justify-between',
|
|
||||||
active && 'bg-state-base-hover',
|
|
||||||
)}
|
|
||||||
href='https://github.com/langgenius/dify/discussions/categories/feedbacks'
|
|
||||||
target='_blank' rel='noopener noreferrer'>
|
|
||||||
<div>{t('common.userProfile.communityFeedback')}</div>
|
|
||||||
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
|
||||||
</Link>}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
{({ active }) => <Link
|
|
||||||
className={classNames(itemClassName, 'group justify-between',
|
|
||||||
active && 'bg-state-base-hover',
|
|
||||||
)}
|
|
||||||
href='https://discord.gg/5AEfbxcd9k'
|
|
||||||
target='_blank' rel='noopener noreferrer'>
|
|
||||||
<div>{t('common.userProfile.community')}</div>
|
|
||||||
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
|
||||||
</Link>}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
{({ active }) => <Link
|
|
||||||
className={classNames(itemClassName, 'group justify-between',
|
|
||||||
active && 'bg-state-base-hover',
|
|
||||||
)}
|
|
||||||
href={
|
|
||||||
locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/' : `https://docs.dify.ai/v/${locale.toLowerCase()}/`
|
|
||||||
}
|
|
||||||
target='_blank' rel='noopener noreferrer'>
|
|
||||||
<div>{t('common.userProfile.helpCenter')}</div>
|
|
||||||
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
|
||||||
</Link>}
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item>
|
|
||||||
{({ active }) => <Link
|
|
||||||
className={classNames(itemClassName, 'group justify-between',
|
|
||||||
active && 'bg-state-base-hover',
|
|
||||||
)}
|
|
||||||
href='https://roadmap.dify.ai'
|
|
||||||
target='_blank' rel='noopener noreferrer'>
|
|
||||||
<div>{t('common.userProfile.roadmap')}</div>
|
|
||||||
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
|
||||||
</Link>}
|
|
||||||
</Menu.Item>
|
|
||||||
{
|
|
||||||
document?.body?.getAttribute('data-public-site-about') !== 'hide' && (
|
|
||||||
<Menu.Item>
|
|
||||||
{({ active }) => <div className={classNames(itemClassName, 'justify-between',
|
|
||||||
active && 'bg-state-base-hover',
|
active && 'bg-state-base-hover',
|
||||||
)} onClick={() => setAboutVisible(true)}>
|
)}
|
||||||
<div>{t('common.userProfile.about')}</div>
|
href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}
|
||||||
<div className='flex items-center'>
|
target='_blank' rel='noopener noreferrer'>
|
||||||
<div className='mr-2 system-xs-regular text-text-tertiary'>{langeniusVersionInfo.current_version}</div>
|
<div>{t('common.userProfile.emailSupport')}</div>
|
||||||
<Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} />
|
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
||||||
</div>
|
</a>}
|
||||||
</div>}
|
</Menu.Item>}
|
||||||
</Menu.Item>
|
<Menu.Item>
|
||||||
)
|
{({ active }) => <Link
|
||||||
}
|
className={classNames(itemClassName, 'group justify-between',
|
||||||
|
active && 'bg-state-base-hover',
|
||||||
|
)}
|
||||||
|
href='https://github.com/langgenius/dify/discussions/categories/feedbacks'
|
||||||
|
target='_blank' rel='noopener noreferrer'>
|
||||||
|
<div>{t('common.userProfile.communityFeedback')}</div>
|
||||||
|
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
||||||
|
</Link>}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => <Link
|
||||||
|
className={classNames(itemClassName, 'group justify-between',
|
||||||
|
active && 'bg-state-base-hover',
|
||||||
|
)}
|
||||||
|
href='https://discord.gg/5AEfbxcd9k'
|
||||||
|
target='_blank' rel='noopener noreferrer'>
|
||||||
|
<div>{t('common.userProfile.community')}</div>
|
||||||
|
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
||||||
|
</Link>}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => <Link
|
||||||
|
className={classNames(itemClassName, 'group justify-between',
|
||||||
|
active && 'bg-state-base-hover',
|
||||||
|
)}
|
||||||
|
href={
|
||||||
|
locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/' : `https://docs.dify.ai/v/${locale.toLowerCase()}/`
|
||||||
|
}
|
||||||
|
target='_blank' rel='noopener noreferrer'>
|
||||||
|
<div>{t('common.userProfile.helpCenter')}</div>
|
||||||
|
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
||||||
|
</Link>}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => <Link
|
||||||
|
className={classNames(itemClassName, 'group justify-between',
|
||||||
|
active && 'bg-state-base-hover',
|
||||||
|
)}
|
||||||
|
href='https://roadmap.dify.ai'
|
||||||
|
target='_blank' rel='noopener noreferrer'>
|
||||||
|
<div>{t('common.userProfile.roadmap')}</div>
|
||||||
|
<ArrowUpRight className='hidden w-[14px] h-[14px] text-text-tertiary group-hover:flex' />
|
||||||
|
</Link>}
|
||||||
|
</Menu.Item>
|
||||||
|
{
|
||||||
|
document?.body?.getAttribute('data-public-site-about') !== 'hide' && (
|
||||||
|
<Menu.Item>
|
||||||
|
{({ active }) => <div className={classNames(itemClassName, 'justify-between',
|
||||||
|
active && 'bg-state-base-hover',
|
||||||
|
)} onClick={() => setAboutVisible(true)}>
|
||||||
|
<div>{t('common.userProfile.about')}</div>
|
||||||
|
<div className='flex items-center'>
|
||||||
|
<div className='mr-2 system-xs-regular text-text-tertiary'>{langeniusVersionInfo.current_version}</div>
|
||||||
|
<Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} />
|
||||||
|
</div>
|
||||||
|
</div>}
|
||||||
|
</Menu.Item>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>}
|
||||||
</div>
|
</div>
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
{({ active }) => <div className='p-1' onClick={() => handleLogout()}>
|
{({ active }) => <div className='p-1' onClick={() => handleLogout()}>
|
||||||
|
@ -17,9 +17,11 @@ import ProviderCard from '@/app/components/tools/provider/card'
|
|||||||
import ProviderDetail from '@/app/components/tools/provider/detail'
|
import ProviderDetail from '@/app/components/tools/provider/detail'
|
||||||
import Empty from '@/app/components/tools/add-tool-modal/empty'
|
import Empty from '@/app/components/tools/add-tool-modal/empty'
|
||||||
import { fetchCollectionList } from '@/service/tools'
|
import { fetchCollectionList } from '@/service/tools'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
const ProviderList = () => {
|
const ProviderList = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useTabSearchParams({
|
const [activeTab, setActiveTab] = useTabSearchParams({
|
||||||
defaultTab: 'builtin',
|
defaultTab: 'builtin',
|
||||||
@ -98,7 +100,7 @@ const ProviderList = () => {
|
|||||||
'relative grid content-start grid-cols-1 gap-4 px-12 pt-2 pb-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0',
|
'relative grid content-start grid-cols-1 gap-4 px-12 pt-2 pb-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0',
|
||||||
currentProvider && 'pr-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
currentProvider && 'pr-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
|
||||||
)}>
|
)}>
|
||||||
{activeTab === 'builtin' && <ContributeCard />}
|
{activeTab === 'builtin' && !systemFeatures.branding.enabled && <ContributeCard />}
|
||||||
{activeTab === 'api' && <CustomCreateCard onRefreshData={getProviderList} />}
|
{activeTab === 'api' && <CustomCreateCard onRefreshData={getProviderList} />}
|
||||||
{filteredCollectionList.map(collection => (
|
{filteredCollectionList.map(collection => (
|
||||||
<ProviderCard
|
<ProviderCard
|
||||||
|
@ -21,8 +21,8 @@ const Contribute: FC = () => {
|
|||||||
>
|
>
|
||||||
<div className='flex pt-[14px] px-[14px] pb-3 h-[66px] items-center gap-3 grow-0 shrink-0'>
|
<div className='flex pt-[14px] px-[14px] pb-3 h-[66px] items-center gap-3 grow-0 shrink-0'>
|
||||||
<div className='relative shrink-0 flex items-center'>
|
<div className='relative shrink-0 flex items-center'>
|
||||||
<div className='z-10 flex p-3 rounded-[10px] bg-white border-[0.5px] border-primary-100 shadow-md'><RiHammerFill className='w-4 h-4 text-primary-600'/></div>
|
<div className='z-10 flex p-3 rounded-[10px] bg-white border-[0.5px] border-primary-100 shadow-md'><RiHammerFill className='w-4 h-4 text-primary-600' /></div>
|
||||||
<div className='-translate-x-2 flex p-3 rounded-[10px] bg-[#FEF6FB] border-[0.5px] border-[#FCE7F6] shadow-md'><Heart02 className='w-4 h-4 text-[#EE46BC]'/></div>
|
<div className='-translate-x-2 flex p-3 rounded-[10px] bg-[#FEF6FB] border-[0.5px] border-[#FCE7F6] shadow-md'><Heart02 className='w-4 h-4 text-[#EE46BC]' /></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='mb-3 px-[14px] text-[15px] leading-5 font-semibold'>
|
<div className='mb-3 px-[14px] text-[15px] leading-5 font-semibold'>
|
||||||
|
@ -7,7 +7,9 @@ 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'
|
import GlobalPublicStoreProvider from '@/context/global-public-context'
|
||||||
import { fetchSystemFeatures } from '@/service/share'
|
import type { SystemFeatures } from '@/types/feature'
|
||||||
|
import { defaultSystemFeatures } from '@/types/feature'
|
||||||
|
import { API_PREFIX } from '@/config'
|
||||||
|
|
||||||
export const viewport: Viewport = {
|
export const viewport: Viewport = {
|
||||||
width: 'device-width',
|
width: 'device-width',
|
||||||
@ -18,12 +20,19 @@ export const viewport: Viewport = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const config = await fetchSystemFeatures()
|
const ret = await fetch(`${API_PREFIX}/system-features`, { cache: 'no-cache' }).then(res => res.json())
|
||||||
if (config.branding.enabled)
|
const config: SystemFeatures = { ...defaultSystemFeatures, ...ret.data }
|
||||||
return { title: config.branding.application_title ?? '-', icons: config.branding.favicon }
|
if (config.branding.enabled) {
|
||||||
|
return {
|
||||||
|
title: { template: `%s - ${config.branding.application_title}`, default: config.branding.application_title },
|
||||||
|
icons: config.branding.favicon,
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
title: 'Dify',
|
title: {
|
||||||
|
template: '%s - Dify',
|
||||||
|
default: 'Dify',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
'use client'
|
||||||
import Header from './_header'
|
import Header from './_header'
|
||||||
import style from './page.module.css'
|
import style from './page.module.css'
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import type { FC, PropsWithChildren } from 'react'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import type { SystemFeatures } from '@/types/feature'
|
import type { SystemFeatures } from '@/types/feature'
|
||||||
import { defaultSystemFeatures } from '@/types/feature'
|
import { defaultSystemFeatures } from '@/types/feature'
|
||||||
import { fetchSystemFeatures } from '@/service/share'
|
import { getSystemFeatures } from '@/service/common'
|
||||||
|
|
||||||
type GlobalPublicStore = {
|
type GlobalPublicStore = {
|
||||||
systemFeatures: SystemFeatures
|
systemFeatures: SystemFeatures
|
||||||
@ -22,7 +22,7 @@ const GlobalPublicStoreProvider: FC<PropsWithChildren> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ['systemFeatures'],
|
queryKey: ['systemFeatures'],
|
||||||
queryFn: fetchSystemFeatures,
|
queryFn: getSystemFeatures,
|
||||||
})
|
})
|
||||||
const { setSystemFeatures } = useGlobalPublicStore()
|
const { setSystemFeatures } = useGlobalPublicStore()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
13
web/hooks/use-document-title.ts
Normal file
13
web/hooks/use-document-title.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
'use client'
|
||||||
|
import { useLayoutEffect } from 'react'
|
||||||
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
|
||||||
|
export default function useDocumentTitle(title: string) {
|
||||||
|
const { systemFeatures } = useGlobalPublicStore()
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (systemFeatures.branding.enabled)
|
||||||
|
document.title = `${title} - ${systemFeatures.branding.application_title}`
|
||||||
|
else
|
||||||
|
document.title = `${title} - Dify`
|
||||||
|
}, [systemFeatures, title])
|
||||||
|
}
|
@ -131,6 +131,7 @@ const translation = {
|
|||||||
status: 'beta',
|
status: 'beta',
|
||||||
explore: 'Explore',
|
explore: 'Explore',
|
||||||
apps: 'Studio',
|
apps: 'Studio',
|
||||||
|
appDetail: 'App Detail',
|
||||||
plugins: 'Plugins',
|
plugins: 'Plugins',
|
||||||
pluginsTips: 'Integrate third-party plugins or create ChatGPT-compatible AI-Plugins.',
|
pluginsTips: 'Integrate third-party plugins or create ChatGPT-compatible AI-Plugins.',
|
||||||
datasets: 'Knowledge',
|
datasets: 'Knowledge',
|
||||||
|
@ -131,6 +131,7 @@ const translation = {
|
|||||||
status: 'ベータ版',
|
status: 'ベータ版',
|
||||||
explore: '探索',
|
explore: '探索',
|
||||||
apps: 'スタジオ',
|
apps: 'スタジオ',
|
||||||
|
appDetail: 'アプリの詳細',
|
||||||
plugins: 'プラグイン',
|
plugins: 'プラグイン',
|
||||||
pluginsTips: 'サードパーティのプラグインを統合するか、ChatGPT互換のAIプラグインを作成します。',
|
pluginsTips: 'サードパーティのプラグインを統合するか、ChatGPT互換のAIプラグインを作成します。',
|
||||||
datasets: 'ナレッジ',
|
datasets: 'ナレッジ',
|
||||||
|
@ -131,6 +131,7 @@ const translation = {
|
|||||||
status: 'beta',
|
status: 'beta',
|
||||||
explore: '探索',
|
explore: '探索',
|
||||||
apps: '工作室',
|
apps: '工作室',
|
||||||
|
appDetail: '应用详情',
|
||||||
plugins: '插件',
|
plugins: '插件',
|
||||||
pluginsTips: '集成第三方插件或创建与 ChatGPT 兼容的 AI 插件。',
|
pluginsTips: '集成第三方插件或创建与 ChatGPT 兼容的 AI 插件。',
|
||||||
datasets: '知识库',
|
datasets: '知识库',
|
||||||
|
@ -127,6 +127,7 @@ const translation = {
|
|||||||
status: 'beta',
|
status: 'beta',
|
||||||
explore: '探索',
|
explore: '探索',
|
||||||
apps: '工作室',
|
apps: '工作室',
|
||||||
|
appDetail: '應用詳情',
|
||||||
plugins: '外掛',
|
plugins: '外掛',
|
||||||
pluginsTips: '整合第三方外掛或建立與 ChatGPT 相容的 AI 外掛。',
|
pluginsTips: '整合第三方外掛或建立與 ChatGPT 相容的 AI 外掛。',
|
||||||
datasets: '知識庫',
|
datasets: '知識庫',
|
||||||
|
@ -36,6 +36,7 @@ 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'
|
||||||
@ -303,6 +304,10 @@ 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 })
|
||||||
|
|
||||||
|
@ -61,6 +61,6 @@ export const defaultSystemFeatures: SystemFeatures = {
|
|||||||
login_page_logo: '',
|
login_page_logo: '',
|
||||||
workspace_logo: '',
|
workspace_logo: '',
|
||||||
favicon: '',
|
favicon: '',
|
||||||
application_title: '',
|
application_title: 'test title',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user