'use client' import type { AccountSettingTab } from '@/app/components/header/account-setting/constants' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { ScrollArea } from '@langgenius/dify-ui/scroll-area' import { useSuspenseQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import { useCallback, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import BillingPage from '@/app/components/billing/billing-page' import CustomPage from '@/app/components/custom/custom-page' import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants' import MenuDialog from '@/app/components/header/account-setting/menu-dialog' import { workspacePermissionKeysAtom } from '@/context/permission-state' import { useProviderContext } from '@/context/provider-context' import { isCurrentWorkspaceDatasetOperatorAtom, isCurrentWorkspaceManagerAtom, } from '@/context/workspace-state' import { systemFeaturesQueryOptions } from '@/features/system-features/client' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import { hasPermission } from '@/utils/permission' import AccessRulesPage from './access-rules-page' import { ApiBasedExtensionPage } from './api-based-extension-page' import DataSourcePage from './data-source-page-new' import MembersPage from './members-page' import ModelProviderPage from './model-provider-page' import { useResetModelProviderListExpanded } from './model-provider-page/atoms' import PermissionsPage from './permissions-page' import PreferencePage from './preference-page' import WorkflowLogArchivesPage from './workflow-log-archives-page' const iconClassName = ` w-4 h-4 mr-2 ` type IAccountSettingProps = { onCancelAction: () => void activeTab: AccountSettingTab onTabChangeAction: (tab: AccountSettingTab) => void } type GroupItem = { key: AccountSettingTab name: string title?: string description?: string icon: React.JSX.Element activeIcon: React.JSX.Element } export default function AccountSetting({ onCancelAction, activeTab, onTabChangeAction, }: IAccountSettingProps) { const resetModelProviderListExpanded = useResetModelProviderListExpanded() const { t } = useTranslation() const { enableBilling, enableReplaceWebAppLogo } = useProviderContext() const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom) const isCurrentWorkspaceManager = useAtomValue(isCurrentWorkspaceManagerAtom) const isCurrentWorkspaceDatasetOperator = useAtomValue(isCurrentWorkspaceDatasetOperatorAtom) const isRbacEnabled = systemFeatures.rbac_enabled const canManageWorkspaceRoles = isRbacEnabled && hasPermission(workspacePermissionKeys, 'workspace.role.manage') const canViewBilling = enableBilling && !isCurrentWorkspaceDatasetOperator const canViewWorkflowLogArchives = systemFeatures.deployment_edition === 'CLOUD' && isCurrentWorkspaceManager // Keep legacy `language` deep links opening Preferences during the tab rename migration. const normalizedActiveTab = activeTab === ACCOUNT_SETTING_TAB.LANGUAGE ? ACCOUNT_SETTING_TAB.PREFERENCES : activeTab const activeMenu = (() => { if (normalizedActiveTab === ACCOUNT_SETTING_TAB.BILLING && !canViewBilling) return ACCOUNT_SETTING_TAB.PREFERENCES if ( normalizedActiveTab === ACCOUNT_SETTING_TAB.WORKFLOW_LOG_ARCHIVES && !canViewWorkflowLogArchives ) return ACCOUNT_SETTING_TAB.MEMBERS if ( (normalizedActiveTab === ACCOUNT_SETTING_TAB.ROLES_AND_PERMISSIONS || normalizedActiveTab === ACCOUNT_SETTING_TAB.PERMISSION_SET) && !canManageWorkspaceRoles ) return ACCOUNT_SETTING_TAB.MEMBERS return normalizedActiveTab })() const scrollContainerRef = useRef(null) const settingItems: GroupItem[] = [ { key: ACCOUNT_SETTING_TAB.PROVIDER, name: t(($) => $['settings.provider'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.MEMBERS, name: t(($) => $['settings.members'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.ROLES_AND_PERMISSIONS, name: t(($) => $['settings.rolesAndPermissions'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.PERMISSION_SET, name: t(($) => $['settings.permissionSet'], { ns: 'common' }), description: t(($) => $['settings.permissionSetDescription'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.BILLING, name: t(($) => $['settings.billing'], { ns: 'common' }), description: t(($) => $['plansCommon.receiptInfo'], { ns: 'billing' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.WORKFLOW_LOG_ARCHIVES, name: t(($) => $['archives.title'], { ns: 'appLog' }), description: t(($) => $['archives.description'], { ns: 'appLog' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.DATA_SOURCE, name: t(($) => $['settings.dataSource'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.API_BASED_EXTENSION, name: t(($) => $['settings.customEndpoint'], { ns: 'common' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.CUSTOM, name: t(($) => $.custom, { ns: 'custom' }), icon: , activeIcon: , }, { key: ACCOUNT_SETTING_TAB.PREFERENCES, name: t(($) => $['settings.preferences'], { ns: 'common' }), title: t(($) => $['account.general'], { ns: 'common' }), icon: , activeIcon: , }, ] const activeItem = settingItems.find((item) => item.key === activeMenu) const visibleSettingItems: GroupItem[] = (() => { const visibleTabs: AccountSettingTab[] = [] visibleTabs.push(ACCOUNT_SETTING_TAB.MEMBERS) if (canManageWorkspaceRoles) { visibleTabs.push(ACCOUNT_SETTING_TAB.ROLES_AND_PERMISSIONS) visibleTabs.push(ACCOUNT_SETTING_TAB.PERMISSION_SET) } if (canViewBilling) visibleTabs.push(ACCOUNT_SETTING_TAB.BILLING) if (enableReplaceWebAppLogo || enableBilling) visibleTabs.push(ACCOUNT_SETTING_TAB.CUSTOM) if (canViewWorkflowLogArchives) visibleTabs.push(ACCOUNT_SETTING_TAB.WORKFLOW_LOG_ARCHIVES) return visibleTabs .map((tab) => settingItems.find((item) => item.key === tab)) .filter((item): item is GroupItem => Boolean(item)) })() const media = useBreakpoints() const isMobile = media === MediaType.mobile const preferenceItem = settingItems.find((item) => item.key === ACCOUNT_SETTING_TAB.PREFERENCES) const menuItems = [ { key: 'workspace-group', name: t(($) => $['settings.workspace'], { ns: 'common' }), items: visibleSettingItems, }, { key: 'user-group', items: preferenceItem ? [preferenceItem] : [], }, ] const [searchValue, setSearchValue] = useState('') const handleTabChange = useCallback( (tab: AccountSettingTab) => { if (tab === ACCOUNT_SETTING_TAB.PROVIDER) resetModelProviderListExpanded() onTabChangeAction(tab) }, [onTabChangeAction, resetModelProviderListExpanded], ) const handleClose = useCallback(() => { resetModelProviderListExpanded() onCancelAction() }, [onCancelAction, resetModelProviderListExpanded]) return (
{t(($) => $['settings.settings'], { ns: 'common' })}
{menuItems.map((menuItem) => (
{menuItem.name && !isMobile && (
{menuItem.name}
)}
{menuItem.items.map((item) => ( ))}
))}
{activeItem?.title ?? activeItem?.name} {activeItem?.description && (
{activeItem?.description}
)}
ESC
{activeMenu === ACCOUNT_SETTING_TAB.PROVIDER && ( )} {activeMenu === ACCOUNT_SETTING_TAB.MEMBERS && } {activeMenu === ACCOUNT_SETTING_TAB.ROLES_AND_PERMISSIONS && ( )} {activeMenu === ACCOUNT_SETTING_TAB.PERMISSION_SET && } {activeMenu === ACCOUNT_SETTING_TAB.BILLING && } {activeMenu === ACCOUNT_SETTING_TAB.WORKFLOW_LOG_ARCHIVES && ( )} {activeMenu === ACCOUNT_SETTING_TAB.DATA_SOURCE && } {activeMenu === ACCOUNT_SETTING_TAB.API_BASED_EXTENSION && } {activeMenu === ACCOUNT_SETTING_TAB.CUSTOM && } {activeMenu === ACCOUNT_SETTING_TAB.PREFERENCES && }
) }