Skip to content

Commit 3b02b09

Browse files
faisalsiddique4400duttarnabmoabu
authored
fix(admin-ui): resolve issue preventing deletion of capabilities (#2303)
* fix(admin-ui): resolve issue preventing deletion of capabilities * requested changes done * Removed un0necessary console Signed-off-by: Faisal Siddique <71010439+faisalsiddique4400@users.noreply.github.com> --------- Signed-off-by: Faisal Siddique <71010439+faisalsiddique4400@users.noreply.github.com> Co-authored-by: Arnab Dutta <arnab.bdutta@gmail.com> Co-authored-by: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com>
1 parent ea2abb7 commit 3b02b09

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Utilities for resolving permission keys, computing mapped roles, and building user-friendly messages
2+
3+
export type ApiPermissionItem = {
4+
inum?: string
5+
permission?: string
6+
[key: string]: unknown
7+
}
8+
9+
export type RolePermissionMappingEntry = {
10+
role: string
11+
permissions: string[]
12+
}
13+
14+
type ActionData =
15+
| { inum?: string; permission?: string; [key: string]: unknown }
16+
| string
17+
| null
18+
| undefined
19+
20+
/**
21+
* Resolve the permission key (string) from actionData and the list of apiPermissions.
22+
* actionData may be an object with { inum, permission } or just an inum string.
23+
*/
24+
export function resolvePermissionKey(
25+
actionData: ActionData,
26+
apiPermissions: ApiPermissionItem[] | undefined,
27+
): string | undefined {
28+
const isObject = (value: ActionData): value is { inum?: string; permission?: string } => {
29+
return typeof value === 'object' && value !== null
30+
}
31+
32+
const permissionFromAction = isObject(actionData) ? actionData.permission : undefined
33+
if (permissionFromAction) return permissionFromAction
34+
35+
const permissionInum = isObject(actionData) ? actionData.inum : actionData
36+
if (!permissionInum) return undefined
37+
38+
const found = Array.isArray(apiPermissions)
39+
? apiPermissions.find((p) => p?.inum === permissionInum)
40+
: undefined
41+
return found?.permission
42+
}
43+
44+
/**
45+
* Find roles that contain the given permission key using the role-permission mapping from the store.
46+
*/
47+
export function findRolesForPermission(
48+
permissionKey: string | undefined,
49+
rolePermissionMapping: RolePermissionMappingEntry[] | undefined,
50+
): string[] {
51+
if (!permissionKey || !Array.isArray(rolePermissionMapping)) return []
52+
return rolePermissionMapping
53+
.filter((r) => Array.isArray(r?.permissions) && r.permissions.includes(permissionKey))
54+
.map((r) => r.role)
55+
}
56+
57+
export function buildMappingGuidanceMessage(
58+
permissionKey: string | undefined,
59+
mappedRoles: string[] | undefined,
60+
): string {
61+
if (!permissionKey) {
62+
return 'Unable to delete permission. Permission identifier not found.'
63+
}
64+
65+
if (!mappedRoles || mappedRoles.length === 0) {
66+
return `Unable to delete permission "${permissionKey}". Please check if it's still in use.`
67+
}
68+
69+
const rolesList = mappedRoles.join(', ')
70+
const rolesWord = mappedRoles.length > 1 ? 'roles' : 'role'
71+
return `Unable to delete permission "${permissionKey}". It is currently mapped to ${rolesWord}: ${rolesList}. Please remove it from the role mapping menu first.`
72+
}
73+
74+
export function buildPermissionDeleteErrorMessage(
75+
actionData: ActionData,
76+
apiPermissions: ApiPermissionItem[] | undefined,
77+
rolePermissionMapping: RolePermissionMappingEntry[] | undefined,
78+
): string {
79+
const permissionKey = resolvePermissionKey(actionData, apiPermissions)
80+
const mappedRoles = findRolesForPermission(permissionKey, rolePermissionMapping)
81+
return buildMappingGuidanceMessage(permissionKey, mappedRoles)
82+
}

admin-ui/plugins/admin/redux/api/PermissionApi.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ export default class PermissionApi {
3333
}
3434

3535
deletePermission = (data) => {
36+
const options = {}
37+
options['adminPermission'] = data
3638
return new Promise((resolve, reject) => {
37-
this.api.deleteAdminuiPermission(encodeURIComponent(data.permission), (error, data) => {
39+
this.api.deleteAdminuiPermission(options, (error, data) => {
3840
handleResponse(error, reject, resolve, data)
3941
})
4042
})

admin-ui/plugins/admin/redux/sagas/ApiPermissionSaga.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { updateToast } from 'Redux/features/toastSlice'
1616

1717
const JansConfigApi = require('jans_config_api')
1818
import { initAudit } from 'Redux/sagas/SagaUtils'
19+
import { buildPermissionDeleteErrorMessage } from 'Utils/PermissionMappingUtils'
1920

2021
function* newFunction() {
2122
const token = yield select((state) => state.authReducer.token.access_token)
@@ -121,7 +122,22 @@ export function* deletePermission({ payload }) {
121122
})
122123
return data
123124
} catch (e) {
124-
yield put(updateToast(true, 'error'))
125+
const actionData = payload?.action?.action_data
126+
const apiPermissions = yield select((state) => state.apiPermissionReducer.items || [])
127+
const rolePermissionMapping = yield select((state) => state.mappingReducer.items || [])
128+
let finalMessage
129+
try {
130+
finalMessage = buildPermissionDeleteErrorMessage(
131+
actionData,
132+
apiPermissions,
133+
rolePermissionMapping,
134+
)
135+
} catch (msgError) {
136+
console.error('Error building permission delete message:', msgError)
137+
finalMessage =
138+
e?.response?.body?.responseMessage || e.message || 'Failed to delete permission'
139+
}
140+
yield put(updateToast(true, 'error', finalMessage))
125141
yield put(deletePermissionResponse({ inum: null }))
126142
if (isFourZeroOneError(e)) {
127143
const jwt = yield select((state) => state.authReducer.userinfo_jwt)

0 commit comments

Comments
 (0)