|
'use client' |
|
|
|
import { createRef, useCallback, useEffect, useMemo, useRef, useState } from 'react' |
|
import useSWR from 'swr' |
|
import { createContext, useContext, useContextSelector } from 'use-context-selector' |
|
import type { FC, ReactNode } from 'react' |
|
import { fetchAppList } from '@/service/apps' |
|
import Loading from '@/app/components/base/loading' |
|
import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile, getSystemFeatures } from '@/service/common' |
|
import type { App } from '@/types/app' |
|
import { Theme } from '@/types/app' |
|
import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common' |
|
import MaintenanceNotice from '@/app/components/header/maintenance-notice' |
|
import type { SystemFeatures } from '@/types/feature' |
|
import { defaultSystemFeatures } from '@/types/feature' |
|
|
|
export type AppContextValue = { |
|
theme: Theme |
|
setTheme: (theme: Theme) => void |
|
apps: App[] |
|
systemFeatures: SystemFeatures |
|
mutateApps: VoidFunction |
|
userProfile: UserProfileResponse |
|
mutateUserProfile: VoidFunction |
|
currentWorkspace: ICurrentWorkspace |
|
isCurrentWorkspaceManager: boolean |
|
isCurrentWorkspaceOwner: boolean |
|
isCurrentWorkspaceEditor: boolean |
|
isCurrentWorkspaceDatasetOperator: boolean |
|
mutateCurrentWorkspace: VoidFunction |
|
pageContainerRef: React.RefObject<HTMLDivElement> |
|
langeniusVersionInfo: LangGeniusVersionResponse |
|
useSelector: typeof useSelector |
|
} |
|
|
|
const initialLangeniusVersionInfo = { |
|
current_env: '', |
|
current_version: '', |
|
latest_version: '', |
|
release_date: '', |
|
release_notes: '', |
|
version: '', |
|
can_auto_update: false, |
|
} |
|
|
|
const initialWorkspaceInfo: ICurrentWorkspace = { |
|
id: '', |
|
name: '', |
|
plan: '', |
|
status: '', |
|
created_at: 0, |
|
role: 'normal', |
|
providers: [], |
|
in_trail: true, |
|
} |
|
|
|
const AppContext = createContext<AppContextValue>({ |
|
theme: Theme.light, |
|
systemFeatures: defaultSystemFeatures, |
|
setTheme: () => { }, |
|
apps: [], |
|
mutateApps: () => { }, |
|
userProfile: { |
|
id: '', |
|
name: '', |
|
email: '', |
|
avatar: '', |
|
is_password_set: false, |
|
}, |
|
currentWorkspace: initialWorkspaceInfo, |
|
isCurrentWorkspaceManager: false, |
|
isCurrentWorkspaceOwner: false, |
|
isCurrentWorkspaceEditor: false, |
|
isCurrentWorkspaceDatasetOperator: false, |
|
mutateUserProfile: () => { }, |
|
mutateCurrentWorkspace: () => { }, |
|
pageContainerRef: createRef(), |
|
langeniusVersionInfo: initialLangeniusVersionInfo, |
|
useSelector, |
|
}) |
|
|
|
export function useSelector<T>(selector: (value: AppContextValue) => T): T { |
|
return useContextSelector(AppContext, selector) |
|
} |
|
|
|
export type AppContextProviderProps = { |
|
children: ReactNode |
|
} |
|
|
|
export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) => { |
|
const pageContainerRef = useRef<HTMLDivElement>(null) |
|
|
|
const { data: appList, mutate: mutateApps } = useSWR({ url: '/apps', params: { page: 1, limit: 30, name: '' } }, fetchAppList) |
|
const { data: userProfileResponse, mutate: mutateUserProfile } = useSWR({ url: '/account/profile', params: {} }, fetchUserProfile) |
|
const { data: currentWorkspaceResponse, mutate: mutateCurrentWorkspace } = useSWR({ url: '/workspaces/current', params: {} }, fetchCurrentWorkspace) |
|
|
|
const { data: systemFeatures } = useSWR({ url: '/console/system-features' }, getSystemFeatures, { |
|
fallbackData: defaultSystemFeatures, |
|
}) |
|
|
|
const [userProfile, setUserProfile] = useState<UserProfileResponse>() |
|
const [langeniusVersionInfo, setLangeniusVersionInfo] = useState<LangGeniusVersionResponse>(initialLangeniusVersionInfo) |
|
const [currentWorkspace, setCurrentWorkspace] = useState<ICurrentWorkspace>(initialWorkspaceInfo) |
|
const isCurrentWorkspaceManager = useMemo(() => ['owner', 'admin'].includes(currentWorkspace.role), [currentWorkspace.role]) |
|
const isCurrentWorkspaceOwner = useMemo(() => currentWorkspace.role === 'owner', [currentWorkspace.role]) |
|
const isCurrentWorkspaceEditor = useMemo(() => ['owner', 'admin', 'editor'].includes(currentWorkspace.role), [currentWorkspace.role]) |
|
const isCurrentWorkspaceDatasetOperator = useMemo(() => currentWorkspace.role === 'dataset_operator', [currentWorkspace.role]) |
|
const updateUserProfileAndVersion = useCallback(async () => { |
|
if (userProfileResponse && !userProfileResponse.bodyUsed) { |
|
const result = await userProfileResponse.json() |
|
setUserProfile(result) |
|
const current_version = userProfileResponse.headers.get('x-version') |
|
const current_env = process.env.NODE_ENV === 'development' ? 'DEVELOPMENT' : userProfileResponse.headers.get('x-env') |
|
const versionData = await fetchLanggeniusVersion({ url: '/version', params: { current_version } }) |
|
setLangeniusVersionInfo({ ...versionData, current_version, latest_version: versionData.version, current_env }) |
|
} |
|
}, [userProfileResponse]) |
|
|
|
useEffect(() => { |
|
updateUserProfileAndVersion() |
|
}, [updateUserProfileAndVersion, userProfileResponse]) |
|
|
|
useEffect(() => { |
|
if (currentWorkspaceResponse) |
|
setCurrentWorkspace(currentWorkspaceResponse) |
|
}, [currentWorkspaceResponse]) |
|
|
|
const [theme, setTheme] = useState<Theme>(Theme.light) |
|
const handleSetTheme = useCallback((theme: Theme) => { |
|
setTheme(theme) |
|
globalThis.document.documentElement.setAttribute('data-theme', theme) |
|
}, []) |
|
|
|
useEffect(() => { |
|
globalThis.document.documentElement.setAttribute('data-theme', theme) |
|
|
|
}, []) |
|
|
|
if (!appList || !userProfile) |
|
return <Loading type='app' /> |
|
|
|
return ( |
|
<AppContext.Provider value={{ |
|
theme, |
|
setTheme: handleSetTheme, |
|
apps: appList.data, |
|
systemFeatures, |
|
mutateApps, |
|
userProfile, |
|
mutateUserProfile, |
|
pageContainerRef, |
|
langeniusVersionInfo, |
|
useSelector, |
|
currentWorkspace, |
|
isCurrentWorkspaceManager, |
|
isCurrentWorkspaceOwner, |
|
isCurrentWorkspaceEditor, |
|
isCurrentWorkspaceDatasetOperator, |
|
mutateCurrentWorkspace, |
|
}}> |
|
<div className='flex flex-col h-full overflow-y-auto'> |
|
{globalThis.document?.body?.getAttribute('data-public-maintenance-notice') && <MaintenanceNotice />} |
|
<div ref={pageContainerRef} className='grow relative flex flex-col overflow-y-auto overflow-x-hidden bg-background-body'> |
|
{children} |
|
</div> |
|
</div> |
|
</AppContext.Provider> |
|
) |
|
} |
|
|
|
export const useAppContext = () => useContext(AppContext) |
|
|
|
export default AppContext |
|
|