diff --git a/messages/en-US.json b/messages/en-US.json index 937032c18..bee581c73 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -872,6 +872,7 @@ "resourcePolicyOtpEmpty": "No one time password", "resourcePolicyReadOnly": "This policy is Read only", "resourcePolicyReadOnlyDescription": "This resource policy is shared accross multiple resources, you cannot edit it on this page.", + "editSharedPolicy": "Edit Shared Policy", "resourcePolicyTypeSave": "Save Resource type", "resourcePolicySelect": "Select resource policy", "resourcePolicySelectError": "Select a resource policy", @@ -918,7 +919,7 @@ "resourcePolicyInline": "Inline Resource Policy", "resourcePolicyInlineDescription": "Access Policy scoped to only this resource", "resourcePolicyShared": "Shared Resource Policy", - "resourcePolicySharedDescription": "Access Policy shared accross multiple resources", + "resourcePolicySharedDescription": "This resource uses a shared policy. Policy-level settings (auth methods, email whitelist) are locked. You can add resource-specific rules, roles, and users below.", "resourceUsersRoles": "Access Controls", "resourceUsersRolesDescription": "Configure which users and roles can visit this resource", "resourceUsersRolesSubmit": "Save Access Controls", diff --git a/src/app/[orgId]/settings/resources/public/[niceId]/authentication/page.tsx b/src/app/[orgId]/settings/resources/public/[niceId]/authentication/page.tsx index 760205ec8..ba55ce833 100644 --- a/src/app/[orgId]/settings/resources/public/[niceId]/authentication/page.tsx +++ b/src/app/[orgId]/settings/resources/public/[niceId]/authentication/page.tsx @@ -315,13 +315,13 @@ export default function ResourceAuthenticationPage() { key={policies.sharedPolicy.resourcePolicyId} > } description={t( - "resourcePolicyReadOnlyDescription" + "resourcePolicySharedDescription" )} actions={ } /> diff --git a/src/components/resource-policy/EditPolicyForm.tsx b/src/components/resource-policy/EditPolicyForm.tsx index 043ab1852..bed4a4647 100644 --- a/src/components/resource-policy/EditPolicyForm.tsx +++ b/src/components/resource-policy/EditPolicyForm.tsx @@ -44,6 +44,11 @@ export function EditPolicyForm({ const router = useRouter(); + // In overlay mode (resourceId provided), policy-level sections are locked. + // Rules and users/roles sections handle their own hybrid logic via resourceId. + const isOverlay = resourceId !== undefined; + const policyLevelReadonly = readonly || isOverlay; + const isMaxmindAvailable = !!( env.server.maxmind_db_path && env.server.maxmind_db_path.length > 0 ); @@ -79,7 +84,7 @@ export function EditPolicyForm({ return ( {!hidePolicyNameForm && ( - + )} - + !policyRoleLockedIds.has(r.id)) - .map((r) => r.id) - ); - const currentResourceUserIds = new Set( - combinedUsers - .filter((u) => !policyUserLockedIds.has(u.id)) - .map((u) => u.id) - ); - - const initialRoleIds = initialResourceRoleIdsRef.current; - const initialUserIds = initialResourceUserIdsRef.current; - - const addedRoleIds = [...currentResourceRoleIds].filter( - (id) => !initialRoleIds.has(id) - ); - const removedRoleIds = [...initialRoleIds].filter( - (id) => !currentResourceRoleIds.has(id) - ); - const addedUserIds = [...currentResourceUserIds].filter( - (id) => !initialUserIds.has(id) - ); - const removedUserIds = [...initialUserIds].filter( - (id) => !currentResourceUserIds.has(id) - ); + const currentResourceRoleIds = combinedRoles + .filter((r) => !policyRoleLockedIds.has(r.id)) + .map((r) => Number(r.id)); + const currentResourceUserIds = combinedUsers + .filter((u) => !policyUserLockedIds.has(u.id)) + .map((u) => u.id); + // Use bulk-set endpoints (session-authenticated) which replace + // all resource-specific roles/users in one call await Promise.all([ - ...addedRoleIds.map((id) => - api.post(`/resource/${resourceId}/roles/add`, { - roleId: Number(id) - }) - ), - ...removedRoleIds.map((id) => - api.post(`/resource/${resourceId}/roles/remove`, { - roleId: Number(id) - }) - ), - ...addedUserIds.map((id) => - api.post(`/resource/${resourceId}/users/add`, { - userId: id - }) - ), - ...removedUserIds.map((id) => - api.post(`/resource/${resourceId}/users/remove`, { - userId: id - }) - ) + api.post(`/resource/${resourceId}/roles`, { + roleIds: currentResourceRoleIds + }), + api.post(`/resource/${resourceId}/users`, { + userIds: currentResourceUserIds + }) ]); // Update refs to reflect new state - initialResourceRoleIdsRef.current = currentResourceRoleIds; - initialResourceUserIdsRef.current = currentResourceUserIds; + initialResourceRoleIdsRef.current = new Set( + currentResourceRoleIds.map(String) + ); + initialResourceUserIdsRef.current = new Set(currentResourceUserIds); toast({ title: t("success"),