// Shared RBAC form view-model helpers. function normalizeSectionId(value) { return String(value || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '-'); } function toSortIndex(value) { const number = Number(value); return Number.isFinite(number) ? number : 999; } function buildPermissionSections(permissionGroups) { const sections = []; const sectionIndex = new Map(); const actionDefinitions = [ { key: 'read', label: 'Read' }, { key: 'create', label: 'Create' }, { key: 'update', label: 'Update' }, { key: 'delete', label: 'Delete' }, { key: 'allow', label: 'Allow' } ]; (Array.isArray(permissionGroups) ? permissionGroups : []).forEach(function (group) { const sectionTitle = String(group && group.categoryName || 'Permissions').trim() || 'Permissions'; const sectionKey = normalizeSectionId(sectionTitle) || 'permissions'; if (!sectionIndex.has(sectionKey)) { sectionIndex.set(sectionKey, { id: sectionKey, title: sectionTitle, sourceIndex: toSortIndex(group && group.sectionIndex), sectionOrder: toSortIndex(group && group.sectionOrder), groups: [] }); sections.push(sectionIndex.get(sectionKey)); } const section = sectionIndex.get(sectionKey); const groupPermissions = Array.isArray(group && group.permissions) ? group.permissions.slice() : []; const sectionGroup = Object.assign({}, group, { permissions: groupPermissions }); section.groups.push(sectionGroup); }); sections.forEach(function (section) { section.actions = actionDefinitions.map(function (actionDefinition) { return { key: actionDefinition.key, label: actionDefinition.label }; }); section.groups.sort(function (left, right) { const leftOrder = toSortIndex(left.resourceOrder); const rightOrder = toSortIndex(right.resourceOrder); if (leftOrder !== rightOrder) { return leftOrder - rightOrder; } const leftIndex = toSortIndex(left.resourceIndex); const rightIndex = toSortIndex(right.resourceIndex); if (leftIndex !== rightIndex) { return leftIndex - rightIndex; } return String(left.title || '').localeCompare(String(right.title || '')); }); section.groups.forEach(function (group) { group.cells = section.actions.map(function (action) { return (Array.isArray(group.permissions) ? group.permissions : []).find(function (permission) { return String(permission.actionKey || '').trim().toLowerCase() === action.key; }) || null; }); }); }); sections.sort(function (left, right) { const leftOrder = toSortIndex(left.sectionOrder); const rightOrder = toSortIndex(right.sectionOrder); if (leftOrder !== rightOrder) { return leftOrder - rightOrder; } const leftIndex = toSortIndex(left.sourceIndex); const rightIndex = toSortIndex(right.sourceIndex); if (leftIndex !== rightIndex) { return leftIndex - rightIndex; } return String(left.title || '').localeCompare(String(right.title || '')); }); return sections; } function buildRbacAddViewModel(message, currentUser, formValues, permissionGroups, users, pagination, messageVariant) { return { title: 'Create role', active: 'rbac', isEdit: false, usersPresent: true, formId: 'role-create-form', formAction: '/settings/roles', footerSaveUrl: '/settings/roles', footerCancelUrl: '/settings/roles', cancelConfirmMessage: "You've made changes. Are you sure you want to leave this page?", footerDeleteUrl: '', footerDeleteDisabled: true, footerDeleteTitle: 'Delete is available after the role has been created.', footerShowDelete: true, message: message, messageVariant: messageVariant || 'primary', currentUser: currentUser || null, formValues: formValues || {}, permissionGroups: permissionGroups || [], permissionSections: buildPermissionSections(permissionGroups), users: users || [], pagination: pagination || null, roleEditBasePath: '/settings/roles/new', scripts: ['js/rbac-permissions.js'], formAttrs: 'data-async-save data-async-save-close-url="/settings/roles" data-async-save-new-redirect="response-url" data-async-save-new-url="/settings/roles/new"' }; } function buildRbacEditViewModel(role, message, currentUser, permissionGroups, users, pagination) { const roleKey = String(role && role.role_key || '').trim(); const isProtectedRole = roleKey === 'super-admin' || roleKey === 'administrators'; const deleteDisabled = isProtectedRole || Boolean(role && role.inUse); return { title: 'Edit role', active: 'rbac', isEdit: true, usersPresent: true, formId: 'role-edit-form', formAction: '/settings/roles/' + Number(role && role.id), footerSaveUrl: '/settings/roles/' + Number(role && role.id), footerCancelUrl: '/settings/roles', cancelConfirmMessage: "You've made changes. Are you sure you want to leave this page?", footerDeleteUrl: '/settings/roles/' + Number(role && role.id) + '/delete', footerDeleteDisabled: deleteDisabled, footerDeleteConfirmMessage: 'Delete ' + String(role && role.name || 'this role') + '?', footerDeleteTitle: isProtectedRole ? 'The built-in Super Admin role cannot be deleted.' : (role && role.inUse ? 'Delete is disabled while this role is assigned to users.' : ''), footerShowDelete: true, message: message, currentUser: currentUser || null, role: Object.assign({}, role, { isProtected: isProtectedRole }), inUse: deleteDisabled, permissionGroups: permissionGroups || [], permissionSections: buildPermissionSections(permissionGroups), users: users || [], pagination: pagination || null, roleEditBasePath: '/settings/roles/' + Number(role && role.id) + '/edit', scripts: ['js/rbac-permissions.js'], formAttrs: 'data-async-save data-async-save-close-url="/settings/roles" data-async-save-new-url="/settings/roles/new"' }; } module.exports = { buildRbacAddViewModel: buildRbacAddViewModel, buildRbacEditViewModel: buildRbacEditViewModel, buildPermissionSections: buildPermissionSections };