From e0232c67ccb8c06e648d15d50345a1995dd03684 Mon Sep 17 00:00:00 2001 From: NFish Date: Sat, 15 Mar 2025 01:25:04 +0800 Subject: [PATCH 1/3] fix: update document title and favicon in client side --- web/app/activate/activateForm.tsx | 2 ++ web/app/forgot-password/page.tsx | 2 ++ web/app/init/InitPasswordPopup.tsx | 2 ++ web/app/install/installForm.tsx | 2 ++ web/app/layout.tsx | 22 +++------------------- web/app/reset-password/page.tsx | 2 ++ web/app/signin/layout.tsx | 2 ++ web/hooks/use-document-title.ts | 13 +++++++++---- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/web/app/activate/activateForm.tsx b/web/app/activate/activateForm.tsx index 9a32a76a73..12dd8b4be8 100644 --- a/web/app/activate/activateForm.tsx +++ b/web/app/activate/activateForm.tsx @@ -7,8 +7,10 @@ import Button from '@/app/components/base/button' import { invitationCheck } from '@/service/common' import Loading from '@/app/components/base/loading' +import useDocumentTitle from '@/hooks/use-document-title' const ActivateForm = () => { + useDocumentTitle('') const router = useRouter() const { t } = useTranslation() const searchParams = useSearchParams() diff --git a/web/app/forgot-password/page.tsx b/web/app/forgot-password/page.tsx index bb46011c06..c2911add6e 100644 --- a/web/app/forgot-password/page.tsx +++ b/web/app/forgot-password/page.tsx @@ -6,8 +6,10 @@ import Header from '../signin/_header' import style from '../signin/page.module.css' import ForgotPasswordForm from './ForgotPasswordForm' import ChangePasswordForm from '@/app/forgot-password/ChangePasswordForm' +import useDocumentTitle from '@/hooks/use-document-title' const ForgotPassword = () => { + useDocumentTitle('') const searchParams = useSearchParams() const token = searchParams.get('token') diff --git a/web/app/init/InitPasswordPopup.tsx b/web/app/init/InitPasswordPopup.tsx index cbf25f43b2..d78502f98a 100644 --- a/web/app/init/InitPasswordPopup.tsx +++ b/web/app/init/InitPasswordPopup.tsx @@ -7,8 +7,10 @@ import Loading from '../components/base/loading' import Button from '@/app/components/base/button' import { fetchInitValidateStatus, initValidate } from '@/service/common' import type { InitValidateStatusResponse } from '@/models/common' +import useDocumentTitle from '@/hooks/use-document-title' const InitPasswordPopup = () => { + useDocumentTitle('') const [password, setPassword] = useState('') const [loading, setLoading] = useState(true) const [validated, setValidated] = useState(false) diff --git a/web/app/install/installForm.tsx b/web/app/install/installForm.tsx index abf377e389..0e0dbee13b 100644 --- a/web/app/install/installForm.tsx +++ b/web/app/install/installForm.tsx @@ -15,6 +15,7 @@ import Button from '@/app/components/base/button' import { fetchInitValidateStatus, fetchSetupStatus, setup } from '@/service/common' import type { InitValidateStatusResponse, SetupStatusResponse } from '@/models/common' +import useDocumentTitle from '@/hooks/use-document-title' const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ @@ -32,6 +33,7 @@ const accountFormSchema = z.object({ type AccountFormValues = z.infer const InstallForm = () => { + useDocumentTitle('') const { t } = useTranslation() const router = useRouter() const [showPassword, setShowPassword] = React.useState(false) diff --git a/web/app/layout.tsx b/web/app/layout.tsx index de579c8671..cdefdc2b5d 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -7,9 +7,6 @@ import { TanstackQueryIniter } from '@/context/query-client' import './styles/globals.css' import './styles/markdown.scss' import GlobalPublicStoreProvider from '@/context/global-public-context' -import type { SystemFeatures } from '@/types/feature' -import { defaultSystemFeatures } from '@/types/feature' -import { API_PREFIX } from '@/config' export const viewport: Viewport = { width: 'device-width', @@ -18,22 +15,9 @@ export const viewport: Viewport = { viewportFit: 'cover', userScalable: false, } - -export async function generateMetadata(): Promise { - const ret = await fetch(`${API_PREFIX}/system-features`, { cache: 'no-cache' }).then(res => res.json()) - const config: SystemFeatures = { ...defaultSystemFeatures, ...ret.data } - if (config.branding.enabled) { - return { - title: { template: `%s - ${config.branding.application_title}`, default: config.branding.application_title }, - icons: config.branding.favicon, - } - } - return { - title: { - template: '%s - Dify', - default: 'Dify', - }, - } +export const metadata: Metadata = { + title: ' ', + icons: 'data:', } const LocaleLayout = ({ diff --git a/web/app/reset-password/page.tsx b/web/app/reset-password/page.tsx index 65f1db3fb5..057f356208 100644 --- a/web/app/reset-password/page.tsx +++ b/web/app/reset-password/page.tsx @@ -12,9 +12,11 @@ import Input from '@/app/components/base/input' import Toast from '@/app/components/base/toast' import { sendResetPasswordCode } from '@/service/common' import I18NContext from '@/context/i18n' +import useDocumentTitle from '@/hooks/use-document-title' export default function CheckCode() { const { t } = useTranslation() + useDocumentTitle('') const searchParams = useSearchParams() const router = useRouter() const [email, setEmail] = useState('') diff --git a/web/app/signin/layout.tsx b/web/app/signin/layout.tsx index d14ab7d8cb..32c0fbfe46 100644 --- a/web/app/signin/layout.tsx +++ b/web/app/signin/layout.tsx @@ -4,9 +4,11 @@ import style from './page.module.css' import cn from '@/utils/classnames' import { useGlobalPublicStore } from '@/context/global-public-context' +import useDocumentTitle from '@/hooks/use-document-title' export default function SignInLayout({ children }: any) { const { systemFeatures } = useGlobalPublicStore() + useDocumentTitle('') return <>
{ - if (systemFeatures.branding.enabled) - document.title = `${title} - ${systemFeatures.branding.application_title}` - else - document.title = `${title} - Dify` + const prefix = title ? `${title} - ` : '' + if (systemFeatures.branding.enabled) { + document.title = `${prefix}${systemFeatures.branding.application_title}` + const faviconEle = document.querySelector('link[rel*=\'icon\']') as HTMLLinkElement + faviconEle.href = systemFeatures.branding.favicon + } + else { + document.title = `${prefix}Dify` + } }, [systemFeatures, title]) } From 7da45ba5898c625afb3fb79cf3bc956069811a57 Mon Sep 17 00:00:00 2001 From: NFish Date: Sat, 15 Mar 2025 11:59:58 +0800 Subject: [PATCH 2/3] fix: show loading icon when fetching system features --- web/context/global-public-context.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web/context/global-public-context.tsx b/web/context/global-public-context.tsx index 17a7441642..71a2e37d07 100644 --- a/web/context/global-public-context.tsx +++ b/web/context/global-public-context.tsx @@ -6,6 +6,7 @@ import { useEffect } from 'react' import type { SystemFeatures } from '@/types/feature' import { defaultSystemFeatures } from '@/types/feature' import { getSystemFeatures } from '@/service/common' +import Loading from '@/app/components/base/loading' type GlobalPublicStore = { systemFeatures: SystemFeatures @@ -20,7 +21,7 @@ export const useGlobalPublicStore = create(set => ({ const GlobalPublicStoreProvider: FC = ({ children, }) => { - const { data } = useQuery({ + const { isPending, data } = useQuery({ queryKey: ['systemFeatures'], queryFn: getSystemFeatures, }) @@ -29,6 +30,8 @@ const GlobalPublicStoreProvider: FC = ({ if (data) setSystemFeatures({ ...defaultSystemFeatures, ...data }) }, [data, setSystemFeatures]) + if (isPending) + return
return <>{children} } export default GlobalPublicStoreProvider From 54634f26d233c9c2fb4f8db3aac22cd2a792fd88 Mon Sep 17 00:00:00 2001 From: NFish Date: Mon, 17 Mar 2025 10:36:51 +0800 Subject: [PATCH 3/3] fix: show copyright in webapp --- .../datasets/(datasetDetailLayout)/[datasetId]/layout.tsx | 7 ++----- web/app/components/app/overview/settings/index.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx index a6fb116fa8..e429dc4796 100644 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx +++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout.tsx @@ -31,6 +31,7 @@ import { getLocaleOnClient } from '@/i18n' import { useAppContext } from '@/context/app-context' import Tooltip from '@/app/components/base/tooltip' import LinkedAppsPanel from '@/app/components/base/linked-apps-panel' +import useDocumentTitle from '@/hooks/use-document-title' export type IAppDetailLayoutProps = { children: React.ReactNode @@ -186,11 +187,7 @@ const DatasetDetailLayout: FC = (props) => { } return baseNavigation }, [datasetRes?.provider, datasetId, t]) - - useEffect(() => { - if (datasetRes) - document.title = `${datasetRes.name || 'Dataset'} - Dify` - }, [datasetRes]) + useDocumentTitle(`${datasetRes?.name || 'Dataset'}`) const setAppSiderbarExpand = useStore(state => state.setAppSiderbarExpand) diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx index 1fb054ad75..1615173578 100644 --- a/web/app/components/app/overview/settings/index.tsx +++ b/web/app/components/app/overview/settings/index.tsx @@ -29,6 +29,8 @@ import AppIconPicker from '@/app/components/base/app-icon-picker' import I18n from '@/context/i18n' import cn from '@/utils/classnames' import { useGlobalPublicStore } from '@/context/global-public-context' +import { IS_CE_EDITION } from '@/config' +import { LicenseStatus } from '@/types/feature' export type ISettingsModalProps = { isChat: boolean @@ -178,7 +180,7 @@ const SettingsModal: FC = ({ chat_color_theme: inputInfo.chatColorTheme, chat_color_theme_inverted: inputInfo.chatColorThemeInverted, prompt_public: false, - copyright: isFreePlan + copyright: IS_CE_EDITION ? '' : inputInfo.copyrightSwitchValue ? inputInfo.copyright @@ -381,14 +383,14 @@ const SettingsModal: FC = ({ )}
{t(`${prefixSettings}.more.copyrightTooltip`)} } asChild={false} > setInputInfo({ ...inputInfo, copyrightSwitchValue: v })} />