mirror of
https://github.com/langgenius/dify.git
synced 2026-05-12 07:37:09 +08:00
feat: enhance access rule management with account bindings and role handling
This commit is contained in:
parent
e44252c242
commit
d878a29c43
@ -1,10 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import type { AccessPolicyWithBindings } from '@/models/access-control'
|
||||
import type { AccessPolicyWithBindings, BindingType } from '@/models/access-control'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { memo, useCallback } from 'react'
|
||||
import { useUpdateAppAccessRuleBindings, useUpdateDatasetAccessRuleBindings } from '@/service/access-control/use-workspace-access-rules'
|
||||
import {
|
||||
useUpdateAppAccessRuleBindings,
|
||||
useUpdateDatasetAccessRuleBindings,
|
||||
} from '@/service/access-control/use-workspace-access-rules'
|
||||
import AccessRuleRowMenu from './access-rule-row-menu'
|
||||
import RoleTag from './role-tag'
|
||||
|
||||
@ -23,7 +26,8 @@ const AccessRuleRow = ({
|
||||
onEdit,
|
||||
onAddRole,
|
||||
}: AccessRuleRowProps) => {
|
||||
const { policy, role_ids } = rule
|
||||
const { policy, role_ids, account_ids } = rule
|
||||
const { id: policyId, resource_type } = policy
|
||||
|
||||
const handleEdit = useCallback(() => onEdit?.(rule), [onEdit, rule])
|
||||
const handleAddRole = useCallback(() => onAddRole?.(rule), [onAddRole, rule])
|
||||
@ -31,27 +35,33 @@ const AccessRuleRow = ({
|
||||
const { mutateAsync: updateAppAccessRuleBindings } = useUpdateAppAccessRuleBindings()
|
||||
const { mutateAsync: updateDatasetAccessRuleBindings } = useUpdateDatasetAccessRuleBindings()
|
||||
|
||||
const handleRemoveRole = useCallback((roleId: string) => {
|
||||
const handleRemoveRole = useCallback((id: string, type: BindingType) => {
|
||||
const payload = {
|
||||
id: policy.id,
|
||||
role_ids: role_ids.filter(id => id !== roleId),
|
||||
account_ids: [],
|
||||
id: policyId,
|
||||
role_ids: role_ids.map(role => role.id),
|
||||
account_ids: account_ids.map(account => account.id),
|
||||
}
|
||||
if (policy.resource_type === 'app') {
|
||||
if (type === 'role') {
|
||||
payload.role_ids = payload.role_ids.filter(roleId => roleId !== id)
|
||||
}
|
||||
else if (type === 'account') {
|
||||
payload.account_ids = payload.account_ids.filter(accountId => accountId !== id)
|
||||
}
|
||||
if (resource_type === 'app') {
|
||||
updateAppAccessRuleBindings(payload, {
|
||||
onSuccess: () => {
|
||||
toast.success('Access rule updated successfully')
|
||||
},
|
||||
})
|
||||
}
|
||||
else if (policy.resource_type === 'dataset') {
|
||||
else if (resource_type === 'dataset') {
|
||||
updateDatasetAccessRuleBindings(payload, {
|
||||
onSuccess: () => {
|
||||
toast.success('Access rule updated successfully')
|
||||
},
|
||||
})
|
||||
}
|
||||
}, [policy.id, policy.resource_type, role_ids, updateAppAccessRuleBindings, updateDatasetAccessRuleBindings])
|
||||
}, [account_ids, policyId, resource_type, role_ids, updateAppAccessRuleBindings, updateDatasetAccessRuleBindings])
|
||||
|
||||
return (
|
||||
<div className={cn('flex items-start gap-2 py-3.5', className)}>
|
||||
@ -65,9 +75,19 @@ const AccessRuleRow = ({
|
||||
<div className="mt-2 flex flex-wrap items-center gap-1.5">
|
||||
{role_ids.map(role => (
|
||||
<RoleTag
|
||||
key={role}
|
||||
id={role}
|
||||
label={role}
|
||||
key={role.id}
|
||||
id={role.id}
|
||||
label={role.name}
|
||||
type="role"
|
||||
onRemove={handleRemoveRole}
|
||||
/>
|
||||
))}
|
||||
{account_ids.map(account => (
|
||||
<RoleTag
|
||||
key={account.id}
|
||||
id={account.id}
|
||||
label={account.name}
|
||||
type="account"
|
||||
onRemove={handleRemoveRole}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -35,9 +35,7 @@ type AddRuleTargetsModalBaseProps = {
|
||||
onSubmit: (selection: { roleIds: string[], memberIds: string[] }) => void
|
||||
}
|
||||
|
||||
export type AddRuleTargetsModalProps = AddRuleTargetsModalBaseProps & {
|
||||
open: boolean
|
||||
}
|
||||
export type AddRuleTargetsModalProps = AddRuleTargetsModalBaseProps
|
||||
|
||||
const TABS: Array<{ key: TabKey, label: string }> = [
|
||||
{ key: 'roles', label: 'ROLES' },
|
||||
@ -237,11 +235,9 @@ const AddRuleTargetsModalBody = ({
|
||||
<div className="system-sm-semibold text-text-secondary">
|
||||
{role.name}
|
||||
</div>
|
||||
{role.description && (
|
||||
<div className="mt-0.5 system-xs-regular text-text-tertiary">
|
||||
{role.description}
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-0.5 system-xs-regular text-text-tertiary">
|
||||
{role.description || 'No description'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@ -330,7 +326,6 @@ const AddRuleTargetsModalBody = ({
|
||||
}
|
||||
|
||||
const AddRuleTargetsModal = ({
|
||||
open,
|
||||
ruleName,
|
||||
initialRoleIds,
|
||||
initialMemberIds,
|
||||
@ -339,7 +334,7 @@ const AddRuleTargetsModal = ({
|
||||
}: AddRuleTargetsModalProps) => {
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
open
|
||||
onOpenChange={(nextOpen) => {
|
||||
if (!nextOpen)
|
||||
onClose()
|
||||
|
||||
@ -130,10 +130,9 @@ const AccessRulesPage = () => {
|
||||
</div>
|
||||
{addingRule && (
|
||||
<AddRuleTargetsModal
|
||||
open
|
||||
ruleName={addingRule.policy.name}
|
||||
initialRoleIds={addingRule.role_ids}
|
||||
initialMemberIds={[]}
|
||||
initialRoleIds={addingRule.role_ids.map(role => role.id)}
|
||||
initialMemberIds={addingRule.account_ids.map(account => account.id)}
|
||||
onClose={closeAddModal}
|
||||
onSubmit={handleAddSubmit}
|
||||
/>
|
||||
|
||||
@ -1,18 +1,21 @@
|
||||
'use client'
|
||||
|
||||
import type { BindingType } from '@/models/access-control'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { memo } from 'react'
|
||||
|
||||
export type RoleTagProps = {
|
||||
id: string
|
||||
label: string
|
||||
onRemove?: (id: string) => void
|
||||
type: BindingType
|
||||
onRemove?: (id: string, type: BindingType) => void
|
||||
className?: string
|
||||
}
|
||||
|
||||
const RoleTag = ({
|
||||
id,
|
||||
label,
|
||||
type,
|
||||
onRemove,
|
||||
className,
|
||||
}: RoleTagProps) => {
|
||||
@ -31,7 +34,7 @@ const RoleTag = ({
|
||||
aria-label={`Remove ${label}`}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onRemove(id)
|
||||
onRemove(id, type)
|
||||
}}
|
||||
className="flex h-4 w-4 items-center justify-center rounded text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
||||
>
|
||||
|
||||
@ -128,7 +128,20 @@ export type UpdateAccessPolicyRequest = {
|
||||
permission_keys?: PermissionKey[]
|
||||
}
|
||||
|
||||
export type BindingType = 'role' | 'account'
|
||||
|
||||
export type Bindings = {
|
||||
role_ids: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
account_ids: Array<{
|
||||
id: string
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
|
||||
export type BindingsPayload = {
|
||||
role_ids: string[]
|
||||
account_ids: string[]
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import type {
|
||||
AccessPolicy,
|
||||
AccessPolicyResourceType,
|
||||
Bindings,
|
||||
AccessPolicyWithBindings,
|
||||
BindingsPayload,
|
||||
CreateAccessPolicyRequest,
|
||||
GetAppAccessPoliciesResponse,
|
||||
GetDatasetAccessPoliciesResponse,
|
||||
@ -107,9 +108,9 @@ export const useUpdateAppAccessRuleBindings = () => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-app-bindings'],
|
||||
mutationFn: (data: Bindings & { id: string }) => {
|
||||
mutationFn: (data: BindingsPayload & { id: string }) => {
|
||||
const { id, ...rest } = data
|
||||
return put(`/workspaces/current/rbac/workspace/apps/access-policies/${id}/bindings`, {
|
||||
return put<AccessPolicyWithBindings>(`/workspaces/current/rbac/workspace/apps/access-policies/${id}/bindings`, {
|
||||
body: {
|
||||
...rest,
|
||||
},
|
||||
@ -126,9 +127,9 @@ export const useUpdateDatasetAccessRuleBindings = () => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-dataset-bindings'],
|
||||
mutationFn: (data: Bindings & { id: string }) => {
|
||||
mutationFn: (data: BindingsPayload & { id: string }) => {
|
||||
const { id, ...rest } = data
|
||||
return put(`/workspaces/current/rbac/workspace/datasets/access-policies/${id}/bindings`, {
|
||||
return put<AccessPolicyWithBindings>(`/workspaces/current/rbac/workspace/datasets/access-policies/${id}/bindings`, {
|
||||
body: {
|
||||
...rest,
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user