feat(Roles): adopt request form data for new form style

This commit is contained in:
Ali BARIN
2025-04-09 14:01:39 +00:00
parent 80a54bc444
commit e2542f39e1
8 changed files with 201 additions and 131 deletions

View File

@@ -1,51 +0,0 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';
import PropTypes from 'prop-types';
import ControlledCheckbox from 'components/ControlledCheckbox';
const ActionField = ({ action, subject, disabled, name, syncIsCreator }) => {
const { formState, resetField } = useFormContext();
const actionDefaultValue =
formState.defaultValues?.[name]?.[subject.key]?.[action.key].value;
const conditionFieldName = `${name}.${subject.key}.${action.key}.conditions.isCreator`;
const conditionFieldTouched =
formState.touchedFields?.[name]?.[subject.key]?.[action.key]?.conditions
?.isCreator === true;
const handleSyncIsCreator = (newValue) => {
if (
syncIsCreator &&
actionDefaultValue === false &&
!conditionFieldTouched
) {
resetField(conditionFieldName, { defaultValue: newValue });
}
};
return (
<ControlledCheckbox
disabled={disabled}
name={`${name}.${subject.key}.${action.key}.value`}
dataTest={`${action.key.toLowerCase()}-checkbox`}
onChange={(e, value) => {
handleSyncIsCreator(value);
}}
/>
);
};
ActionField.propTypes = {
action: PropTypes.shape({
key: PropTypes.string.isRequired,
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
}),
subject: PropTypes.shape({
key: PropTypes.string.isRequired,
}).isRequired,
disabled: PropTypes.bool,
name: PropTypes.string.isRequired,
syncIsCreator: PropTypes.bool,
};
export default ActionField;

View File

@@ -0,0 +1,63 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';
import PropTypes from 'prop-types';
import ControlledCheckbox from 'components/ControlledCheckbox';
const AllEntitiesPermissions = ({
action,
subject,
disabled,
name,
syncIsCreator,
}) => {
const { getValues, formState, resetField } = useFormContext();
const fieldName = `${name}.${subject.key}.${action.key}.allEntities`;
const defaultValue =
formState.defaultValues?.[name]?.[subject.key]?.[action.key].allEntities;
const ownEntitiesFieldName = `${name}.${subject.key}.${action.key}.ownEntities`;
const ownEntitiesFieldTouched =
formState.touchedFields?.[name]?.[subject.key]?.[action.key]
?.ownEntities === true;
const currentValue = getValues(fieldName);
React.useEffect(() => {
if (currentValue === true) {
resetField(ownEntitiesFieldName, { defaultValue: true });
}
}, [ownEntitiesFieldName, currentValue]);
const handleSyncIsCreator = (newValue) => {
if (syncIsCreator && defaultValue === false && !ownEntitiesFieldTouched) {
resetField(ownEntitiesFieldName, { defaultValue: newValue });
}
if (newValue === true) {
resetField(ownEntitiesFieldName, { defaultValue: true });
}
};
return (
<ControlledCheckbox
disabled={disabled}
name={fieldName}
dataTest={`${action.key.toLowerCase()}-checkbox`}
/>
);
};
AllEntitiesPermissions.propTypes = {
action: PropTypes.shape({
key: PropTypes.string.isRequired,
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
}),
subject: PropTypes.shape({
key: PropTypes.string.isRequired,
}).isRequired,
disabled: PropTypes.bool,
name: PropTypes.string.isRequired,
syncIsCreator: PropTypes.bool,
};
export default AllEntitiesPermissions;

View File

@@ -0,0 +1,41 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';
import PropTypes from 'prop-types';
import ControlledCheckbox from 'components/ControlledCheckbox';
const OwnEntitiesPermission = ({ action, subject, disabled, name }) => {
const { getValues, resetField } = useFormContext();
const fieldName = `${name}.${subject.key}.${action.key}.ownEntities`;
const allEntitiesFieldName = `${name}.${subject.key}.${action.key}.allEntities`;
const currentValue = getValues(fieldName);
React.useEffect(() => {
if (currentValue === false) {
resetField(allEntitiesFieldName, { defaultValue: false });
}
}, [allEntitiesFieldName, currentValue]);
return (
<ControlledCheckbox
name={fieldName}
disabled={disabled}
dataTest={`isCreator-${action.key.toLowerCase()}-checkbox`}
/>
);
};
OwnEntitiesPermission.propTypes = {
action: PropTypes.shape({
key: PropTypes.string.isRequired,
subjects: PropTypes.arrayOf(PropTypes.string).isRequired,
}),
subject: PropTypes.shape({
key: PropTypes.string.isRequired,
}).isRequired,
disabled: PropTypes.bool,
name: PropTypes.string.isRequired,
};
export default OwnEntitiesPermission;

View File

@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import SettingsIcon from '@mui/icons-material/Settings';
import IconButton from '@mui/material/IconButton';
import Paper from '@mui/material/Paper';
@@ -10,12 +9,16 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Typography from '@mui/material/Typography';
import PropTypes from 'prop-types';
import * as React from 'react';
import ControlledCheckbox from 'components/ControlledCheckbox';
import usePermissionCatalog from 'hooks/usePermissionCatalog.ee';
import PermissionSettings from './PermissionSettings.ee';
import useFormatMessage from 'hooks/useFormatMessage';
import AllEntitiesPermissions from './AllEntitiesPermissions';
import ConditionField from './OwnEntitiesPermission';
import PermissionCatalogFieldLoader from './PermissionCatalogFieldLoader';
import ActionField from './ActionField';
import PermissionSettings from './PermissionSettings.ee';
const PermissionCatalogField = ({
name = 'permissions',
@@ -23,6 +26,7 @@ const PermissionCatalogField = ({
syncIsCreator = false,
loading = false,
}) => {
const formatMessage = useFormatMessage();
const { data, isLoading: isPermissionCatalogLoading } =
usePermissionCatalog();
const permissionCatalog = data?.data;
@@ -39,24 +43,44 @@ const PermissionCatalogField = ({
<TableCell component="th" />
{permissionCatalog?.actions.map((action) => (
<TableCell component="th" key={action.key}>
<Typography
component="div"
variant="subtitle1"
align="center"
sx={{
color: 'text.secondary',
fontWeight: 700,
}}
>
{action.label}
</Typography>
</TableCell>
))}
<React.Fragment key={action.key}>
<TableCell component="th" key={action.key}>
<Typography
component="div"
variant="subtitle2"
align="center"
sx={{
color: 'text.secondary',
fontWeight: 700,
}}
>
{action.label}{' '}
{formatMessage('permissionCatalogField.ownEntitiesLabel')}
</Typography>
</TableCell>
<TableCell component="th" />
<TableCell
component="th"
key={`${action.key}-isCreator-condition`}
>
<Typography
component="div"
variant="subtitle2"
align="center"
sx={{
color: 'text.secondary',
fontWeight: 700,
}}
>
{action.label}{' '}
{formatMessage('permissionCatalogField.allEntitiesLabel')}
</Typography>
</TableCell>
</React.Fragment>
))}
</TableRow>
</TableHead>
<TableBody>
{permissionCatalog?.subjects.map((subject) => (
<TableRow
@@ -71,44 +95,43 @@ const PermissionCatalogField = ({
</TableCell>
{permissionCatalog?.actions.map((action) => (
<TableCell key={`${subject.key}.${action.key}`} align="center">
<Typography variant="subtitle2" component="div">
{action.subjects.includes(subject.key) && (
<ActionField
action={action}
subject={subject}
disabled={disabled}
name={name}
syncIsCreator={syncIsCreator}
/>
)}
{!action.subjects.includes(subject.key) && '-'}
</Typography>
</TableCell>
))}
<TableCell>
<Stack direction="row" gap={1} justifyContent="right">
<IconButton
color="info"
size="small"
onClick={() => setDialogName(subject.key)}
disabled={disabled}
data-test="permission-settings-button"
<React.Fragment key={`${subject.key}.${action.key}`}>
<TableCell
key={`${subject.key}.${action.key}-isCreator-condition`}
align="center"
>
<SettingsIcon />
</IconButton>
<Typography variant="subtitle2" component="div">
{action.subjects.includes(subject.key) && (
<ConditionField
action={action}
subject={subject}
disabled={disabled}
name={name}
/>
)}
{!action.subjects.includes(subject.key) && '-'}
</Typography>
</TableCell>
<PermissionSettings
open={dialogName === subject.key}
onClose={() => setDialogName('')}
fieldPrefix={`${name}.${subject.key}`}
subject={subject.key}
actions={permissionCatalog?.actions}
conditions={permissionCatalog?.conditions}
/>
</Stack>
</TableCell>
<TableCell
key={`${subject.key}.${action.key}`}
align="center"
>
<Typography variant="subtitle2" component="div">
{action.subjects.includes(subject.key) && (
<AllEntitiesPermissions
action={action}
subject={subject}
disabled={disabled}
name={name}
syncIsCreator={syncIsCreator}
/>
)}
{!action.subjects.includes(subject.key) && '-'}
</Typography>
</TableCell>
</React.Fragment>
))}
</TableRow>
))}
</TableBody>
@@ -116,6 +139,7 @@ const PermissionCatalogField = ({
</TableContainer>
);
};
PermissionCatalogField.propTypes = {
name: PropTypes.string,
disabled: PropTypes.bool,

View File

@@ -6,10 +6,8 @@ export function getRoleWithComputedPermissions(role) {
[permission.subject]: {
...(computedPermissions[permission.subject] || {}),
[permission.action]: {
conditions: Object.fromEntries(
permission.conditions.map((condition) => [condition, true]),
),
value: true,
allEntities: permission.conditions.includes('isCreator') === false,
ownEntities: true,
},
},
}),
@@ -28,15 +26,19 @@ export function getPermissions(computedPermissions) {
(permissions, computedPermissionEntry) => {
const [subject, actionsWithConditions] = computedPermissionEntry;
for (const action in actionsWithConditions) {
const { value: permitted, conditions = {} } =
actionsWithConditions[action];
if (permitted) {
const { ownEntities, allEntities } = actionsWithConditions[action];
if (ownEntities && !allEntities) {
permissions.push({
action,
subject,
conditions: Object.entries(conditions)
.filter(([, enabled]) => enabled)
.map(([condition]) => condition),
conditions: ['isCreator'],
});
} else if (ownEntities && allEntities) {
permissions.push({
action,
subject,
conditions: [],
});
}
}
@@ -46,18 +48,9 @@ export function getPermissions(computedPermissions) {
);
}
export const getComputedPermissionsDefaultValues = (
data,
conditionsInitialValues,
) => {
export const getComputedPermissionsDefaultValues = (data) => {
if (!data) return {};
const conditions = {};
data.conditions.forEach((condition) => {
conditions[condition.key] =
conditionsInitialValues?.[condition.key] || false;
});
const result = {};
data.subjects.forEach((subject) => {
@@ -69,8 +62,8 @@ export const getComputedPermissionsDefaultValues = (
if (action.subjects.includes(subjectKey)) {
result[subjectKey][actionKey] = {
value: false,
conditions: { ...conditions },
ownEntities: false,
allEntities: false,
};
}
});

View File

@@ -403,5 +403,7 @@
"executionFilters.statusFilterSuccessfulOption": "Successful",
"executionFilters.statusFilterFailedOption": "Failed",
"executionFilters.startDateLabel": "Start Date",
"executionFilters.endDateLabel": "End Date"
"executionFilters.endDateLabel": "End Date",
"permissionCatalogField.ownEntitiesLabel": "(own entities)",
"permissionCatalogField.allEntitiesLabel": "(all entities)"
}

View File

@@ -73,9 +73,6 @@ export default function CreateRole() {
description: '',
computedPermissions: getComputedPermissionsDefaultValues(
permissionCatalogData?.data,
{
isCreator: true,
},
),
}),
[permissionCatalogData],

View File

@@ -78,6 +78,7 @@ export default function EditRole() {
try {
setPermissionError(null);
const newPermissions = getPermissions(roleData.computedPermissions);
await updateRole({
name: roleData.name,
description: roleData.description,