Overriding is working

This commit is contained in:
Owen
2026-06-01 20:54:37 -07:00
parent 6b3a0a2113
commit 8e0e32c2be
4 changed files with 32 additions and 57 deletions

View File

@@ -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",

View File

@@ -315,13 +315,13 @@ export default function ResourceAuthenticationPage() {
key={policies.sharedPolicy.resourcePolicyId}
>
<ActionBanner
variant="warning"
title={t("resourcePolicyReadOnly")}
variant="info"
title={t("resourcePolicyShared")}
titleIcon={
<ShieldAlertIcon className="w-5 h-5" />
}
description={t(
"resourcePolicyReadOnlyDescription"
"resourcePolicySharedDescription"
)}
actions={
<Button
@@ -332,14 +332,13 @@ export default function ResourceAuthenticationPage() {
<Link
href={`/${org.org.orgId}/settings/policies/resource/${policies.sharedPolicy.niceId}`}
>
{t("edit")}
{t("editSharedPolicy")}
<ArrowRightIcon className="size-4" />
</Link>
</Button>
}
/>
<EditPolicyForm
readonly
resourceId={resource.resourceId}
/>
</ResourcePolicyProvider>

View File

@@ -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 (
<SettingsContainer>
{!hidePolicyNameForm && (
<EditPolicyNameSectionForm readonly={readonly} />
<EditPolicyNameSectionForm readonly={policyLevelReadonly} />
)}
<EditPolicyUsersRolesSectionForm
@@ -89,11 +94,11 @@ export function EditPolicyForm({
resourceId={resourceId}
/>
<EditPolicyAuthMethodsSectionForm readonly={readonly} />
<EditPolicyAuthMethodsSectionForm readonly={policyLevelReadonly} />
<EditPolicyOtpEmailSectionForm
emailEnabled={env.email.emailEnabled}
readonly={readonly}
readonly={policyLevelReadonly}
/>
<EditPolicyRulesSectionForm

View File

@@ -268,59 +268,29 @@ export function EditPolicyUsersRolesSectionForm({
setIsSavingOverlay(true);
try {
// Compute which roles/users are resource-specific (non-locked)
const currentResourceRoleIds = new Set(
combinedRoles
.filter((r) => !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"),