///////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2025, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // ////////////////////////////////////////////////////////////// import React, { useMemo, useEffect } from 'react'; import url_for from 'sources/url_for'; import gettext from 'sources/gettext'; import getApiInstance, { parseApiError } from '../../../../static/js/api_instance'; import { Box, FormLabel } from '@mui/material'; import SectionContainer from '../../../../dashboard/static/js/components/SectionContainer'; import { InputCheckbox, InputSelect, InputText } from '../../../../static/js/components/FormComponents'; import { SearchRounded } from '@mui/icons-material'; import { PgButtonGroup, PgIconButton, PrimaryButton } from '../../../../static/js/components/Buttons'; import { usePgAdmin } from '../../../../static/js/PgAdminProvider'; import Loader from 'sources/components/Loader'; import SelectAllRoundedIcon from '@mui/icons-material/SelectAllRounded'; import DeselectRoundedIcon from '@mui/icons-material/DeselectRounded'; import PropTypes from 'prop-types'; function PermissionsForRole({sections, selectedPerms, setSelectedPerms}) { return ( {Object.keys(sections).map(section => { const items = sections[section]; return {section} } aria-label="Select All" title={gettext('Select All')} onClick={() => { setSelectedPerms((prev) => { return Array.from(new Set([...prev, ...items.map(i => i.name)])); }); }} > } aria-label="Deselect All" title={gettext('Deselect All')} onClick={() => { setSelectedPerms((prev) => { return prev.filter((p) => !items.map(i => i.name).includes(p)); }); }} > } style={{minHeight: 0, height: 'auto'}}> {items.map(item => ( { let val = e.target.checked; setSelectedPerms((prev) => { if (val) { return [...prev, item.name]; } else { return prev.filter((p) => p !== item.name); } }); }} sx={{widht: 'fit-content'}} /> ))} ; })} ); } PermissionsForRole.propTypes = { sections: PropTypes.object, selectedPerms: PropTypes.array, setSelectedPerms: PropTypes.func, }; export default function Permissions({roles, updateRolePermissions}) { const api = getApiInstance(); const [allPermissions, setAllPermissions] = React.useState([]); const [searchVal, setSearchVal] = React.useState(''); const [selectedPerms, setSelectedPerms] = React.useState([]); const [selectedRole, setSelectedRole] = React.useState(); const [loading, setLoading] = React.useState(''); const pgAdmin = usePgAdmin(); const isDirty = useMemo(() => { return JSON.stringify(roles.find((r)=>r.id === selectedRole)?.permissions.sort() || []) !== JSON.stringify(selectedPerms.sort()); }, [selectedRole, selectedPerms, roles]); const savePermissions = async () => { const url = url_for('user_management.save_permissions', {id: selectedRole}); try { setLoading(gettext('Saving...')); const resp = await api.put(url, {permissions: selectedPerms}); updateRolePermissions(selectedRole, resp.data.permissions); pgAdmin.Browser.notifier.success(gettext('Permissions saved successfully')); } catch (error) { pgAdmin.Browser.notifier.error(parseApiError(error)); console.error(error); } setLoading(''); }; useEffect(() => { const url = url_for('user_management.all_permissions'); api.get(url) .then(response => { setAllPermissions(response.data); }) .catch(error => { pgAdmin.Browser.notifier.error(parseApiError(error)); console.error(error); }); }, []); useEffect(() => { setSelectedPerms(roles.find((r)=>r.id === selectedRole)?.permissions || []); }, [selectedRole]); useEffect(() => { if (selectedRole) { const role = roles.find((r)=>r.id === selectedRole); if (!role) { setSelectedRole(undefined); } } }, [roles]); const filteredAllPermissions = useMemo(() => { return allPermissions.filter(perm => perm.label.toLowerCase().includes(searchVal.toLowerCase())); }, [allPermissions, searchVal]); // Convert the permissions array to section based dict const sections = useMemo(()=>{ return filteredAllPermissions.reduce((acc, perm) => { let section = perm.category; if (!acc[section]) { acc[section] = []; } acc[section].push(perm); return acc; }, {}); }, [filteredAllPermissions]); return ( {gettext('Role')} r.name != 'Administrator').map((r) => ({ label: r.name, value: r.id }))} optionsReloadBasis={roles.map((r)=>r.name).join('')} onChange={(val) => {setSelectedRole(val);}} value={selectedRole} placeholder={gettext('Select Role')} /> {gettext('Save')} { setSearchVal(val); }} startAdornment={} /> {selectedRole && } ); } Permissions.propTypes = { roles: PropTypes.array.isRequired, updateRolePermissions: PropTypes.func.isRequired, };