refactor(web): migrate rbac access console contracts (#38256)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Stephen Zhou 2026-07-01 22:45:34 +08:00 committed by GitHub
parent f1f6ab0ac6
commit ee1d33eaa6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 452 additions and 289 deletions

View File

@ -20213,7 +20213,7 @@ Whitelist scopes accepted by RBAC app and dataset access config APIs.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| data | [ [ResourceUserAccessPolicies](#resourceuseraccesspolicies) ] | | No |
| scope | string | | Yes |
| scope | [RBACResourceWhitelistScope](#rbacresourcewhitelistscope) | | Yes |
#### ResourceWhitelist

View File

@ -249,7 +249,7 @@ class ResourceUserAccessPolicies(_RBACModel):
class ResourceUserAccessPoliciesResponse(_RBACModel):
scope: str
scope: RBACResourceWhitelistScope
data: list[ResourceUserAccessPolicies] = Field(default_factory=list)

View File

@ -299,7 +299,7 @@ class TestResourceAccess:
def test_app_user_access_policies(self, mock_send: MagicMock):
mock_send.return_value = {
"scope": "app",
"scope": "specific",
"data": [
{
"account": {"account_id": "acct-1", "account_name": "Alice"},

View File

@ -551,7 +551,7 @@ export type AppAccessMatrix = {
export type ResourceUserAccessPoliciesResponse = {
data?: Array<ResourceUserAccessPolicies>
scope: string
scope: RbacResourceWhitelistScope
}
export type ReplaceUserAccessPolicies = {

View File

@ -1841,7 +1841,7 @@ export const zResourceUserAccessPolicies = z.object({
*/
export const zResourceUserAccessPoliciesResponse = z.object({
data: z.array(zResourceUserAccessPolicies).optional(),
scope: z.string(),
scope: zRbacResourceWhitelistScope,
})
/**

View File

@ -134,10 +134,13 @@ describe('AccessRulesEditor', () => {
expect(screen.getByRole('button', { name: 'permission.accessRule.resourceOpenScopeDescription' })).toBeInTheDocument()
const allMembersButton = screen.getByRole('button', { name: /permission\.accessRule\.allPermittedMembers/ })
const onlyMeButton = screen.getByRole('button', { name: /permission\.accessRule\.onlyMe/ })
const specificMembersButton = screen.getByRole('button', { name: /permission\.accessRule\.specificMembersOnly/ })
expect(allMembersButton).toBeDisabled()
expect(onlyMeButton).toBeDisabled()
expect(specificMembersButton).toBeDisabled()
expect(allMembersButton).toHaveAttribute('aria-pressed', 'false')
expect(onlyMeButton).toHaveAttribute('aria-pressed', 'false')
expect(specificMembersButton).toHaveAttribute('aria-pressed', 'false')
})
@ -181,6 +184,30 @@ describe('AccessRulesEditor', () => {
expect(onRemoveAccessPolicyMemberBinding).toHaveBeenCalledWith('account-1', 'app-policy-id')
})
it('should render and update the only-me resource access scope', () => {
const onOpenScopeChange = vi.fn()
render(
<AccessRulesEditor
rules={[]}
userAccessSettings={[]}
isLoadingRules={false}
isLoadingUserAccessSettings={false}
openScope="only_me"
isUpdatingOpenScope={false}
updatingAccountId={null}
onOpenScopeChange={onOpenScopeChange}
/>,
)
expect(screen.getByRole('button', { name: /permission\.accessRule\.onlyMe/ })).toHaveAttribute('aria-pressed', 'true')
fireEvent.click(screen.getByRole('button', { name: /permission\.accessRule\.specificMembersOnly/ }))
fireEvent.click(screen.getByRole('button', { name: 'common.operation.change' }))
expect(onOpenScopeChange).toHaveBeenCalledWith('specific')
})
it('should render the fixed default option when an account has no exception policy', () => {
render(
<AccessRulesEditor

View File

@ -49,7 +49,7 @@ function ResourceOpenScopeSection({
</h2>
<TitleInfotip content={resourceOpenScopeDescription} />
</div>
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
<div className="grid grid-cols-1 gap-2 sm:grid-cols-3">
<OpenScopeOption
value="all"
selected={value === 'all'}
@ -58,6 +58,14 @@ function ResourceOpenScopeSection({
description={t('accessRule.allPermittedMembersDescription', { ns: 'permission' })}
onChange={onChange ? handleRequestChange : undefined}
/>
<OpenScopeOption
value="only_me"
selected={value === 'only_me'}
disabled={disabled || !onChange}
title={t('accessRule.onlyMe', { ns: 'permission' })}
description={t('accessRule.onlyMeDescription', { ns: 'permission' })}
onChange={onChange ? handleRequestChange : undefined}
/>
<OpenScopeOption
value="specific"
selected={value === 'specific'}

View File

@ -1,182 +0,0 @@
import type { AccessControlTemplateLanguage } from '@/i18n-config/language'
import type {
GetAccessPolicyDetailResponse,
GetAppAccessPolicyByAppIdResponse,
GetAppUserAccessSettingsResponse,
GetDatasetAccessPolicyByDatasetIdResponse,
GetDatasetUserAccessSettingsResponse,
ResourceOpenScope,
} from '@/models/access-control'
import { type } from '@orpc/contract'
import { base } from '../base'
const appAccessRulesContract = base
.route({
path: '/workspaces/current/rbac/apps/{appId}/access-policy',
method: 'GET',
})
.input(type<{
params: {
appId: string
}
query: {
language: AccessControlTemplateLanguage
}
}>())
.output(type<GetAppAccessPolicyByAppIdResponse>())
const appUserAccessSettingsContract = base
.route({
path: '/workspaces/current/rbac/apps/{appId}/user-access-policies',
method: 'GET',
})
.input(type<{
params: {
appId: string
}
query: {
language: AccessControlTemplateLanguage
}
}>())
.output(type<GetAppUserAccessSettingsResponse>())
const updateAppUserAccessSettingsContract = base
.route({
path: '/workspaces/current/rbac/apps/{appId}/users/{accountId}/access-policies',
method: 'PUT',
})
.input(type<{
params: {
appId: string
accountId: string
}
body: {
access_policy_ids: string[]
}
}>())
.output(type<GetAccessPolicyDetailResponse>())
const removeAppAccessPolicyMemberBindingsContract = base
.route({
path: '/workspaces/current/rbac/apps/{appId}/access-policies/{policyId}/member-bindings',
method: 'DELETE',
})
.input(type<{
params: {
appId: string
policyId: string
}
body: {
account_ids: string[]
}
}>())
.output(type<unknown>())
const updateAppOpenScopeContract = base
.route({
path: '/workspaces/current/rbac/apps/{appId}/whitelist',
method: 'PUT',
})
.input(type<{
params: {
appId: string
}
body: {
scope: ResourceOpenScope
}
}>())
.output(type<unknown>())
const datasetAccessRulesContract = base
.route({
path: '/workspaces/current/rbac/datasets/{datasetId}/access-policy',
method: 'GET',
})
.input(type<{
params: {
datasetId: string
}
query: {
language: AccessControlTemplateLanguage
}
}>())
.output(type<GetDatasetAccessPolicyByDatasetIdResponse>())
const datasetUserAccessSettingsContract = base
.route({
path: '/workspaces/current/rbac/datasets/{datasetId}/user-access-policies',
method: 'GET',
})
.input(type<{
params: {
datasetId: string
}
query: {
language: AccessControlTemplateLanguage
}
}>())
.output(type<GetDatasetUserAccessSettingsResponse>())
const updateDatasetUserAccessSettingsContract = base
.route({
path: '/workspaces/current/rbac/datasets/{datasetId}/users/{accountId}/access-policies',
method: 'PUT',
})
.input(type<{
params: {
datasetId: string
accountId: string
}
body: {
access_policy_ids: string[]
}
}>())
.output(type<GetAccessPolicyDetailResponse>())
const removeDatasetAccessPolicyMemberBindingsContract = base
.route({
path: '/workspaces/current/rbac/datasets/{datasetId}/access-policies/{policyId}/member-bindings',
method: 'DELETE',
})
.input(type<{
params: {
datasetId: string
policyId: string
}
body: {
account_ids: string[]
}
}>())
.output(type<unknown>())
const updateDatasetOpenScopeContract = base
.route({
path: '/workspaces/current/rbac/datasets/{datasetId}/whitelist',
method: 'PUT',
})
.input(type<{
params: {
datasetId: string
}
body: {
scope: ResourceOpenScope
}
}>())
.output(type<unknown>())
export const rbacAccessConfigContract = {
apps: {
accessRules: appAccessRulesContract,
userAccessSettings: appUserAccessSettingsContract,
updateUserAccessSettings: updateAppUserAccessSettingsContract,
removeMemberBindings: removeAppAccessPolicyMemberBindingsContract,
updateOpenScope: updateAppOpenScopeContract,
},
datasets: {
accessRules: datasetAccessRulesContract,
userAccessSettings: datasetUserAccessSettingsContract,
updateUserAccessSettings: updateDatasetUserAccessSettingsContract,
removeMemberBindings: removeDatasetAccessPolicyMemberBindingsContract,
updateOpenScope: updateDatasetOpenScopeContract,
},
}

View File

@ -45,7 +45,6 @@ import { workflowGenerate } from '@dify/contracts/api/console/workflow-generate/
import { workflow } from '@dify/contracts/api/console/workflow/orpc.gen'
import { workspaces } from '@dify/contracts/api/console/workspaces/orpc.gen'
import { contract as enterpriseContract } from '@dify/contracts/enterprise/orpc.gen'
import { rbacAccessConfigContract } from './console/access-control'
import { exploreRouterContract } from './console/explore'
import { modelProvidersRouterContract } from './console/model-providers'
import { pluginsRouterContract } from './console/plugins'
@ -108,7 +107,6 @@ export const consoleRouterContract = {
explore: exploreRouterContract,
modelProviders: modelProvidersRouterContract,
plugins: pluginsRouterContract,
rbacAccessConfig: rbacAccessConfigContract,
snippets: snippetsRouterContract,
triggers: triggersRouterContract,
trialApps: trialAppsRouterContract,

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "لا يوجد وصف",
"accessRule.noRules": "لا توجد قواعد وصول",
"accessRule.noUserAccessSettings": "لا توجد إعدادات أذونات فردية",
"accessRule.onlyMe": "أنا فقط",
"accessRule.onlyMeDescription": "يمكنك وحدك الوصول إلى هذا المورد.",
"accessRule.permission": "الإذن",
"accessRule.resourceOpenScope": "نطاق فتح المورد",
"accessRule.resourceOpenScopeDescription": "اختر من يُفتح له هذا المورد. لا تزال أذونات الأدوار تحدد ما يمكن لكل عضو فعله.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Keine Beschreibung",
"accessRule.noRules": "Keine Zugriffsregeln",
"accessRule.noUserAccessSettings": "Keine individuellen Berechtigungseinstellungen",
"accessRule.onlyMe": "Nur ich",
"accessRule.onlyMeDescription": "Nur Sie können auf diese Ressource zugreifen.",
"accessRule.permission": "Berechtigung",
"accessRule.resourceOpenScope": "Freigabebereich der Ressource",
"accessRule.resourceOpenScopeDescription": "Wählen Sie, für wen diese Ressource geöffnet ist. Rollenberechtigungen bestimmen weiterhin, was jedes Mitglied tun kann.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "No description",
"accessRule.noRules": "No access rules",
"accessRule.noUserAccessSettings": "No individual permission settings",
"accessRule.onlyMe": "Only me",
"accessRule.onlyMeDescription": "Only you can access this resource.",
"accessRule.permission": "Permission",
"accessRule.resourceOpenScope": "Resource open scope",
"accessRule.resourceOpenScopeDescription": "Choose who this resource is open to. Role permissions still decide what each member can do.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Sin descripción",
"accessRule.noRules": "Sin reglas de acceso",
"accessRule.noUserAccessSettings": "Sin ajustes de permisos individuales",
"accessRule.onlyMe": "Solo yo",
"accessRule.onlyMeDescription": "Solo tú puedes acceder a este recurso.",
"accessRule.permission": "Permiso",
"accessRule.resourceOpenScope": "Ámbito de apertura del recurso",
"accessRule.resourceOpenScopeDescription": "Elige a quién está abierto este recurso. Los permisos de rol siguen decidiendo lo que puede hacer cada miembro.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "بدون توضیحات",
"accessRule.noRules": "بدون قانون دسترسی",
"accessRule.noUserAccessSettings": "بدون تنظیمات مجوز فردی",
"accessRule.onlyMe": "فقط من",
"accessRule.onlyMeDescription": "فقط شما می‌توانید به این منبع دسترسی داشته باشید.",
"accessRule.permission": "مجوز",
"accessRule.resourceOpenScope": "دامنه دسترسی منبع",
"accessRule.resourceOpenScopeDescription": "انتخاب کنید این منبع برای چه کسانی باز است. مجوزهای نقش همچنان تعیین می‌کنند هر عضو چه کاری می‌تواند انجام دهد.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Aucune description",
"accessRule.noRules": "Aucune règle d'accès",
"accessRule.noUserAccessSettings": "Aucun paramètre d'autorisation individuel",
"accessRule.onlyMe": "Moi uniquement",
"accessRule.onlyMeDescription": "Vous seul pouvez accéder à cette ressource.",
"accessRule.permission": "Autorisation",
"accessRule.resourceOpenScope": "Portée d'ouverture de la ressource",
"accessRule.resourceOpenScopeDescription": "Choisissez à qui cette ressource est ouverte. Les autorisations de rôle déterminent toujours ce que chaque membre peut faire.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "कोई विवरण नहीं",
"accessRule.noRules": "कोई एक्सेस नियम नहीं",
"accessRule.noUserAccessSettings": "कोई व्यक्तिगत अनुमति सेटिंग्स नहीं",
"accessRule.onlyMe": "केवल मैं",
"accessRule.onlyMeDescription": "केवल आप इस संसाधन तक पहुँच सकते हैं।",
"accessRule.permission": "अनुमति",
"accessRule.resourceOpenScope": "संसाधन का खुला दायरा",
"accessRule.resourceOpenScopeDescription": "चुनें कि यह संसाधन किसके लिए खुला है। भूमिका अनुमतियां अभी भी तय करती हैं कि प्रत्येक सदस्य क्या कर सकता है।",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Tidak ada deskripsi",
"accessRule.noRules": "Tidak ada aturan akses",
"accessRule.noUserAccessSettings": "Tidak ada pengaturan izin individu",
"accessRule.onlyMe": "Hanya saya",
"accessRule.onlyMeDescription": "Hanya Anda yang dapat mengakses resource ini.",
"accessRule.permission": "Izin",
"accessRule.resourceOpenScope": "Cakupan akses sumber daya",
"accessRule.resourceOpenScopeDescription": "Pilih siapa yang dapat mengakses sumber daya ini. Izin peran tetap menentukan apa yang dapat dilakukan setiap anggota.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Nessuna descrizione",
"accessRule.noRules": "Nessuna regola di accesso",
"accessRule.noUserAccessSettings": "Nessuna impostazione dei permessi individuali",
"accessRule.onlyMe": "Solo io",
"accessRule.onlyMeDescription": "Solo tu puoi accedere a questa risorsa.",
"accessRule.permission": "Permesso",
"accessRule.resourceOpenScope": "Ambito di apertura della risorsa",
"accessRule.resourceOpenScopeDescription": "Scegli a chi è aperta questa risorsa. I permessi di ruolo determinano comunque cosa può fare ciascun membro.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "説明なし",
"accessRule.noRules": "アクセスルールがありません",
"accessRule.noUserAccessSettings": "個別権限設定がありません",
"accessRule.onlyMe": "自分のみ",
"accessRule.onlyMeDescription": "このリソースにアクセスできるのは自分だけです。",
"accessRule.permission": "権限",
"accessRule.resourceOpenScope": "リソース公開範囲",
"accessRule.resourceOpenScopeDescription": "このリソースを公開する対象を選択します。各メンバーが実行できる操作はロール権限で決まります。",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "설명 없음",
"accessRule.noRules": "접근 규칙 없음",
"accessRule.noUserAccessSettings": "개별 권한 설정 없음",
"accessRule.onlyMe": "나만",
"accessRule.onlyMeDescription": "이 리소스에는 본인만 접근할 수 있습니다.",
"accessRule.permission": "권한",
"accessRule.resourceOpenScope": "리소스 공개 범위",
"accessRule.resourceOpenScopeDescription": "이 리소스를 누구에게 공개할지 선택합니다. 각 멤버가 할 수 있는 작업은 여전히 역할 권한이 결정합니다.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Geen beschrijving",
"accessRule.noRules": "Geen toegangsregels",
"accessRule.noUserAccessSettings": "Geen individuele rechteninstellingen",
"accessRule.onlyMe": "Alleen ik",
"accessRule.onlyMeDescription": "Alleen jij kunt toegang krijgen tot deze resource.",
"accessRule.permission": "Recht",
"accessRule.resourceOpenScope": "Toegangsbereik van resource",
"accessRule.resourceOpenScopeDescription": "Kies voor wie deze resource toegankelijk is. Rolrechten bepalen nog steeds wat elk lid kan doen.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Brak opisu",
"accessRule.noRules": "Brak reguł dostępu",
"accessRule.noUserAccessSettings": "Brak indywidualnych ustawień uprawnień",
"accessRule.onlyMe": "Tylko ja",
"accessRule.onlyMeDescription": "Tylko Ty możesz uzyskać dostęp do tego zasobu.",
"accessRule.permission": "Uprawnienie",
"accessRule.resourceOpenScope": "Zakres otwarcia zasobu",
"accessRule.resourceOpenScopeDescription": "Wybierz, dla kogo ten zasób jest otwarty. Uprawnienia ról nadal decydują o tym, co każdy członek może robić.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Sem descrição",
"accessRule.noRules": "Sem regras de acesso",
"accessRule.noUserAccessSettings": "Sem configurações de permissão individuais",
"accessRule.onlyMe": "Somente eu",
"accessRule.onlyMeDescription": "Somente você pode acessar este recurso.",
"accessRule.permission": "Permissão",
"accessRule.resourceOpenScope": "Escopo de abertura do recurso",
"accessRule.resourceOpenScopeDescription": "Escolha para quem este recurso está aberto. As permissões de função ainda determinam o que cada membro pode fazer.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Fără descriere",
"accessRule.noRules": "Fără reguli de acces",
"accessRule.noUserAccessSettings": "Fără setări individuale de permisiuni",
"accessRule.onlyMe": "Doar eu",
"accessRule.onlyMeDescription": "Numai tu poți accesa această resursă.",
"accessRule.permission": "Permisiune",
"accessRule.resourceOpenScope": "Domeniul de deschidere al resursei",
"accessRule.resourceOpenScopeDescription": "Alege cui îi este deschisă această resursă. Permisiunile de rol decid în continuare ce poate face fiecare membru.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Без описания",
"accessRule.noRules": "Нет правил доступа",
"accessRule.noUserAccessSettings": "Нет индивидуальных настроек прав",
"accessRule.onlyMe": "Только я",
"accessRule.onlyMeDescription": "Только вы можете получить доступ к этому ресурсу.",
"accessRule.permission": "Право",
"accessRule.resourceOpenScope": "Область открытости ресурса",
"accessRule.resourceOpenScopeDescription": "Выберите, кому открыт этот ресурс. Права роли по-прежнему определяют, что может делать каждый участник.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Brez opisa",
"accessRule.noRules": "Brez pravil za dostop",
"accessRule.noUserAccessSettings": "Brez individualnih nastavitev dovoljenj",
"accessRule.onlyMe": "Samo jaz",
"accessRule.onlyMeDescription": "Do tega vira lahko dostopate samo vi.",
"accessRule.permission": "Dovoljenje",
"accessRule.resourceOpenScope": "Obseg odprtosti vira",
"accessRule.resourceOpenScopeDescription": "Izberite, komu je ta vir na voljo. Dovoljenja vlog še vedno določajo, kaj lahko vsak član počne.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "ไม่มีคําอธิบาย",
"accessRule.noRules": "ไม่มีกฎการเข้าถึง",
"accessRule.noUserAccessSettings": "ไม่มีการตั้งค่าสิทธิ์เฉพาะบุคคล",
"accessRule.onlyMe": "ฉันเท่านั้น",
"accessRule.onlyMeDescription": "เฉพาะคุณเท่านั้นที่เข้าถึงทรัพยากรนี้ได้",
"accessRule.permission": "สิทธิ์",
"accessRule.resourceOpenScope": "ขอบเขตการเปิดของทรัพยากร",
"accessRule.resourceOpenScopeDescription": "เลือกว่าทรัพยากรนี้เปิดให้ใครเข้าถึง สิทธิ์ตามบทบาทยังคงเป็นตัวกําหนดว่าสมาชิกแต่ละคนทําอะไรได้บ้าง",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Açıklama yok",
"accessRule.noRules": "Erişim kuralı yok",
"accessRule.noUserAccessSettings": "Bireysel izin ayarı yok",
"accessRule.onlyMe": "Yalnızca ben",
"accessRule.onlyMeDescription": "Bu kaynağa yalnızca siz erişebilirsiniz.",
"accessRule.permission": "İzin",
"accessRule.resourceOpenScope": "Kaynak açık kapsamı",
"accessRule.resourceOpenScopeDescription": "Bu kaynağın kime açık olduğunu seçin. Her üyenin ne yapabileceğine yine de rol izinleri karar verir.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Немає опису",
"accessRule.noRules": "Немає правил доступу",
"accessRule.noUserAccessSettings": "Немає індивідуальних налаштувань дозволів",
"accessRule.onlyMe": "Лише я",
"accessRule.onlyMeDescription": "Лише ви можете отримати доступ до цього ресурсу.",
"accessRule.permission": "Дозвіл",
"accessRule.resourceOpenScope": "Сфера відкритості ресурсу",
"accessRule.resourceOpenScopeDescription": "Виберіть, кому відкрито цей ресурс. Дозволи ролей усе одно визначають, що може робити кожен учасник.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "Không có mô tả",
"accessRule.noRules": "Không có quy tắc truy cập",
"accessRule.noUserAccessSettings": "Không có cài đặt quyền riêng lẻ",
"accessRule.onlyMe": "Chỉ mình tôi",
"accessRule.onlyMeDescription": "Chỉ bạn có thể truy cập tài nguyên này.",
"accessRule.permission": "Quyền",
"accessRule.resourceOpenScope": "Phạm vi mở của tài nguyên",
"accessRule.resourceOpenScopeDescription": "Chọn tài nguyên này được mở cho ai. Quyền vai trò vẫn quyết định mỗi thành viên có thể làm gì.",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "无描述",
"accessRule.noRules": "暂无访问规则",
"accessRule.noUserAccessSettings": "暂无个人权限设置",
"accessRule.onlyMe": "仅自己",
"accessRule.onlyMeDescription": "仅你自己可以访问此资源。",
"accessRule.permission": "权限",
"accessRule.resourceOpenScope": "访问范围",
"accessRule.resourceOpenScopeDescription": "选择此资源对哪些成员开放。角色权限仍决定每位成员可执行的操作。",

View File

@ -28,6 +28,8 @@
"accessRule.noDescription": "無描述",
"accessRule.noRules": "暫無訪問規則",
"accessRule.noUserAccessSettings": "暫無個人權限設定",
"accessRule.onlyMe": "僅自己",
"accessRule.onlyMeDescription": "僅你自己可以存取此資源。",
"accessRule.permission": "權限",
"accessRule.resourceOpenScope": "訪問範圍",
"accessRule.resourceOpenScopeDescription": "選擇此資源對哪些成員開放。角色權限仍決定每位成員可執行的操作。",

View File

@ -263,8 +263,4 @@ export type RemoveAppAccessPolicyMemberBindingsRequest = RemoveResourceAccessPol
export type RemoveDatasetAccessPolicyMemberBindingsRequest = RemoveResourceAccessPolicyMemberBindingsRequest
export type GetAccessPolicyDetailResponse = {
access_policies: Pick<AccessPolicy, 'id' | 'name' | 'resource_type' | 'policy_key' | 'permission_keys'>[]
}
export type ResourceOpenScope = 'all' | 'specific'
export type ResourceOpenScope = 'all' | 'only_me' | 'specific'

View File

@ -0,0 +1,23 @@
import type { ResourceUserAccessPoliciesResponse } from '@dify/contracts/api/console/workspaces/types.gen'
import { normalizeAppUserAccessPolicies } from '../normalizers'
const createResourceUserAccessPoliciesResponse = (
overrides: Partial<ResourceUserAccessPoliciesResponse> = {},
): ResourceUserAccessPoliciesResponse => ({
data: [],
scope: 'specific',
...overrides,
})
describe('access-control normalizers', () => {
// Resource access scope values come from the RBAC whitelist enum and must not be collapsed.
describe('Resource user access policies', () => {
it('should preserve only-me open scope when normalizing app user access policies', () => {
const response = createResourceUserAccessPoliciesResponse({
scope: 'only_me',
})
expect(normalizeAppUserAccessPolicies(response).scope).toBe('only_me')
})
})
})

View File

@ -28,25 +28,55 @@ const mocks = vi.hoisted(() => ({
vi.mock('@/service/client', () => ({
consoleClient: {
rbacAccessConfig: {
apps: {
updateOpenScope: mocks.updateOpenScope,
updateUserAccessSettings: mocks.updateUserAccessSettings,
removeMemberBindings: mocks.removeMemberBindings,
workspaces: {
current: {
rbac: {
apps: {
byAppId: {
accessPolicies: {
byPolicyId: {
memberBindings: {
delete: mocks.removeMemberBindings,
},
},
},
users: {
byTargetAccountId: {
accessPolicies: {
put: mocks.updateUserAccessSettings,
},
},
},
whitelist: {
put: mocks.updateOpenScope,
},
},
},
},
},
},
},
consoleQuery: {
rbacAccessConfig: {
apps: {
accessRules: {
key: mocks.accessRulesKey,
queryOptions: mocks.accessRulesQueryOptions,
},
userAccessSettings: {
key: mocks.userAccessSettingsKey,
queryKey: mocks.userAccessSettingsQueryKey,
queryOptions: mocks.userAccessSettingsQueryOptions,
workspaces: {
current: {
rbac: {
apps: {
byAppId: {
accessPolicy: {
get: {
key: mocks.accessRulesKey,
queryOptions: mocks.accessRulesQueryOptions,
},
},
userAccessPolicies: {
get: {
key: mocks.userAccessSettingsKey,
queryKey: mocks.userAccessSettingsQueryKey,
queryOptions: mocks.userAccessSettingsQueryOptions,
},
},
},
},
},
},
},
@ -79,7 +109,7 @@ describe('use-app-access-config', () => {
expect(mocks.accessRulesQueryOptions).toHaveBeenCalledWith({
input: {
params: {
appId: 'app-1',
app_id: 'app-1',
},
query: {
language: 'zh',
@ -97,7 +127,7 @@ describe('use-app-access-config', () => {
expect(mocks.userAccessSettingsQueryOptions).toHaveBeenCalledWith({
input: {
params: {
appId: 'app-1',
app_id: 'app-1',
},
query: {
language: 'en',
@ -115,8 +145,8 @@ describe('use-app-access-config', () => {
expect(mocks.updateUserAccessSettings).toHaveBeenCalledWith({
params: {
appId: 'app-1',
accountId: 'account-1',
app_id: 'app-1',
target_account_id: 'account-1',
},
body: {
access_policy_ids: ['policy-1', 'policy-2'],
@ -135,8 +165,8 @@ describe('use-app-access-config', () => {
expect(mocks.removeMemberBindings).toHaveBeenCalledWith({
params: {
appId: 'app-1',
policyId: 'policy-1',
app_id: 'app-1',
policy_id: 'policy-1',
},
body: {
account_ids: ['account-1'],
@ -155,7 +185,7 @@ describe('use-app-access-config', () => {
expect(mocks.updateOpenScope).toHaveBeenCalledWith({
params: {
appId: 'app-1',
app_id: 'app-1',
},
body: {
scope: 'all',

View File

@ -28,25 +28,55 @@ const mocks = vi.hoisted(() => ({
vi.mock('@/service/client', () => ({
consoleClient: {
rbacAccessConfig: {
datasets: {
updateOpenScope: mocks.updateOpenScope,
updateUserAccessSettings: mocks.updateUserAccessSettings,
removeMemberBindings: mocks.removeMemberBindings,
workspaces: {
current: {
rbac: {
datasets: {
byDatasetId: {
accessPolicies: {
byPolicyId: {
memberBindings: {
delete: mocks.removeMemberBindings,
},
},
},
users: {
byTargetAccountId: {
accessPolicies: {
put: mocks.updateUserAccessSettings,
},
},
},
whitelist: {
put: mocks.updateOpenScope,
},
},
},
},
},
},
},
consoleQuery: {
rbacAccessConfig: {
datasets: {
accessRules: {
key: mocks.accessRulesKey,
queryOptions: mocks.accessRulesQueryOptions,
},
userAccessSettings: {
key: mocks.userAccessSettingsKey,
queryKey: mocks.userAccessSettingsQueryKey,
queryOptions: mocks.userAccessSettingsQueryOptions,
workspaces: {
current: {
rbac: {
datasets: {
byDatasetId: {
accessPolicy: {
get: {
key: mocks.accessRulesKey,
queryOptions: mocks.accessRulesQueryOptions,
},
},
userAccessPolicies: {
get: {
key: mocks.userAccessSettingsKey,
queryKey: mocks.userAccessSettingsQueryKey,
queryOptions: mocks.userAccessSettingsQueryOptions,
},
},
},
},
},
},
},
@ -79,7 +109,7 @@ describe('use-dataset-access-config', () => {
expect(mocks.accessRulesQueryOptions).toHaveBeenCalledWith({
input: {
params: {
datasetId: 'dataset-1',
dataset_id: 'dataset-1',
},
query: {
language: 'ja',
@ -97,7 +127,7 @@ describe('use-dataset-access-config', () => {
expect(mocks.userAccessSettingsQueryOptions).toHaveBeenCalledWith({
input: {
params: {
datasetId: 'dataset-1',
dataset_id: 'dataset-1',
},
query: {
language: 'zh',
@ -115,8 +145,8 @@ describe('use-dataset-access-config', () => {
expect(mocks.updateUserAccessSettings).toHaveBeenCalledWith({
params: {
datasetId: 'dataset-1',
accountId: 'account-1',
dataset_id: 'dataset-1',
target_account_id: 'account-1',
},
body: {
access_policy_ids: ['policy-1', 'policy-2'],
@ -135,8 +165,8 @@ describe('use-dataset-access-config', () => {
expect(mocks.removeMemberBindings).toHaveBeenCalledWith({
params: {
datasetId: 'dataset-1',
policyId: 'policy-1',
dataset_id: 'dataset-1',
policy_id: 'policy-1',
},
body: {
account_ids: ['account-1'],
@ -155,7 +185,7 @@ describe('use-dataset-access-config', () => {
expect(mocks.updateOpenScope).toHaveBeenCalledWith({
params: {
datasetId: 'dataset-1',
dataset_id: 'dataset-1',
},
body: {
scope: 'specific',

View File

@ -0,0 +1,175 @@
import type {
AccessPolicy,
AccessPolicyResourceType,
AccessPolicyWithBindings,
GetAppAccessPolicyByAppIdResponse,
GetAppUserAccessSettingsResponse,
GetDatasetAccessPolicyByDatasetIdResponse,
GetDatasetUserAccessSettingsResponse,
ResourceOpenScope,
ResourceUserAccessSetting,
Role,
} from '@/models/access-control'
type GeneratedAccessMatrixItem = import('@dify/contracts/api/console/workspaces/types.gen').AccessMatrixItem
type GeneratedAccessPolicy = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicy
type GeneratedAccessPolicyAccount = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicyAccount
type GeneratedAccessPolicyRole = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicyRole
type GeneratedAppAccessMatrix = import('@dify/contracts/api/console/workspaces/types.gen').AppAccessMatrix
type GeneratedDatasetAccessMatrix = import('@dify/contracts/api/console/workspaces/types.gen').DatasetAccessMatrix
type GeneratedRbacRole = import('@dify/contracts/api/console/workspaces/types.gen').RbacRole
type GeneratedRbacRoleAccount = import('@dify/contracts/api/console/workspaces/types.gen').RbacRoleAccount
type GeneratedResourceOpenScope = import('@dify/contracts/api/console/workspaces/types.gen').RbacResourceWhitelistScope
type GeneratedResourceUserAccessPoliciesResponse = import('@dify/contracts/api/console/workspaces/types.gen').ResourceUserAccessPoliciesResponse
type GeneratedResourceUserAccessPolicies = NonNullable<GeneratedResourceUserAccessPoliciesResponse['data']>[number]
const normalizeRoleCategory = (category?: string): Role['category'] => {
if (category === 'global_system_default')
return 'global_system_default'
return 'global_custom'
}
const normalizeRoleType = (type?: string): Role['type'] => {
if (type === 'app' || type === 'dataset')
return type
return 'workspace'
}
const normalizeRoleTag = (roleTag?: string): Role['role_tag'] => {
if (roleTag === 'owner')
return 'owner'
return ''
}
const normalizeResourceType = (resourceType: string, fallback: AccessPolicyResourceType): AccessPolicyResourceType => {
if (resourceType === 'app' || resourceType === 'dataset')
return resourceType
return fallback
}
const normalizeAccessPolicy = (
policy: GeneratedAccessPolicy,
fallbackResourceType: AccessPolicyResourceType,
): AccessPolicy => ({
id: policy.id,
tenant_id: policy.tenant_id ?? '',
resource_type: normalizeResourceType(policy.resource_type, fallbackResourceType),
policy_key: policy.policy_key ?? '',
name: policy.name,
description: policy.description ?? '',
permission_keys: policy.permission_keys ?? [],
is_builtin: policy.is_builtin ?? false,
category: normalizeRoleCategory(policy.category),
created_at: String(policy.created_at ?? 0),
updated_at: String(policy.updated_at ?? 0),
})
const normalizeAccessPolicyRole = (role: GeneratedAccessPolicyRole) => ({
role_id: role.role_id,
role_name: role.role_name,
binding_id: role.binding_id,
is_locked: role.is_locked ?? false,
role_tag: normalizeRoleTag(role.role_tag),
})
const normalizeAccessPolicyAccount = (account: GeneratedAccessPolicyAccount) => ({
account_id: account.account_id,
account_name: account.account_name,
binding_id: account.binding_id,
is_locked: account.is_locked ?? false,
avatar: account.avatar ?? '',
})
const normalizeAccessMatrixItem = (
item: GeneratedAccessMatrixItem,
fallbackResourceType: AccessPolicyResourceType,
): AccessPolicyWithBindings | null => {
if (!item.policy)
return null
return {
policy: normalizeAccessPolicy(item.policy, fallbackResourceType),
roles: (item.roles ?? []).map(normalizeAccessPolicyRole),
accounts: (item.accounts ?? []).map(normalizeAccessPolicyAccount),
}
}
const isAccessPolicyWithBindings = (item: AccessPolicyWithBindings | null): item is AccessPolicyWithBindings => {
return item !== null
}
const normalizeResourceOpenScope = (scope: GeneratedResourceOpenScope): ResourceOpenScope => {
switch (scope) {
case 'all':
return 'all'
case 'only_me':
return 'only_me'
case 'specific':
return 'specific'
}
}
const normalizeAccount = (account: GeneratedRbacRoleAccount): ResourceUserAccessSetting['account'] => ({
account_id: account.account_id,
account_name: account.account_name ?? '',
email: account.email ?? '',
avatar: account.avatar ?? '',
})
const normalizeRole = (role: GeneratedRbacRole): ResourceUserAccessSetting['roles'][number] => ({
id: role.id,
type: normalizeRoleType(role.type),
category: normalizeRoleCategory(role.category),
name: role.name,
is_builtin: role.is_builtin ?? false,
permission_keys: role.permission_keys ?? [],
})
const normalizeResourceUserAccessSetting = (
setting: GeneratedResourceUserAccessPolicies,
fallbackResourceType: AccessPolicyResourceType,
): ResourceUserAccessSetting => ({
account: normalizeAccount(setting.account),
roles: (setting.roles ?? []).map(normalizeRole),
access_policies: (setting.access_policies ?? []).map(policy => normalizeAccessPolicy(policy, fallbackResourceType)),
})
const normalizeResourceUserAccessPolicies = (
response: GeneratedResourceUserAccessPoliciesResponse,
fallbackResourceType: AccessPolicyResourceType,
): GetAppUserAccessSettingsResponse | GetDatasetUserAccessSettingsResponse => ({
data: (response.data ?? []).map(setting => normalizeResourceUserAccessSetting(setting, fallbackResourceType)),
scope: normalizeResourceOpenScope(response.scope),
})
export const normalizeAppAccessMatrix = (response: GeneratedAppAccessMatrix): GetAppAccessPolicyByAppIdResponse => ({
app_id: response.app_id ?? '',
items: (response.items ?? [])
.map(item => normalizeAccessMatrixItem(item, 'app'))
.filter(isAccessPolicyWithBindings),
})
export const normalizeDatasetAccessMatrix = (
response: GeneratedDatasetAccessMatrix,
): GetDatasetAccessPolicyByDatasetIdResponse => ({
dataset_id: response.dataset_id ?? '',
items: (response.items ?? [])
.map(item => normalizeAccessMatrixItem(item, 'dataset'))
.filter(isAccessPolicyWithBindings),
})
export const normalizeAppUserAccessPolicies = (
response: GeneratedResourceUserAccessPoliciesResponse,
): GetAppUserAccessSettingsResponse => {
return normalizeResourceUserAccessPolicies(response, 'app')
}
export const normalizeDatasetUserAccessPolicies = (
response: GeneratedResourceUserAccessPoliciesResponse,
): GetDatasetUserAccessSettingsResponse => {
return normalizeResourceUserAccessPolicies(response, 'dataset')
}

View File

@ -6,33 +6,42 @@ import type {
} from '@/models/access-control'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { consoleClient, consoleQuery } from '@/service/client'
import { normalizeAppAccessMatrix, normalizeAppUserAccessPolicies } from './normalizers'
const NAME_SPACE = 'app-access-config'
const appRbacContract = consoleQuery.workspaces.current.rbac.apps.byAppId
const appRbacClient = consoleClient.workspaces.current.rbac.apps.byAppId
export const useAppAccessRules = (appId: string, language: AccessControlTemplateLanguage) => {
return useQuery(consoleQuery.rbacAccessConfig.apps.accessRules.queryOptions({
input: {
params: {
appId,
return useQuery({
...appRbacContract.accessPolicy.get.queryOptions({
input: {
params: {
app_id: appId,
},
query: {
language,
},
},
query: {
language,
},
},
}))
}),
select: normalizeAppAccessMatrix,
})
}
export const useAppUserAccessSettings = (appId: string, language: AccessControlTemplateLanguage) => {
return useQuery(consoleQuery.rbacAccessConfig.apps.userAccessSettings.queryOptions({
input: {
params: {
appId,
return useQuery({
...appRbacContract.userAccessPolicies.get.queryOptions({
input: {
params: {
app_id: appId,
},
query: {
language,
},
},
query: {
language,
},
},
}))
}),
select: normalizeAppUserAccessPolicies,
})
}
export const useUpdateAppUserAccessSettings = (appId: string) => {
@ -40,10 +49,10 @@ export const useUpdateAppUserAccessSettings = (appId: string) => {
return useMutation({
mutationKey: [NAME_SPACE, 'update-app-user-access-settings', appId],
mutationFn: (payload: UpdateAppUserAccessSettingsRequest) => consoleClient.rbacAccessConfig.apps.updateUserAccessSettings({
mutationFn: (payload: UpdateAppUserAccessSettingsRequest) => appRbacClient.users.byTargetAccountId.accessPolicies.put({
params: {
appId,
accountId: payload.accountId,
app_id: appId,
target_account_id: payload.accountId,
},
body: {
access_policy_ids: payload.accessPolicyIds,
@ -52,10 +61,10 @@ export const useUpdateAppUserAccessSettings = (appId: string) => {
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.apps.accessRules.key(),
queryKey: appRbacContract.accessPolicy.get.key({ type: 'query' }),
}),
])
},
@ -67,10 +76,10 @@ export const useRemoveAppAccessPolicyMemberBindings = (appId: string) => {
return useMutation({
mutationKey: [NAME_SPACE, 'remove-app-access-policy-member-bindings', appId],
mutationFn: (payload: RemoveAppAccessPolicyMemberBindingsRequest) => consoleClient.rbacAccessConfig.apps.removeMemberBindings({
mutationFn: (payload: RemoveAppAccessPolicyMemberBindingsRequest) => appRbacClient.accessPolicies.byPolicyId.memberBindings.delete({
params: {
appId,
policyId: payload.accessPolicyId,
app_id: appId,
policy_id: payload.accessPolicyId,
},
body: {
account_ids: payload.accountIds,
@ -79,10 +88,10 @@ export const useRemoveAppAccessPolicyMemberBindings = (appId: string) => {
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.apps.accessRules.key(),
queryKey: appRbacContract.accessPolicy.get.key({ type: 'query' }),
}),
])
},
@ -94,9 +103,9 @@ export const useUpdateAppOpenScope = (appId: string) => {
return useMutation({
mutationKey: [NAME_SPACE, 'update-app-open-scope', appId],
mutationFn: (openScope: ResourceOpenScope) => consoleClient.rbacAccessConfig.apps.updateOpenScope({
mutationFn: (openScope: ResourceOpenScope) => appRbacClient.whitelist.put({
params: {
appId,
app_id: appId,
},
body: {
scope: openScope,
@ -105,7 +114,7 @@ export const useUpdateAppOpenScope = (appId: string) => {
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
])
},

View File

@ -6,8 +6,11 @@ import type {
} from '@/models/access-control'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { consoleClient, consoleQuery } from '@/service/client'
import { normalizeDatasetAccessMatrix, normalizeDatasetUserAccessPolicies } from './normalizers'
const NAME_SPACE = 'dataset-access-config'
const datasetRbacContract = consoleQuery.workspaces.current.rbac.datasets.byDatasetId
const datasetRbacClient = consoleClient.workspaces.current.rbac.datasets.byDatasetId
type DatasetAccessConfigQueryOptions = {
enabled?: boolean
@ -15,10 +18,10 @@ type DatasetAccessConfigQueryOptions = {
export const useDatasetAccessRules = (datasetId: string, language: AccessControlTemplateLanguage, options?: DatasetAccessConfigQueryOptions) => {
return useQuery({
...consoleQuery.rbacAccessConfig.datasets.accessRules.queryOptions({
...datasetRbacContract.accessPolicy.get.queryOptions({
input: {
params: {
datasetId,
dataset_id: datasetId,
},
query: {
language,
@ -26,15 +29,16 @@ export const useDatasetAccessRules = (datasetId: string, language: AccessControl
},
}),
enabled: options?.enabled ?? true,
select: normalizeDatasetAccessMatrix,
})
}
export const useDatasetUserAccessSettings = (datasetId: string, language: AccessControlTemplateLanguage, options?: DatasetAccessConfigQueryOptions) => {
return useQuery({
...consoleQuery.rbacAccessConfig.datasets.userAccessSettings.queryOptions({
...datasetRbacContract.userAccessPolicies.get.queryOptions({
input: {
params: {
datasetId,
dataset_id: datasetId,
},
query: {
language,
@ -42,6 +46,7 @@ export const useDatasetUserAccessSettings = (datasetId: string, language: Access
},
}),
enabled: options?.enabled ?? true,
select: normalizeDatasetUserAccessPolicies,
})
}
@ -50,10 +55,10 @@ export const useUpdateDatasetUserAccessSettings = (datasetId: string) => {
return useMutation({
mutationKey: [NAME_SPACE, 'update-dataset-user-access-settings', datasetId],
mutationFn: (payload: UpdateDatasetUserAccessSettingsRequest) => consoleClient.rbacAccessConfig.datasets.updateUserAccessSettings({
mutationFn: (payload: UpdateDatasetUserAccessSettingsRequest) => datasetRbacClient.users.byTargetAccountId.accessPolicies.put({
params: {
datasetId,
accountId: payload.accountId,
dataset_id: datasetId,
target_account_id: payload.accountId,
},
body: {
access_policy_ids: payload.accessPolicyIds,
@ -62,10 +67,10 @@ export const useUpdateDatasetUserAccessSettings = (datasetId: string) => {
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.datasets.accessRules.key(),
queryKey: datasetRbacContract.accessPolicy.get.key({ type: 'query' }),
}),
])
},
@ -77,10 +82,10 @@ export const useRemoveDatasetAccessPolicyMemberBindings = (datasetId: string) =>
return useMutation({
mutationKey: [NAME_SPACE, 'remove-dataset-access-policy-member-bindings', datasetId],
mutationFn: (payload: RemoveDatasetAccessPolicyMemberBindingsRequest) => consoleClient.rbacAccessConfig.datasets.removeMemberBindings({
mutationFn: (payload: RemoveDatasetAccessPolicyMemberBindingsRequest) => datasetRbacClient.accessPolicies.byPolicyId.memberBindings.delete({
params: {
datasetId,
policyId: payload.accessPolicyId,
dataset_id: datasetId,
policy_id: payload.accessPolicyId,
},
body: {
account_ids: payload.accountIds,
@ -89,10 +94,10 @@ export const useRemoveDatasetAccessPolicyMemberBindings = (datasetId: string) =>
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.datasets.accessRules.key(),
queryKey: datasetRbacContract.accessPolicy.get.key({ type: 'query' }),
}),
])
},
@ -104,9 +109,9 @@ export const useUpdateDatasetOpenScope = (datasetId: string) => {
return useMutation({
mutationKey: [NAME_SPACE, 'update-dataset-open-scope', datasetId],
mutationFn: (openScope: ResourceOpenScope) => consoleClient.rbacAccessConfig.datasets.updateOpenScope({
mutationFn: (openScope: ResourceOpenScope) => datasetRbacClient.whitelist.put({
params: {
datasetId,
dataset_id: datasetId,
},
body: {
scope: openScope,
@ -115,7 +120,7 @@ export const useUpdateDatasetOpenScope = (datasetId: string) => {
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
}),
])
},

View File

@ -17,8 +17,6 @@ const customConsoleContractLoaders: Record<string, () => Promise<AnyContractRout
modelProviders: () =>
import('@/contract/console/model-providers').then(({ modelProvidersRouterContract }) => wrapConsoleContract('modelProviders', modelProvidersRouterContract)),
plugins: () => import('@/contract/console/plugins').then(({ pluginsRouterContract }) => wrapConsoleContract('plugins', pluginsRouterContract)),
rbacAccessConfig: () =>
import('@/contract/console/access-control').then(({ rbacAccessConfigContract }) => wrapConsoleContract('rbacAccessConfig', rbacAccessConfigContract)),
snippets: () => import('@/contract/console/snippets').then(({ snippetsRouterContract }) => wrapConsoleContract('snippets', snippetsRouterContract)),
triggers: () => import('@/contract/console/trigger').then(({ triggersRouterContract }) => wrapConsoleContract('triggers', triggersRouterContract)),
trialApps: () => import('@/contract/console/try-app').then(({ trialAppsRouterContract }) => wrapConsoleContract('trialApps', trialAppsRouterContract)),