feat: add permissions and access rules tabs in account settings (WIP)

This commit is contained in:
twwu 2026-04-22 18:28:54 +08:00
parent 712e522220
commit 73551495c5
9 changed files with 88 additions and 5 deletions

View File

@ -0,0 +1,23 @@
import { Button } from '@langgenius/dify-ui/button'
const AccessRulesPage = () => {
return (
<>
<div className="flex flex-col">
<div className="mb-8 flex items-center gap-3">
<div className="system-sm-semibold-uppercase text-text-secondary">
App Access Rules
</div>
<Button
variant="secondary"
size="medium"
>
Create App permission set
</Button>
</div>
</div>
</>
)
}
export default AccessRulesPage

View File

@ -3,6 +3,8 @@ export const ACCOUNT_SETTING_MODAL_ACTION = 'showSettings'
export const ACCOUNT_SETTING_TAB = {
PROVIDER: 'provider',
MEMBERS: 'members',
PERMISSIONS: 'permissions',
ACCESS_RULES: 'access-rules',
BILLING: 'billing',
DATA_SOURCE: 'data-source',
API_BASED_EXTENSION: 'api-based-extension',

View File

@ -22,6 +22,7 @@ import LanguagePage from './language-page'
import MembersPage from './members-page'
import ModelProviderPage from './model-provider-page'
import { useResetModelProviderListExpanded } from './model-provider-page/atoms'
import PermissionsPage from './permissions-page'
const iconClassName = `
w-5 h-5 mr-2
@ -49,7 +50,7 @@ export default function AccountSetting({
const resetModelProviderListExpanded = useResetModelProviderListExpanded()
const activeMenu = activeTab
const { t } = useTranslation()
const { enableBilling, enableReplaceWebAppLogo } = useProviderContext()
const { enableBilling, enableReplaceWebAppLogo, enableAccessControl } = useProviderContext()
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
const workplaceGroupItems: GroupItem[] = (() => {
@ -71,6 +72,23 @@ export default function AccountSetting({
},
]
if (enableAccessControl) {
items.push(
{
key: ACCOUNT_SETTING_TAB.PERMISSIONS,
name: t('settings.permissions', { ns: 'common' }),
icon: <span className={cn('i-ri-user-settings-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-shield-user-fill', iconClassName)} />,
},
{
key: ACCOUNT_SETTING_TAB.ACCESS_RULES,
name: t('settings.accessRules', { ns: 'common' }),
icon: <span className={cn('i-ri-shield-user-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-shield-user-fill', iconClassName)} />,
},
)
}
if (enableBilling) {
items.push({
key: ACCOUNT_SETTING_TAB.BILLING,
@ -228,6 +246,7 @@ export default function AccountSetting({
<div className="px-4 pt-2 sm:px-8">
{activeMenu === ACCOUNT_SETTING_TAB.PROVIDER && <ModelProviderPage searchText={searchValue} />}
{activeMenu === ACCOUNT_SETTING_TAB.MEMBERS && <MembersPage />}
{activeMenu === ACCOUNT_SETTING_TAB.PERMISSIONS && <PermissionsPage />}
{activeMenu === ACCOUNT_SETTING_TAB.BILLING && <BillingPage />}
{activeMenu === ACCOUNT_SETTING_TAB.DATA_SOURCE && <DataSourcePage />}
{activeMenu === ACCOUNT_SETTING_TAB.API_BASED_EXTENSION && <ApiBasedExtensionPage />}

View File

@ -118,8 +118,8 @@ const MembersPage = () => {
<div className="overflow-visible lg:overflow-visible">
<div className="flex min-w-[480px] items-center border-b border-divider-regular py-[7px]">
<div className="grow px-3 system-xs-medium-uppercase text-text-tertiary">{t('members.name', { ns: 'common' })}</div>
<div className="w-[104px] shrink-0 system-xs-medium-uppercase text-text-tertiary">{t('members.lastActive', { ns: 'common' })}</div>
<div className="w-[96px] shrink-0 px-3 system-xs-medium-uppercase text-text-tertiary">{t('members.role', { ns: 'common' })}</div>
<div className="w-[120px] shrink-0 system-xs-medium-uppercase text-text-tertiary">{t('members.lastActive', { ns: 'common' })}</div>
<div className="w-[215px] shrink-0 px-3 system-xs-medium-uppercase text-text-tertiary">{t('members.role', { ns: 'common' })}</div>
</div>
<div className="relative min-w-[480px]">
{
@ -136,8 +136,10 @@ const MembersPage = () => {
<div className="system-xs-regular text-text-tertiary">{account.email}</div>
</div>
</div>
<div className="flex w-[104px] shrink-0 items-center py-2 system-sm-regular text-text-secondary">{formatTimeFromNow(Number((account.last_active_at || account.created_at)) * 1000)}</div>
<div className="flex w-[96px] shrink-0 items-center">
<div className="flex w-[120px] shrink-0 items-center py-2 system-sm-regular text-text-secondary">
{formatTimeFromNow(Number((account.last_active_at || account.created_at)) * 1000)}
</div>
<div className="flex w-[215px] shrink-0 items-center">
{isCurrentWorkspaceOwner && account.role === 'owner' && isAllowTransferWorkspace && (
<TransferOwnership onOperate={() => setShowTransferOwnershipModal(true)}></TransferOwnership>
)}

View File

@ -0,0 +1,30 @@
import { Button } from '@langgenius/dify-ui/button'
const PermissionsPage = () => {
return (
<>
<div className="flex flex-col">
<div className="mb-4 flex items-center gap-3 rounded-xl border-t-[0.5px] border-l-[0.5px] border-divider-subtle bg-linear-to-bl from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-3 pr-5">
<div className="flex grow flex-col gap-y-1">
<div className="system-md-semibold text-text-primary">
Default Global
</div>
<div className="system-sm-regular text-text-tertiary">
A default global permission scheme applied to the workspace
</div>
</div>
<div className="flex items-center">
<Button
variant="primary"
size="small"
>
+ Add Role
</Button>
</div>
</div>
</div>
</>
)
}
export default PermissionsPage

View File

@ -168,6 +168,7 @@ export const ProviderContextProvider = ({
isAllowTransferWorkspace,
isAllowPublishAsCustomKnowledgePipelineTemplate,
humanInputEmailDeliveryEnabled,
enableAccessControl: true, // todo: get from backend
}}
>
{children}

View File

@ -43,6 +43,7 @@ export type ProviderContextState = {
isAllowTransferWorkspace: boolean
isAllowPublishAsCustomKnowledgePipelineTemplate: boolean
humanInputEmailDeliveryEnabled: boolean
enableAccessControl: boolean
}
export const baseProviderContextValue: ProviderContextState = {
@ -76,6 +77,7 @@ export const baseProviderContextValue: ProviderContextState = {
isAllowTransferWorkspace: false,
isAllowPublishAsCustomKnowledgePipelineTemplate: false,
humanInputEmailDeliveryEnabled: false,
enableAccessControl: true,
}
export const ProviderContext = createContext<ProviderContextState>(baseProviderContextValue)

View File

@ -607,6 +607,7 @@
"provider.saveFailed": "Save api key failed",
"provider.validatedError": "Validation failed: ",
"provider.validating": "Validating key...",
"settings.accessRules": "Access Rules",
"settings.account": "My account",
"settings.accountGroup": "GENERAL",
"settings.apiBasedExtension": "API Extension",
@ -616,6 +617,7 @@
"settings.integrations": "Integrations",
"settings.language": "Language",
"settings.members": "Members",
"settings.permissions": "Permissions",
"settings.plugin": "Plugins",
"settings.provider": "Model Provider",
"settings.workplaceGroup": "WORKSPACE",

View File

@ -607,6 +607,7 @@
"provider.saveFailed": "API 密钥保存失败",
"provider.validatedError": "校验失败:",
"provider.validating": "验证密钥中...",
"settings.accessRules": "访问规则",
"settings.account": "我的账户",
"settings.accountGroup": "通用",
"settings.apiBasedExtension": "API 扩展",
@ -616,6 +617,7 @@
"settings.integrations": "集成",
"settings.language": "语言",
"settings.members": "成员",
"settings.permissions": "权限",
"settings.plugin": "插件",
"settings.provider": "模型供应商",
"settings.workplaceGroup": "工作空间",