| import React from 'react' | import React from 'react' | ||||
| import type { ReactNode } from 'react' | import type { ReactNode } from 'react' | ||||
| import SwrInitor from '@/app/components/swr-initor' | |||||
| import SwrInitializer from '@/app/components/swr-initializer' | |||||
| import { AppContextProvider } from '@/context/app-context' | import { AppContextProvider } from '@/context/app-context' | ||||
| import GA, { GaType } from '@/app/components/base/ga' | import GA, { GaType } from '@/app/components/base/ga' | ||||
| import HeaderWrapper from '@/app/components/header/header-wrapper' | import HeaderWrapper from '@/app/components/header/header-wrapper' | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <GA gaType={GaType.admin} /> | <GA gaType={GaType.admin} /> | ||||
| <SwrInitor> | |||||
| <SwrInitializer> | |||||
| <AppContextProvider> | <AppContextProvider> | ||||
| <EventEmitterContextProvider> | <EventEmitterContextProvider> | ||||
| <ProviderContextProvider> | <ProviderContextProvider> | ||||
| </ProviderContextProvider> | </ProviderContextProvider> | ||||
| </EventEmitterContextProvider> | </EventEmitterContextProvider> | ||||
| </AppContextProvider> | </AppContextProvider> | ||||
| </SwrInitor> | |||||
| </SwrInitializer> | |||||
| </> | </> | ||||
| ) | ) | ||||
| } | } |
| 'use client' | 'use client' | ||||
| import { useState } from 'react' | import { useState } from 'react' | ||||
| import useSWR from 'swr' | |||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { | import { | ||||
| RiGraduationCapFill, | RiGraduationCapFill, | ||||
| import { useGlobalPublicStore } from '@/context/global-public-context' | import { useGlobalPublicStore } from '@/context/global-public-context' | ||||
| import EmailChangeModal from './email-change-modal' | import EmailChangeModal from './email-change-modal' | ||||
| import { validPassword } from '@/config' | import { validPassword } from '@/config' | ||||
| import { fetchAppList } from '@/service/apps' | |||||
| import type { App } from '@/types/app' | |||||
| const titleClassName = ` | const titleClassName = ` | ||||
| system-sm-semibold text-text-secondary | system-sm-semibold text-text-secondary | ||||
| export default function AccountPage() { | export default function AccountPage() { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { systemFeatures } = useGlobalPublicStore() | const { systemFeatures } = useGlobalPublicStore() | ||||
| const { mutateUserProfile, userProfile, apps } = useAppContext() | |||||
| const { data: appList } = useSWR({ url: '/apps', params: { page: 1, limit: 100, name: '' } }, fetchAppList) | |||||
| const apps = appList?.data || [] | |||||
| const { mutateUserProfile, userProfile } = useAppContext() | |||||
| const { isEducationAccount } = useProviderContext() | const { isEducationAccount } = useProviderContext() | ||||
| const { notify } = useContext(ToastContext) | const { notify } = useContext(ToastContext) | ||||
| const [editNameModalVisible, setEditNameModalVisible] = useState(false) | const [editNameModalVisible, setEditNameModalVisible] = useState(false) | ||||
| {!!apps.length && ( | {!!apps.length && ( | ||||
| <Collapse | <Collapse | ||||
| title={`${t('common.account.showAppLength', { length: apps.length })}`} | title={`${t('common.account.showAppLength', { length: apps.length })}`} | ||||
| items={apps.map(app => ({ ...app, key: app.id, name: app.name }))} | |||||
| items={apps.map((app: App) => ({ ...app, key: app.id, name: app.name }))} | |||||
| renderItem={renderAppItem} | renderItem={renderAppItem} | ||||
| wrapperClassName='mt-2' | wrapperClassName='mt-2' | ||||
| /> | /> |
| import React from 'react' | import React from 'react' | ||||
| import type { ReactNode } from 'react' | import type { ReactNode } from 'react' | ||||
| import Header from './header' | import Header from './header' | ||||
| import SwrInitor from '@/app/components/swr-initor' | |||||
| import SwrInitor from '@/app/components/swr-initializer' | |||||
| import { AppContextProvider } from '@/context/app-context' | import { AppContextProvider } from '@/context/app-context' | ||||
| import GA, { GaType } from '@/app/components/base/ga' | import GA, { GaType } from '@/app/components/base/ga' | ||||
| import HeaderWrapper from '@/app/components/header/header-wrapper' | import HeaderWrapper from '@/app/components/header/header-wrapper' |
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useContext, useContextSelector } from 'use-context-selector' | |||||
| import { useContext } from 'use-context-selector' | |||||
| import React, { useCallback, useState } from 'react' | import React, { useCallback, useState } from 'react' | ||||
| import { | import { | ||||
| RiDeleteBinLine, | RiDeleteBinLine, | ||||
| import cn from '@/utils/classnames' | import cn from '@/utils/classnames' | ||||
| import { useStore as useAppStore } from '@/app/components/app/store' | import { useStore as useAppStore } from '@/app/components/app/store' | ||||
| import { ToastContext } from '@/app/components/base/toast' | import { ToastContext } from '@/app/components/base/toast' | ||||
| import AppsContext, { useAppContext } from '@/context/app-context' | |||||
| import { useAppContext } from '@/context/app-context' | |||||
| import { useProviderContext } from '@/context/provider-context' | import { useProviderContext } from '@/context/provider-context' | ||||
| import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' | import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' | ||||
| import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' | import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' | ||||
| const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false) | const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false) | ||||
| const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([]) | const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([]) | ||||
| const mutateApps = useContextSelector( | |||||
| AppsContext, | |||||
| state => state.mutateApps, | |||||
| ) | |||||
| const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({ | const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({ | ||||
| name, | name, | ||||
| icon_type, | icon_type, | ||||
| message: t('app.editDone'), | message: t('app.editDone'), | ||||
| }) | }) | ||||
| setAppDetail(app) | setAppDetail(app) | ||||
| mutateApps() | |||||
| } | } | ||||
| catch { | catch { | ||||
| notify({ type: 'error', message: t('app.editFailed') }) | notify({ type: 'error', message: t('app.editFailed') }) | ||||
| } | } | ||||
| }, [appDetail, mutateApps, notify, setAppDetail, t]) | |||||
| }, [appDetail, notify, setAppDetail, t]) | |||||
| const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => { | const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => { | ||||
| if (!appDetail) | if (!appDetail) | ||||
| message: t('app.newApp.appCreated'), | message: t('app.newApp.appCreated'), | ||||
| }) | }) | ||||
| localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | ||||
| mutateApps() | |||||
| onPlanInfoChanged() | onPlanInfoChanged() | ||||
| getRedirection(true, newApp, replace) | getRedirection(true, newApp, replace) | ||||
| } | } | ||||
| try { | try { | ||||
| await deleteApp(appDetail.id) | await deleteApp(appDetail.id) | ||||
| notify({ type: 'success', message: t('app.appDeleted') }) | notify({ type: 'success', message: t('app.appDeleted') }) | ||||
| mutateApps() | |||||
| onPlanInfoChanged() | onPlanInfoChanged() | ||||
| setAppDetail() | setAppDetail() | ||||
| replace('/apps') | replace('/apps') | ||||
| }) | }) | ||||
| } | } | ||||
| setShowConfirmDelete(false) | setShowConfirmDelete(false) | ||||
| }, [appDetail, mutateApps, notify, onPlanInfoChanged, replace, setAppDetail, t]) | |||||
| }, [appDetail, notify, onPlanInfoChanged, replace, setAppDetail, t]) | |||||
| const { isCurrentWorkspaceEditor } = useAppContext() | const { isCurrentWorkspaceEditor } = useAppContext() | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useContext, useContextSelector } from 'use-context-selector' | |||||
| import { useContext } from 'use-context-selector' | |||||
| import { RiArrowRightLine, RiArrowRightSLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react' | import { RiArrowRightLine, RiArrowRightSLine, RiCommandLine, RiCornerDownLeftLine, RiExchange2Fill } from '@remixicon/react' | ||||
| import Link from 'next/link' | import Link from 'next/link' | ||||
| import { useDebounceFn, useKeyPress } from 'ahooks' | import { useDebounceFn, useKeyPress } from 'ahooks' | ||||
| import Divider from '@/app/components/base/divider' | import Divider from '@/app/components/base/divider' | ||||
| import cn from '@/utils/classnames' | import cn from '@/utils/classnames' | ||||
| import { basePath } from '@/utils/var' | import { basePath } from '@/utils/var' | ||||
| import AppsContext, { useAppContext } from '@/context/app-context' | |||||
| import { useAppContext } from '@/context/app-context' | |||||
| import { useProviderContext } from '@/context/provider-context' | import { useProviderContext } from '@/context/provider-context' | ||||
| import { ToastContext } from '@/app/components/base/toast' | import { ToastContext } from '@/app/components/base/toast' | ||||
| import type { AppMode } from '@/types/app' | import type { AppMode } from '@/types/app' | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { push } = useRouter() | const { push } = useRouter() | ||||
| const { notify } = useContext(ToastContext) | const { notify } = useContext(ToastContext) | ||||
| const mutateApps = useContextSelector(AppsContext, state => state.mutateApps) | |||||
| const [appMode, setAppMode] = useState<AppMode>('advanced-chat') | const [appMode, setAppMode] = useState<AppMode>('advanced-chat') | ||||
| const [appIcon, setAppIcon] = useState<AppIconSelection>({ type: 'emoji', icon: '🤖', background: '#FFEAD5' }) | const [appIcon, setAppIcon] = useState<AppIconSelection>({ type: 'emoji', icon: '🤖', background: '#FFEAD5' }) | ||||
| notify({ type: 'success', message: t('app.newApp.appCreated') }) | notify({ type: 'success', message: t('app.newApp.appCreated') }) | ||||
| onSuccess() | onSuccess() | ||||
| onClose() | onClose() | ||||
| mutateApps() | |||||
| localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | ||||
| getRedirection(isCurrentWorkspaceEditor, app, push) | getRedirection(isCurrentWorkspaceEditor, app, push) | ||||
| } | } | ||||
| notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) | notify({ type: 'error', message: t('app.newApp.appCreateFailed') }) | ||||
| } | } | ||||
| isCreatingRef.current = false | isCreatingRef.current = false | ||||
| }, [name, notify, t, appMode, appIcon, description, onSuccess, onClose, mutateApps, push, isCurrentWorkspaceEditor]) | |||||
| }, [name, notify, t, appMode, appIcon, description, onSuccess, onClose, push, isCurrentWorkspaceEditor]) | |||||
| const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 }) | const { run: handleCreateApp } = useDebounceFn(onCreate, { wait: 300 }) | ||||
| useKeyPress(['meta.enter', 'ctrl.enter'], () => { | useKeyPress(['meta.enter', 'ctrl.enter'], () => { |
| const [option, setOption] = useState<Option>('iframe') | const [option, setOption] = useState<Option>('iframe') | ||||
| const [isCopied, setIsCopied] = useState<OptionStatus>({ iframe: false, scripts: false, chromePlugin: false }) | const [isCopied, setIsCopied] = useState<OptionStatus>({ iframe: false, scripts: false, chromePlugin: false }) | ||||
| const { langeniusVersionInfo } = useAppContext() | |||||
| const { langGeniusVersionInfo } = useAppContext() | |||||
| const themeBuilder = useThemeContext() | const themeBuilder = useThemeContext() | ||||
| themeBuilder.buildTheme(siteInfo?.chat_color_theme ?? null, siteInfo?.chat_color_theme_inverted ?? false) | themeBuilder.buildTheme(siteInfo?.chat_color_theme ?? null, siteInfo?.chat_color_theme_inverted ?? false) | ||||
| const isTestEnv = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT' | |||||
| const isTestEnv = langGeniusVersionInfo.current_env === 'TESTING' || langGeniusVersionInfo.current_env === 'DEVELOPMENT' | |||||
| const onClickCopy = () => { | const onClickCopy = () => { | ||||
| if (option === 'chromePlugin') { | if (option === 'chromePlugin') { | ||||
| const splitUrl = OPTION_MAP[option].getContent(appBaseUrl, accessToken).split(': ') | const splitUrl = OPTION_MAP[option].getContent(appBaseUrl, accessToken).split(': ') |
| 'use client' | 'use client' | ||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react' | import React, { useCallback, useEffect, useMemo, useState } from 'react' | ||||
| import { useContext, useContextSelector } from 'use-context-selector' | |||||
| import { useContext } from 'use-context-selector' | |||||
| import { useRouter } from 'next/navigation' | import { useRouter } from 'next/navigation' | ||||
| import { useTranslation } from 'react-i18next' | import { useTranslation } from 'react-i18next' | ||||
| import { RiBuildingLine, RiGlobalLine, RiLockLine, RiMoreFill, RiVerifiedBadgeLine } from '@remixicon/react' | import { RiBuildingLine, RiGlobalLine, RiLockLine, RiMoreFill, RiVerifiedBadgeLine } from '@remixicon/react' | ||||
| import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' | import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' | ||||
| import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' | import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' | ||||
| import AppIcon from '@/app/components/base/app-icon' | import AppIcon from '@/app/components/base/app-icon' | ||||
| import AppsContext, { useAppContext } from '@/context/app-context' | |||||
| import { useAppContext } from '@/context/app-context' | |||||
| import type { HtmlContentProps } from '@/app/components/base/popover' | import type { HtmlContentProps } from '@/app/components/base/popover' | ||||
| import CustomPopover from '@/app/components/base/popover' | import CustomPopover from '@/app/components/base/popover' | ||||
| import Divider from '@/app/components/base/divider' | import Divider from '@/app/components/base/divider' | ||||
| const { onPlanInfoChanged } = useProviderContext() | const { onPlanInfoChanged } = useProviderContext() | ||||
| const { push } = useRouter() | const { push } = useRouter() | ||||
| const mutateApps = useContextSelector( | |||||
| AppsContext, | |||||
| state => state.mutateApps, | |||||
| ) | |||||
| const [showEditModal, setShowEditModal] = useState(false) | const [showEditModal, setShowEditModal] = useState(false) | ||||
| const [showDuplicateModal, setShowDuplicateModal] = useState(false) | const [showDuplicateModal, setShowDuplicateModal] = useState(false) | ||||
| const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false) | const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false) | ||||
| notify({ type: 'success', message: t('app.appDeleted') }) | notify({ type: 'success', message: t('app.appDeleted') }) | ||||
| if (onRefresh) | if (onRefresh) | ||||
| onRefresh() | onRefresh() | ||||
| mutateApps() | |||||
| onPlanInfoChanged() | onPlanInfoChanged() | ||||
| } | } | ||||
| catch (e: any) { | catch (e: any) { | ||||
| }) | }) | ||||
| } | } | ||||
| setShowConfirmDelete(false) | setShowConfirmDelete(false) | ||||
| }, [app.id, mutateApps, notify, onPlanInfoChanged, onRefresh, t]) | |||||
| }, [app.id, notify, onPlanInfoChanged, onRefresh, t]) | |||||
| const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({ | const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({ | ||||
| name, | name, | ||||
| }) | }) | ||||
| if (onRefresh) | if (onRefresh) | ||||
| onRefresh() | onRefresh() | ||||
| mutateApps() | |||||
| } | } | ||||
| catch { | catch { | ||||
| notify({ type: 'error', message: t('app.editFailed') }) | notify({ type: 'error', message: t('app.editFailed') }) | ||||
| } | } | ||||
| }, [app.id, mutateApps, notify, onRefresh, t]) | |||||
| }, [app.id, notify, onRefresh, t]) | |||||
| const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => { | const onCopy: DuplicateAppModalProps['onConfirm'] = async ({ name, icon_type, icon, icon_background }) => { | ||||
| try { | try { | ||||
| localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') | ||||
| if (onRefresh) | if (onRefresh) | ||||
| onRefresh() | onRefresh() | ||||
| mutateApps() | |||||
| onPlanInfoChanged() | onPlanInfoChanged() | ||||
| getRedirection(isCurrentWorkspaceEditor, newApp, push) | getRedirection(isCurrentWorkspaceEditor, newApp, push) | ||||
| } | } | ||||
| const onSwitch = () => { | const onSwitch = () => { | ||||
| if (onRefresh) | if (onRefresh) | ||||
| onRefresh() | onRefresh() | ||||
| mutateApps() | |||||
| setShowSwitchModal(false) | setShowSwitchModal(false) | ||||
| } | } | ||||
| const onUpdateAccessControl = useCallback(() => { | const onUpdateAccessControl = useCallback(() => { | ||||
| if (onRefresh) | if (onRefresh) | ||||
| onRefresh() | onRefresh() | ||||
| mutateApps() | |||||
| setShowAccessControl(false) | setShowAccessControl(false) | ||||
| }, [onRefresh, mutateApps, setShowAccessControl]) | |||||
| }, [onRefresh, setShowAccessControl]) | |||||
| const Operations = (props: HtmlContentProps) => { | const Operations = (props: HtmlContentProps) => { | ||||
| const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp } = useGetUserCanAccessApp({ appId: app?.id, enabled: (!!props?.open && systemFeatures.webapp_auth.enabled) }) | const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp } = useGetUserCanAccessApp({ appId: app?.id, enabled: (!!props?.open && systemFeatures.webapp_auth.enabled) }) | ||||
| dateFormat: `${t('datasetDocuments.segment.dateTimeFormat')}`, | dateFormat: `${t('datasetDocuments.segment.dateTimeFormat')}`, | ||||
| }) | }) | ||||
| return `${t('datasetDocuments.segment.editedAt')} ${timeText}` | return `${t('datasetDocuments.segment.editedAt')} ${timeText}` | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, [app.updated_at, app.created_at]) | }, [app.updated_at, app.created_at]) | ||||
| return ( | return ( |
| className={cn(textClassName, 'scale-[0.4] text-center text-white')} | className={cn(textClassName, 'scale-[0.4] text-center text-white')} | ||||
| style={style} | style={style} | ||||
| > | > | ||||
| {name[0].toLocaleUpperCase()} | |||||
| {name && name[0].toLocaleUpperCase()} | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| ) | ) |
| }) => { | }) => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { plan } = useProviderContext() | const { plan } = useProviderContext() | ||||
| const { userProfile, langeniusVersionInfo } = useAppContext() | |||||
| const { userProfile, langGeniusVersionInfo } = useAppContext() | |||||
| const isTeam = plan.type === Plan.team | const isTeam = plan.type === Plan.team | ||||
| const usage = plan.usage.buildApps | const usage = plan.usage.buildApps | ||||
| const total = plan.total.buildApps | const total = plan.total.buildApps | ||||
| )} | )} | ||||
| {plan.type !== Plan.sandbox && plan.type !== Plan.professional && ( | {plan.type !== Plan.sandbox && plan.type !== Plan.professional && ( | ||||
| <Button variant='secondary-accent'> | <Button variant='secondary-accent'> | ||||
| <a target='_blank' rel='noopener noreferrer' href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)}> | |||||
| <a target='_blank' rel='noopener noreferrer' href={mailToSupport(userProfile.email, plan.type, langGeniusVersionInfo.current_version)}> | |||||
| {t('billing.apps.contactUs')} | {t('billing.apps.contactUs')} | ||||
| </a> | </a> | ||||
| </Button> | </Button> |
| value: sessionStorage, | value: sessionStorage, | ||||
| }) | }) | ||||
| const BrowserInitor = ({ | |||||
| const BrowserInitializer = ({ | |||||
| children, | children, | ||||
| }: { children: React.ReactNode }) => { | |||||
| }: { children: React.ReactElement }) => { | |||||
| return children | return children | ||||
| } | } | ||||
| export default BrowserInitor | |||||
| export default BrowserInitializer |
| import { useGlobalPublicStore } from '@/context/global-public-context' | import { useGlobalPublicStore } from '@/context/global-public-context' | ||||
| type IAccountSettingProps = { | type IAccountSettingProps = { | ||||
| langeniusVersionInfo: LangGeniusVersionResponse | |||||
| langGeniusVersionInfo: LangGeniusVersionResponse | |||||
| onCancel: () => void | onCancel: () => void | ||||
| } | } | ||||
| export default function AccountAbout({ | export default function AccountAbout({ | ||||
| langeniusVersionInfo, | |||||
| langGeniusVersionInfo, | |||||
| onCancel, | onCancel, | ||||
| }: IAccountSettingProps) { | }: IAccountSettingProps) { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const isLatest = langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version | |||||
| const isLatest = langGeniusVersionInfo.current_version === langGeniusVersionInfo.latest_version | |||||
| const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) | const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) | ||||
| return ( | return ( | ||||
| /> | /> | ||||
| : <DifyLogo size='large' className='mx-auto' />} | : <DifyLogo size='large' className='mx-auto' />} | ||||
| <div className='text-center text-xs font-normal text-text-tertiary'>Version {langeniusVersionInfo?.current_version}</div> | |||||
| <div className='text-center text-xs font-normal text-text-tertiary'>Version {langGeniusVersionInfo?.current_version}</div> | |||||
| <div className='flex flex-col items-center gap-2 text-center text-xs font-normal text-text-secondary'> | <div className='flex flex-col items-center gap-2 text-center text-xs font-normal text-text-secondary'> | ||||
| <div>© {dayjs().year()} LangGenius, Inc., Contributors.</div> | <div>© {dayjs().year()} LangGenius, Inc., Contributors.</div> | ||||
| <div className='text-text-accent'> | <div className='text-text-accent'> | ||||
| <div className='text-xs font-medium text-text-tertiary'> | <div className='text-xs font-medium text-text-tertiary'> | ||||
| { | { | ||||
| isLatest | isLatest | ||||
| ? t('common.about.latestAvailable', { version: langeniusVersionInfo.latest_version }) | |||||
| : t('common.about.nowAvailable', { version: langeniusVersionInfo.latest_version }) | |||||
| ? t('common.about.latestAvailable', { version: langGeniusVersionInfo.latest_version }) | |||||
| : t('common.about.nowAvailable', { version: langGeniusVersionInfo.latest_version }) | |||||
| } | } | ||||
| </div> | </div> | ||||
| <div className='flex items-center'> | <div className='flex items-center'> | ||||
| !isLatest && !IS_CE_EDITION && ( | !isLatest && !IS_CE_EDITION && ( | ||||
| <Button variant='primary' size='small'> | <Button variant='primary' size='small'> | ||||
| <Link | <Link | ||||
| href={langeniusVersionInfo.release_notes} | |||||
| href={langGeniusVersionInfo.release_notes} | |||||
| target='_blank' rel='noopener noreferrer' | target='_blank' rel='noopener noreferrer' | ||||
| > | > | ||||
| {t('common.about.updateNow')} | {t('common.about.updateNow')} |
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const docLink = useDocLink() | const docLink = useDocLink() | ||||
| const { userProfile, langeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext() | |||||
| const { userProfile, langGeniusVersionInfo, isCurrentWorkspaceOwner } = useAppContext() | |||||
| const { isEducationAccount } = useProviderContext() | const { isEducationAccount } = useProviderContext() | ||||
| const { setShowAccountSettingModal } = useModalContext() | const { setShowAccountSettingModal } = useModalContext() | ||||
| <RiInformation2Line className='size-4 shrink-0 text-text-tertiary' /> | <RiInformation2Line className='size-4 shrink-0 text-text-tertiary' /> | ||||
| <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.about')}</div> | <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.about')}</div> | ||||
| <div className='flex shrink-0 items-center'> | <div className='flex shrink-0 items-center'> | ||||
| <div className='system-xs-regular mr-2 text-text-tertiary'>{langeniusVersionInfo.current_version}</div> | |||||
| <Indicator color={langeniusVersionInfo.current_version === langeniusVersionInfo.latest_version ? 'green' : 'orange'} /> | |||||
| <div className='system-xs-regular mr-2 text-text-tertiary'>{langGeniusVersionInfo.current_version}</div> | |||||
| <Indicator color={langGeniusVersionInfo.current_version === langGeniusVersionInfo.latest_version ? 'green' : 'orange'} /> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </MenuItem> | </MenuItem> | ||||
| } | } | ||||
| </Menu> | </Menu> | ||||
| { | { | ||||
| aboutVisible && <AccountAbout onCancel={() => setAboutVisible(false)} langeniusVersionInfo={langeniusVersionInfo} /> | |||||
| aboutVisible && <AccountAbout onCancel={() => setAboutVisible(false)} langGeniusVersionInfo={langGeniusVersionInfo} /> | |||||
| } | } | ||||
| </div > | </div > | ||||
| ) | ) |
| ` | ` | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { plan } = useProviderContext() | const { plan } = useProviderContext() | ||||
| const { userProfile, langeniusVersionInfo } = useAppContext() | |||||
| const { userProfile, langGeniusVersionInfo } = useAppContext() | |||||
| const canEmailSupport = plan.type === Plan.professional || plan.type === Plan.team || plan.type === Plan.enterprise | const canEmailSupport = plan.type === Plan.professional || plan.type === Plan.team || plan.type === Plan.enterprise | ||||
| return <Menu as="div" className="relative h-full w-full"> | return <Menu as="div" className="relative h-full w-full"> | ||||
| className={cn(itemClassName, 'group justify-between', | className={cn(itemClassName, 'group justify-between', | ||||
| 'data-[active]:bg-state-base-hover', | 'data-[active]:bg-state-base-hover', | ||||
| )} | )} | ||||
| href={mailToSupport(userProfile.email, plan.type, langeniusVersionInfo.current_version)} | |||||
| href={mailToSupport(userProfile.email, plan.type, langGeniusVersionInfo.current_version)} | |||||
| target='_blank' rel='noopener noreferrer'> | target='_blank' rel='noopener noreferrer'> | ||||
| <RiMailSendLine className='size-4 shrink-0 text-text-tertiary' /> | <RiMailSendLine className='size-4 shrink-0 text-text-tertiary' /> | ||||
| <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.emailSupport')}</div> | <div className='system-md-regular grow px-1 text-text-secondary'>{t('common.userProfile.emailSupport')}</div> |
| const EnvNav = () => { | const EnvNav = () => { | ||||
| const { t } = useTranslation() | const { t } = useTranslation() | ||||
| const { langeniusVersionInfo } = useAppContext() | |||||
| const showEnvTag = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT' | |||||
| const { langGeniusVersionInfo } = useAppContext() | |||||
| const showEnvTag = langGeniusVersionInfo.current_env === 'TESTING' || langGeniusVersionInfo.current_env === 'DEVELOPMENT' | |||||
| if (!showEnvTag) | if (!showEnvTag) | ||||
| return null | return null | ||||
| return ( | return ( | ||||
| <div className={` | <div className={` | ||||
| mr-1 flex h-[22px] items-center rounded-md border px-2 text-xs font-medium | mr-1 flex h-[22px] items-center rounded-md border px-2 text-xs font-medium | ||||
| ${headerEnvClassName[langeniusVersionInfo.current_env]} | |||||
| ${headerEnvClassName[langGeniusVersionInfo.current_env]} | |||||
| `}> | `}> | ||||
| { | { | ||||
| langeniusVersionInfo.current_env === 'TESTING' && ( | |||||
| langGeniusVersionInfo.current_env === 'TESTING' && ( | |||||
| <> | <> | ||||
| <Beaker02 className='h-3 w-3' /> | <Beaker02 className='h-3 w-3' /> | ||||
| <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.testing')}</div> | <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.testing')}</div> | ||||
| ) | ) | ||||
| } | } | ||||
| { | { | ||||
| langeniusVersionInfo.current_env === 'DEVELOPMENT' && ( | |||||
| langGeniusVersionInfo.current_env === 'DEVELOPMENT' && ( | |||||
| <> | <> | ||||
| <TerminalSquare className='h-3 w-3' /> | <TerminalSquare className='h-3 w-3' /> | ||||
| <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.development')}</div> | <div className='ml-1 max-[1280px]:hidden'>{t('common.environment.development')}</div> |
| useEffect(() => { | useEffect(() => { | ||||
| if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier) | if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier) | ||||
| onInstalled() | onInstalled() | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, [hasInstalled]) | }, [hasInstalled]) | ||||
| const [isInstalling, setIsInstalling] = React.useState(false) | const [isInstalling, setIsInstalling] = React.useState(false) | ||||
| } | } | ||||
| } | } | ||||
| const { langeniusVersionInfo } = useAppContext() | |||||
| const { langGeniusVersionInfo } = useAppContext() | |||||
| const isDifyVersionCompatible = useMemo(() => { | const isDifyVersionCompatible = useMemo(() => { | ||||
| if (!langeniusVersionInfo.current_version) | |||||
| if (!langGeniusVersionInfo.current_version) | |||||
| return true | return true | ||||
| return gte(langeniusVersionInfo.current_version, payload.meta.minimum_dify_version ?? '0.0.0') | |||||
| }, [langeniusVersionInfo.current_version, payload.meta.minimum_dify_version]) | |||||
| return gte(langGeniusVersionInfo.current_version, payload.meta.minimum_dify_version ?? '0.0.0') | |||||
| }, [langGeniusVersionInfo.current_version, payload.meta.minimum_dify_version]) | |||||
| return ( | return ( | ||||
| <> | <> |
| useEffect(() => { | useEffect(() => { | ||||
| if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier) | if (hasInstalled && uniqueIdentifier === installedInfoPayload.uniqueIdentifier) | ||||
| onInstalled() | onInstalled() | ||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, [hasInstalled]) | }, [hasInstalled]) | ||||
| const handleCancel = () => { | const handleCancel = () => { | ||||
| } | } | ||||
| } | } | ||||
| const { langeniusVersionInfo } = useAppContext() | |||||
| const { langGeniusVersionInfo } = useAppContext() | |||||
| const { data: pluginDeclaration } = usePluginDeclarationFromMarketPlace(uniqueIdentifier) | const { data: pluginDeclaration } = usePluginDeclarationFromMarketPlace(uniqueIdentifier) | ||||
| const isDifyVersionCompatible = useMemo(() => { | const isDifyVersionCompatible = useMemo(() => { | ||||
| if (!pluginDeclaration || !langeniusVersionInfo.current_version) return true | |||||
| return gte(langeniusVersionInfo.current_version, pluginDeclaration?.manifest.meta.minimum_dify_version ?? '0.0.0') | |||||
| }, [langeniusVersionInfo.current_version, pluginDeclaration]) | |||||
| if (!pluginDeclaration || !langGeniusVersionInfo.current_version) return true | |||||
| return gte(langGeniusVersionInfo.current_version, pluginDeclaration?.manifest.meta.minimum_dify_version ?? '0.0.0') | |||||
| }, [langGeniusVersionInfo.current_version, pluginDeclaration]) | |||||
| const { canInstall } = useInstallPluginLimit({ ...payload, from: 'marketplace' }) | const { canInstall } = useInstallPluginLimit({ ...payload, from: 'marketplace' }) | ||||
| return ( | return ( |
| return [PluginSource.github, PluginSource.marketplace].includes(source) ? author : '' | return [PluginSource.github, PluginSource.marketplace].includes(source) ? author : '' | ||||
| }, [source, author]) | }, [source, author]) | ||||
| const { langeniusVersionInfo } = useAppContext() | |||||
| const { langGeniusVersionInfo } = useAppContext() | |||||
| const isDifyVersionCompatible = useMemo(() => { | const isDifyVersionCompatible = useMemo(() => { | ||||
| if (!langeniusVersionInfo.current_version) | |||||
| if (!langGeniusVersionInfo.current_version) | |||||
| return true | return true | ||||
| return gte(langeniusVersionInfo.current_version, declarationMeta.minimum_dify_version ?? '0.0.0') | |||||
| }, [declarationMeta.minimum_dify_version, langeniusVersionInfo.current_version]) | |||||
| return gte(langGeniusVersionInfo.current_version, declarationMeta.minimum_dify_version ?? '0.0.0') | |||||
| }, [declarationMeta.minimum_dify_version, langGeniusVersionInfo.current_version]) | |||||
| const handleDelete = () => { | const handleDelete = () => { | ||||
| refreshPluginList({ category } as any) | refreshPluginList({ category } as any) |
| const isDevelopment = process.env.NODE_ENV === 'development' | const isDevelopment = process.env.NODE_ENV === 'development' | ||||
| const SentryInit = ({ | |||||
| const SentryInitializer = ({ | |||||
| children, | children, | ||||
| }: { children: React.ReactNode }) => { | |||||
| }: { children: React.ReactElement }) => { | |||||
| useEffect(() => { | useEffect(() => { | ||||
| const SENTRY_DSN = document?.body?.getAttribute('data-public-sentry-dsn') | const SENTRY_DSN = document?.body?.getAttribute('data-public-sentry-dsn') | ||||
| if (!isDevelopment && SENTRY_DSN) { | if (!isDevelopment && SENTRY_DSN) { | ||||
| return children | return children | ||||
| } | } | ||||
| export default SentryInit | |||||
| export default SentryInitializer |
| EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION, | EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION, | ||||
| } from '@/app/education-apply/constants' | } from '@/app/education-apply/constants' | ||||
| type SwrInitorProps = { | |||||
| type SwrInitializerProps = { | |||||
| children: ReactNode | children: ReactNode | ||||
| } | } | ||||
| const SwrInitor = ({ | |||||
| const SwrInitializer = ({ | |||||
| children, | children, | ||||
| }: SwrInitorProps) => { | |||||
| }: SwrInitializerProps) => { | |||||
| const router = useRouter() | const router = useRouter() | ||||
| const searchParams = useSearchParams() | const searchParams = useSearchParams() | ||||
| const consoleToken = decodeURIComponent(searchParams.get('access_token') || '') | const consoleToken = decodeURIComponent(searchParams.get('access_token') || '') | ||||
| : null | : null | ||||
| } | } | ||||
| export default SwrInitor | |||||
| export default SwrInitializer |
| import RoutePrefixHandle from './routePrefixHandle' | import RoutePrefixHandle from './routePrefixHandle' | ||||
| import type { Viewport } from 'next' | import type { Viewport } from 'next' | ||||
| import I18nServer from './components/i18n-server' | import I18nServer from './components/i18n-server' | ||||
| import BrowserInitor from './components/browser-initor' | |||||
| import SentryInitor from './components/sentry-initor' | |||||
| import BrowserInitializer from './components/browser-initializer' | |||||
| import SentryInitializer from './components/sentry-initializer' | |||||
| import { getLocaleOnServer } from '@/i18n/server' | import { getLocaleOnServer } from '@/i18n/server' | ||||
| import { TanstackQueryIniter } from '@/context/query-client' | |||||
| import { TanstackQueryInitializer } from '@/context/query-client' | |||||
| import { ThemeProvider } from 'next-themes' | import { ThemeProvider } from 'next-themes' | ||||
| import './styles/globals.css' | import './styles/globals.css' | ||||
| import './styles/markdown.scss' | import './styles/markdown.scss' | ||||
| className="color-scheme h-full select-auto" | className="color-scheme h-full select-auto" | ||||
| {...datasetMap} | {...datasetMap} | ||||
| > | > | ||||
| <BrowserInitor> | |||||
| <SentryInitor> | |||||
| <TanstackQueryIniter> | |||||
| <BrowserInitializer> | |||||
| <SentryInitializer> | |||||
| <TanstackQueryInitializer> | |||||
| <ThemeProvider | <ThemeProvider | ||||
| attribute='data-theme' | attribute='data-theme' | ||||
| defaultTheme='system' | defaultTheme='system' | ||||
| </GlobalPublicStoreProvider> | </GlobalPublicStoreProvider> | ||||
| </I18nServer> | </I18nServer> | ||||
| </ThemeProvider> | </ThemeProvider> | ||||
| </TanstackQueryIniter> | |||||
| </SentryInitor> | |||||
| </BrowserInitor> | |||||
| </TanstackQueryInitializer> | |||||
| </SentryInitializer> | |||||
| </BrowserInitializer> | |||||
| <RoutePrefixHandle /> | <RoutePrefixHandle /> | ||||
| </body> | </body> | ||||
| </html> | </html> |
| 'use client' | 'use client' | ||||
| import { createRef, useCallback, useEffect, useMemo, useRef, useState } from 'react' | |||||
| import { useCallback, useEffect, useMemo, useState } from 'react' | |||||
| import useSWR from 'swr' | import useSWR from 'swr' | ||||
| import { createContext, useContext, useContextSelector } from 'use-context-selector' | import { createContext, useContext, useContextSelector } from 'use-context-selector' | ||||
| import type { FC, ReactNode } from 'react' | import type { FC, ReactNode } from 'react' | ||||
| import { fetchAppList } from '@/service/apps' | |||||
| import Loading from '@/app/components/base/loading' | |||||
| import { fetchCurrentWorkspace, fetchLanggeniusVersion, fetchUserProfile } from '@/service/common' | |||||
| import type { App } from '@/types/app' | |||||
| import { fetchCurrentWorkspace, fetchLangGeniusVersion, fetchUserProfile } from '@/service/common' | |||||
| import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common' | import type { ICurrentWorkspace, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common' | ||||
| import MaintenanceNotice from '@/app/components/header/maintenance-notice' | import MaintenanceNotice from '@/app/components/header/maintenance-notice' | ||||
| import { noop } from 'lodash-es' | import { noop } from 'lodash-es' | ||||
| export type AppContextValue = { | export type AppContextValue = { | ||||
| apps: App[] | |||||
| mutateApps: VoidFunction | |||||
| userProfile: UserProfileResponse | userProfile: UserProfileResponse | ||||
| mutateUserProfile: VoidFunction | mutateUserProfile: VoidFunction | ||||
| currentWorkspace: ICurrentWorkspace | currentWorkspace: ICurrentWorkspace | ||||
| isCurrentWorkspaceEditor: boolean | isCurrentWorkspaceEditor: boolean | ||||
| isCurrentWorkspaceDatasetOperator: boolean | isCurrentWorkspaceDatasetOperator: boolean | ||||
| mutateCurrentWorkspace: VoidFunction | mutateCurrentWorkspace: VoidFunction | ||||
| pageContainerRef: React.RefObject<HTMLDivElement> | |||||
| langeniusVersionInfo: LangGeniusVersionResponse | |||||
| langGeniusVersionInfo: LangGeniusVersionResponse | |||||
| useSelector: typeof useSelector | useSelector: typeof useSelector | ||||
| isLoadingCurrentWorkspace: boolean | isLoadingCurrentWorkspace: boolean | ||||
| } | } | ||||
| const initialLangeniusVersionInfo = { | |||||
| const userProfilePlaceholder = { | |||||
| id: '', | |||||
| name: '', | |||||
| email: '', | |||||
| avatar: '', | |||||
| avatar_url: '', | |||||
| is_password_set: false, | |||||
| } | |||||
| const initialLangGeniusVersionInfo = { | |||||
| current_env: '', | current_env: '', | ||||
| current_version: '', | current_version: '', | ||||
| latest_version: '', | latest_version: '', | ||||
| } | } | ||||
| const AppContext = createContext<AppContextValue>({ | const AppContext = createContext<AppContextValue>({ | ||||
| apps: [], | |||||
| mutateApps: noop, | |||||
| userProfile: { | |||||
| id: '', | |||||
| name: '', | |||||
| email: '', | |||||
| avatar: '', | |||||
| avatar_url: '', | |||||
| is_password_set: false, | |||||
| }, | |||||
| userProfile: userProfilePlaceholder, | |||||
| currentWorkspace: initialWorkspaceInfo, | currentWorkspace: initialWorkspaceInfo, | ||||
| isCurrentWorkspaceManager: false, | isCurrentWorkspaceManager: false, | ||||
| isCurrentWorkspaceOwner: false, | isCurrentWorkspaceOwner: false, | ||||
| isCurrentWorkspaceDatasetOperator: false, | isCurrentWorkspaceDatasetOperator: false, | ||||
| mutateUserProfile: noop, | mutateUserProfile: noop, | ||||
| mutateCurrentWorkspace: noop, | mutateCurrentWorkspace: noop, | ||||
| pageContainerRef: createRef(), | |||||
| langeniusVersionInfo: initialLangeniusVersionInfo, | |||||
| langGeniusVersionInfo: initialLangGeniusVersionInfo, | |||||
| useSelector, | useSelector, | ||||
| isLoadingCurrentWorkspace: false, | isLoadingCurrentWorkspace: false, | ||||
| }) | }) | ||||
| } | } | ||||
| export const AppContextProvider: FC<AppContextProviderProps> = ({ children }) => { | 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: userProfileResponse, mutate: mutateUserProfile } = useSWR({ url: '/account/profile', params: {} }, fetchUserProfile) | ||||
| const { data: currentWorkspaceResponse, mutate: mutateCurrentWorkspace, isLoading: isLoadingCurrentWorkspace } = useSWR({ url: '/workspaces/current', params: {} }, fetchCurrentWorkspace) | const { data: currentWorkspaceResponse, mutate: mutateCurrentWorkspace, isLoading: isLoadingCurrentWorkspace } = useSWR({ url: '/workspaces/current', params: {} }, fetchCurrentWorkspace) | ||||
| const [userProfile, setUserProfile] = useState<UserProfileResponse>() | |||||
| const [langeniusVersionInfo, setLangeniusVersionInfo] = useState<LangGeniusVersionResponse>(initialLangeniusVersionInfo) | |||||
| const [userProfile, setUserProfile] = useState<UserProfileResponse>(userProfilePlaceholder) | |||||
| const [langGeniusVersionInfo, setLangGeniusVersionInfo] = useState<LangGeniusVersionResponse>(initialLangGeniusVersionInfo) | |||||
| const [currentWorkspace, setCurrentWorkspace] = useState<ICurrentWorkspace>(initialWorkspaceInfo) | const [currentWorkspace, setCurrentWorkspace] = useState<ICurrentWorkspace>(initialWorkspaceInfo) | ||||
| const isCurrentWorkspaceManager = useMemo(() => ['owner', 'admin'].includes(currentWorkspace.role), [currentWorkspace.role]) | const isCurrentWorkspaceManager = useMemo(() => ['owner', 'admin'].includes(currentWorkspace.role), [currentWorkspace.role]) | ||||
| const isCurrentWorkspaceOwner = useMemo(() => currentWorkspace.role === 'owner', [currentWorkspace.role]) | const isCurrentWorkspaceOwner = useMemo(() => currentWorkspace.role === 'owner', [currentWorkspace.role]) | ||||
| setUserProfile(result) | setUserProfile(result) | ||||
| const current_version = userProfileResponse.headers.get('x-version') | const current_version = userProfileResponse.headers.get('x-version') | ||||
| const current_env = process.env.NODE_ENV === 'development' ? 'DEVELOPMENT' : userProfileResponse.headers.get('x-env') | 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 }) | |||||
| const versionData = await fetchLangGeniusVersion({ url: '/version', params: { current_version } }) | |||||
| setLangGeniusVersionInfo({ ...versionData, current_version, latest_version: versionData.version, current_env }) | |||||
| } | } | ||||
| }, [userProfileResponse]) | }, [userProfileResponse]) | ||||
| setCurrentWorkspace(currentWorkspaceResponse) | setCurrentWorkspace(currentWorkspaceResponse) | ||||
| }, [currentWorkspaceResponse]) | }, [currentWorkspaceResponse]) | ||||
| if (!appList || !userProfile) | |||||
| return <Loading type='app' /> | |||||
| return ( | return ( | ||||
| <AppContext.Provider value={{ | <AppContext.Provider value={{ | ||||
| apps: appList.data, | |||||
| mutateApps, | |||||
| userProfile, | userProfile, | ||||
| mutateUserProfile, | mutateUserProfile, | ||||
| pageContainerRef, | |||||
| langeniusVersionInfo, | |||||
| langGeniusVersionInfo, | |||||
| useSelector, | useSelector, | ||||
| currentWorkspace, | currentWorkspace, | ||||
| isCurrentWorkspaceManager, | isCurrentWorkspaceManager, | ||||
| }}> | }}> | ||||
| <div className='flex h-full flex-col overflow-y-auto'> | <div className='flex h-full flex-col overflow-y-auto'> | ||||
| {globalThis.document?.body?.getAttribute('data-public-maintenance-notice') && <MaintenanceNotice />} | {globalThis.document?.body?.getAttribute('data-public-maintenance-notice') && <MaintenanceNotice />} | ||||
| <div ref={pageContainerRef} className='relative flex grow flex-col overflow-y-auto overflow-x-hidden bg-background-body'> | |||||
| <div className='relative flex grow flex-col overflow-y-auto overflow-x-hidden bg-background-body'> | |||||
| {children} | {children} | ||||
| </div> | </div> | ||||
| </div> | </div> |
| }, | }, | ||||
| }) | }) | ||||
| export const TanstackQueryIniter: FC<PropsWithChildren> = (props) => { | |||||
| export const TanstackQueryInitializer: FC<PropsWithChildren> = (props) => { | |||||
| const { children } = props | const { children } = props | ||||
| return <QueryClientProvider client={client}> | return <QueryClientProvider client={client}> | ||||
| {children} | {children} |
| return get<CommonResponse>(url, params) | return get<CommonResponse>(url, params) | ||||
| } | } | ||||
| export const fetchLanggeniusVersion: Fetcher<LangGeniusVersionResponse, { url: string; params: Record<string, any> }> = ({ url, params }) => { | |||||
| export const fetchLangGeniusVersion: Fetcher<LangGeniusVersionResponse, { url: string; params: Record<string, any> }> = ({ url, params }) => { | |||||
| return get<LangGeniusVersionResponse>(url, { params }) | return get<LangGeniusVersionResponse>(url, { params }) | ||||
| } | } | ||||