refactor(web): move app context layout styles to shell (#38511)

This commit is contained in:
yyh 2026-07-07 17:47:30 +08:00 committed by GitHub
parent 31b17513c2
commit 2c6ec1a761
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 73 additions and 47 deletions

View File

@ -1,8 +1,9 @@
import type { ReactNode } from 'react'
import * as React from 'react'
import AmplitudeProvider from '@/app/components/base/amplitude'
import { GoogleAnalyticsScripts } from '@/app/components/base/ga'
import Zendesk from '@/app/components/base/zendesk'
import { EducationVerifyActionRecorder } from '@/app/components/education-verify-action-recorder'
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
import MainNavLayout from '@/app/components/main-nav/layout'
import { NextRouteStateBridge } from '@/app/components/next-route-state'
import { OAuthRegistrationAnalytics } from '@/app/components/oauth-registration-analytics'
@ -17,32 +18,35 @@ export default async function Layout({
children,
detailSidebar,
}: {
children: ReactNode
detailSidebar: ReactNode
children: React.ReactNode
detailSidebar: React.ReactNode
}) {
return (
<>
<React.Fragment>
<GoogleAnalyticsScripts />
<AmplitudeProvider />
<OAuthRegistrationAnalytics />
<EducationVerifyActionRecorder />
<CommonLayoutHydrationBoundary>
<NextRouteStateBridge>
<AppContextProvider>
<EventEmitterContextProvider>
<ProviderContextProvider>
<ModalContextProvider>
<MainNavLayout detailSidebar={detailSidebar}>
{children}
</MainNavLayout>
<CommonLayoutGlobalMounts />
</ModalContextProvider>
</ProviderContextProvider>
</EventEmitterContextProvider>
</AppContextProvider>
<div className="flex h-full flex-col overflow-hidden">
<MaintenanceNotice />
<AppContextProvider>
<EventEmitterContextProvider>
<ProviderContextProvider>
<ModalContextProvider>
<MainNavLayout detailSidebar={detailSidebar}>
{children}
</MainNavLayout>
<CommonLayoutGlobalMounts />
</ModalContextProvider>
</ProviderContextProvider>
</EventEmitterContextProvider>
</AppContextProvider>
</div>
</NextRouteStateBridge>
</CommonLayoutHydrationBoundary>
<Zendesk />
</>
</React.Fragment>
)
}

View File

@ -1,10 +1,10 @@
import type { ReactNode } from 'react'
import * as React from 'react'
import { CommonLayoutHydrationBoundary } from '@/app/(commonLayout)/hydration-boundary'
import AmplitudeProvider from '@/app/components/base/amplitude'
import { GoogleAnalyticsScripts } from '@/app/components/base/ga'
import { EducationVerifyActionRecorder } from '@/app/components/education-verify-action-recorder'
import HeaderWrapper from '@/app/components/header/header-wrapper'
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
import { OAuthRegistrationAnalytics } from '@/app/components/oauth-registration-analytics'
import { AppContextProvider } from '@/context/app-context-provider'
import { EventEmitterContextProvider } from '@/context/event-emitter-provider'
@ -12,30 +12,32 @@ import { ModalContextProvider } from '@/context/modal-context-provider'
import { ProviderContextProvider } from '@/context/provider-context-provider'
import Header from './header'
const Layout = async ({ children }: { children: ReactNode }) => {
export default async function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<React.Fragment>
<GoogleAnalyticsScripts />
<AmplitudeProvider />
<OAuthRegistrationAnalytics />
<EducationVerifyActionRecorder />
<CommonLayoutHydrationBoundary>
<AppContextProvider>
<EventEmitterContextProvider>
<ProviderContextProvider>
<ModalContextProvider>
<HeaderWrapper>
<Header />
</HeaderWrapper>
<div className="relative flex h-0 shrink-0 grow flex-col overflow-y-auto bg-components-panel-bg">
{children}
</div>
</ModalContextProvider>
</ProviderContextProvider>
</EventEmitterContextProvider>
</AppContextProvider>
<div className="flex h-full flex-col overflow-hidden bg-background-body">
<MaintenanceNotice />
<AppContextProvider>
<EventEmitterContextProvider>
<ProviderContextProvider>
<ModalContextProvider>
<HeaderWrapper>
<Header />
</HeaderWrapper>
<div className="relative flex h-0 min-h-0 shrink-0 grow flex-col overflow-y-auto bg-components-panel-bg">
{children}
</div>
</ModalContextProvider>
</ProviderContextProvider>
</EventEmitterContextProvider>
</AppContextProvider>
</div>
</CommonLayoutHydrationBoundary>
</>
</React.Fragment>
)
}
export default Layout

View File

@ -4,10 +4,18 @@ import { useLanguage } from '@/app/components/header/account-setting/model-provi
import { NOTICE_I18N } from '@/i18n-config/language'
import MaintenanceNotice from '../maintenance-notice'
const mockEnv = vi.hoisted(() => ({
NEXT_PUBLIC_MAINTENANCE_NOTICE: 'true',
}))
vi.mock('@/app/components/base/icons/src/vender/line/general', () => ({
X: (props: React.SVGProps<SVGSVGElement>) => <svg {...props} />,
}))
vi.mock('@/env', () => ({
env: mockEnv,
}))
vi.mock(
'@/app/components/header/account-setting/model-provider-page/hooks',
() => ({
@ -44,6 +52,7 @@ describe('MaintenanceNotice', () => {
beforeEach(() => {
vi.clearAllMocks()
localStorage.clear()
mockEnv.NEXT_PUBLIC_MAINTENANCE_NOTICE = 'true'
vi.mocked(useLanguage).mockReturnValue('en_US')
setNoticeHref('#')
})
@ -71,6 +80,14 @@ describe('MaintenanceNotice', () => {
const { container } = render(<MaintenanceNotice />)
expect(container.firstChild).toBeNull()
})
it('should not render when the notice env flag is disabled', () => {
mockEnv.NEXT_PUBLIC_MAINTENANCE_NOTICE = ''
const { container } = render(<MaintenanceNotice />)
expect(container.firstChild).toBeNull()
})
})
describe('User Interactions', () => {

View File

@ -1,11 +1,21 @@
'use client'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { X } from '@/app/components/base/icons/src/vender/line/general'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { env } from '@/env'
import { NOTICE_I18N } from '@/i18n-config/language'
import { useHideMaintenanceNotice } from './storage'
const MaintenanceNotice = () => {
function MaintenanceNotice() {
if (!env.NEXT_PUBLIC_MAINTENANCE_NOTICE)
return null
return <MaintenanceNoticeContent />
}
function MaintenanceNoticeContent() {
const { t } = useTranslation()
const locale = useLanguage()

View File

@ -2,14 +2,13 @@
import type { GetAccountProfileResponse } from '@dify/contracts/api/console/account/types.gen'
import type { PostWorkspacesCurrentResponse } from '@dify/contracts/api/console/workspaces/types.gen'
import type { FC, ReactNode } from 'react'
import type { ReactNode } from 'react'
import type { ICurrentWorkspace, LangGeniusVersionResponse } from '@/models/common'
import { useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query'
import { useCallback, useEffect, useMemo } from 'react'
import { setUserId, setUserProperties } from '@/app/components/base/amplitude'
import { flushRegistrationSuccess } from '@/app/components/base/amplitude/registration-tracking'
import { setZendeskConversationFields } from '@/app/components/base/zendesk/utils'
import MaintenanceNotice from '@/app/components/header/maintenance-notice'
import { ZENDESK_FIELD_IDS } from '@/config'
import {
AppContext,
@ -18,7 +17,6 @@ import {
userProfilePlaceholder,
useSelector,
} from '@/context/app-context'
import { env } from '@/env'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { useWorkspacePermissionKeys } from '@/service/access-control/use-permission-keys'
@ -66,7 +64,7 @@ const normalizeCurrentWorkspace = (workspace?: PostWorkspacesCurrentResponse): I
}
}
export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) => {
export function AppContextProvider({ children }: AppContextProviderProps) {
const queryClient = useQueryClient()
const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions())
const { data: userProfileResp } = useSuspenseQuery(userProfileQueryOptions())
@ -192,12 +190,7 @@ export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) =>
workspacePermissionKeys: workspacePermissionKeysQuery.data?.workspace.permission_keys ?? emptyWorkspacePermissionKeys,
}}
>
<div className="flex h-full flex-col overflow-hidden">
{env.NEXT_PUBLIC_MAINTENANCE_NOTICE && <MaintenanceNotice />}
<div className="relative flex h-0 min-h-0 grow flex-col overflow-hidden bg-background-body">
{children}
</div>
</div>
{children}
</AppContext.Provider>
)
}