mirror of
https://github.com/langgenius/dify.git
synced 2026-05-02 16:38:04 +08:00
Problems: - Identical useEffect + router.replace guard for dataset_operator role duplicated across 4 leaf components (tools/page, appDetail/layout, explore/index, apps/list), violating DRY and risking permission gaps when new routes are added - datasets/list had a redundant role guard already covered by datasets/layout - datasets/layout used useEffect for redirect, causing content flash - useEffect-based guards render unauthorized content before redirect - explore/index used useState + useEffect to derive hasEditPermission, an unnecessary render cycle (rerender-derived-state-no-effect) - apps/list imported 6 @remixicon/react components instead of using Tailwind CSS icon classes, inflating JS bundle - apps/list contained unused validTabs Set (dead code) Solutions: - Create RoleRouteGuard component at (commonLayout)/layout.tsx level that synchronously checks role during render and returns null before children mount, preventing content flash - Remove all 5 duplicated useEffect guards from leaf components - Replace datasets/layout useEffect guard with synchronous render check - Derive hasEditPermission directly during render in explore/index - Replace @remixicon/react imports with i-ri-* CSS icon classes - Remove dead code (validTabs)
71 lines
2.4 KiB
TypeScript
71 lines
2.4 KiB
TypeScript
'use client'
|
|
import type { FC } from 'react'
|
|
import type { CurrentTryAppParams } from '@/context/explore-context'
|
|
import type { InstalledApp } from '@/models/explore'
|
|
import * as React from 'react'
|
|
import { useState } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import Sidebar from '@/app/components/explore/sidebar'
|
|
import { useAppContext } from '@/context/app-context'
|
|
import ExploreContext from '@/context/explore-context'
|
|
import useDocumentTitle from '@/hooks/use-document-title'
|
|
import { useMembers } from '@/service/use-common'
|
|
|
|
export type IExploreProps = {
|
|
children: React.ReactNode
|
|
}
|
|
|
|
const Explore: FC<IExploreProps> = ({
|
|
children,
|
|
}) => {
|
|
const [controlUpdateInstalledApps, setControlUpdateInstalledApps] = useState(0)
|
|
const { userProfile } = useAppContext()
|
|
const [installedApps, setInstalledApps] = useState<InstalledApp[]>([])
|
|
const [isFetchingInstalledApps, setIsFetchingInstalledApps] = useState(false)
|
|
const { t } = useTranslation()
|
|
const { data: membersData } = useMembers()
|
|
|
|
useDocumentTitle(t('menus.explore', { ns: 'common' }))
|
|
|
|
const hasEditPermission = membersData?.accounts
|
|
? membersData.accounts.find(account => account.id === userProfile.id)?.role !== 'normal'
|
|
: false
|
|
|
|
const [currentTryAppParams, setCurrentTryAppParams] = useState<CurrentTryAppParams | undefined>(undefined)
|
|
const [isShowTryAppPanel, setIsShowTryAppPanel] = useState(false)
|
|
const setShowTryAppPanel = (showTryAppPanel: boolean, params?: CurrentTryAppParams) => {
|
|
if (showTryAppPanel)
|
|
setCurrentTryAppParams(params)
|
|
else
|
|
setCurrentTryAppParams(undefined)
|
|
setIsShowTryAppPanel(showTryAppPanel)
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-full overflow-hidden border-t border-divider-regular bg-background-body">
|
|
<ExploreContext.Provider
|
|
value={
|
|
{
|
|
controlUpdateInstalledApps,
|
|
setControlUpdateInstalledApps,
|
|
hasEditPermission,
|
|
installedApps,
|
|
setInstalledApps,
|
|
isFetchingInstalledApps,
|
|
setIsFetchingInstalledApps,
|
|
currentApp: currentTryAppParams,
|
|
isShowTryAppPanel,
|
|
setShowTryAppPanel,
|
|
}
|
|
}
|
|
>
|
|
<Sidebar controlUpdateInstalledApps={controlUpdateInstalledApps} />
|
|
<div className="h-full min-h-0 w-0 grow">
|
|
{children}
|
|
</div>
|
|
</ExploreContext.Provider>
|
|
</div>
|
|
)
|
|
}
|
|
export default React.memo(Explore)
|