dify/web/app/layout.tsx
yyh 66a545fc6d
refactor: centralize deployment edition in system features (#39454)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: GareArc <garethcxy@dify.ai>
2026-07-24 07:15:02 +00:00

95 lines
4.0 KiB
TypeScript

import type { Viewport } from '@/next'
import { ToastHost } from '@langgenius/dify-ui/toast'
import { TooltipProvider } from '@langgenius/dify-ui/tooltip'
import { dehydrate, HydrationBoundary } from '@tanstack/react-query'
import { Provider as JotaiProvider } from 'jotai/react'
import { ThemeProvider } from 'next-themes'
import { NuqsAdapter } from 'nuqs/adapters/next/app'
import { IS_PROD } from '@/config'
import { TanStackQueryProvider } from '@/context/query-client'
import { getQueryClientServer } from '@/context/query-client-server'
import { getDatasetMap } from '@/env'
import { SystemFeaturesBootstrapBoundary } from '@/features/system-features/bootstrap-boundary'
import { getLocaleOnServer } from '@/i18n-config/server'
import { headers } from '@/next/headers'
import { serverConsoleQuery } from '@/service/server'
import { CloudAnalytics } from './components/base/analytics-consent/cloud-analytics'
import { PartnerStackCookieRecorder } from './components/billing/partner-stack/cookie-recorder'
import { AgentationLoader } from './components/devtools/agentation-loader'
import { ReactScanLoader } from './components/devtools/react-scan/loader'
import { I18nServerProvider } from './components/provider/i18n-server'
import RoutePrefixHandle from './routePrefixHandle'
import './styles/globals.css'
import './styles/markdown.css'
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover',
}
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const datasetMap = getDatasetMap()
const queryClient = getQueryClientServer()
const systemFeaturesQuery = serverConsoleQuery.systemFeatures.get.queryOptions()
const [locale, requestHeaders] = await Promise.all([
getLocaleOnServer(),
headers(),
queryClient.prefetchQuery(systemFeaturesQuery),
])
const dehydratedState = dehydrate(queryClient)
const nonce = IS_PROD ? (requestHeaders.get('x-nonce') ?? undefined) : undefined
return (
<html lang={locale ?? 'en'} className="h-full" suppressHydrationWarning>
<head>
<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#1C64F2" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="Dify" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/icon-192x192.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/icon-192x192.png" />
<meta name="msapplication-TileColor" content="#1C64F2" />
<meta name="msapplication-config" content="/browserconfig.xml" />
<ReactScanLoader />
</head>
<body className="h-full bg-background-body" {...datasetMap}>
<CloudAnalytics />
<div className="isolate h-full">
<JotaiProvider>
<ThemeProvider
attribute="data-theme"
defaultTheme="system"
enableSystem
disableTransitionOnChange
nonce={nonce}
>
<NuqsAdapter>
<TanStackQueryProvider>
<HydrationBoundary state={dehydratedState}>
<I18nServerProvider>
<ToastHost timeout={5000} limit={3} />
<SystemFeaturesBootstrapBoundary>
<PartnerStackCookieRecorder />
<TooltipProvider delay={300} closeDelay={200}>
{children}
</TooltipProvider>
</SystemFeaturesBootstrapBoundary>
</I18nServerProvider>
</HydrationBoundary>
</TanStackQueryProvider>
</NuqsAdapter>
</ThemeProvider>
</JotaiProvider>
<RoutePrefixHandle />
<AgentationLoader />
</div>
</body>
</html>
)
}