Merge branch 'feature/rw-stage-rbac-settings-permissions' into poc/permissions-parametrized-actions

This commit is contained in:
Marc-Roig 2023-08-08 14:41:36 +02:00
commit 3d07c67652
No known key found for this signature in database
GPG Key ID: FB4E2C43A0BEE249
5 changed files with 65 additions and 17 deletions

View File

@ -3,7 +3,7 @@ import * as React from 'react';
import { useFetchClient } from '@strapi/helper-plugin'; import { useFetchClient } from '@strapi/helper-plugin';
import { useQuery } from 'react-query'; import { useQuery } from 'react-query';
export function useLicenseLimits({ enabled } = { enabled: true }) { export function useLicenseLimits(queryOptions = {}) {
const { get } = useFetchClient(); const { get } = useFetchClient();
const { data, isError, isLoading } = useQuery( const { data, isError, isLoading } = useQuery(
['ee', 'license-limit-info'], ['ee', 'license-limit-info'],
@ -15,11 +15,17 @@ export function useLicenseLimits({ enabled } = { enabled: true }) {
return data; return data;
}, },
{ {
enabled, ...queryOptions,
// the request is expected to fail sometimes if a user does not
// have permissions
retry: false,
} }
); );
const license = data ?? {}; const license = React.useMemo(() => {
return data ?? {};
}, [data]);
const getFeature = React.useCallback( const getFeature = React.useCallback(
(name) => { (name) => {

View File

@ -184,17 +184,17 @@ export function Stage({
color: hex, color: hex,
})); }));
React.useEffect(() => {
dragPreviewRef(getEmptyImage(), { captureDraggingState: false });
}, [dragPreviewRef, index]);
const { themeColorName } = getStageColorByHex(colorField.value) ?? {}; const { themeColorName } = getStageColorByHex(colorField.value) ?? {};
const filteredRoles = roles const filteredRoles = roles
// Super admins always have permissions to do everything and therefore // Super admins always have permissions to do everything and therefore
// there is no point in removing permissions for the role // there is no point for this role to show up in the role combobox
.filter((role) => role.code !== 'strapi-super-admin'); .filter((role) => role.code !== 'strapi-super-admin');
React.useEffect(() => {
dragPreviewRef(getEmptyImage(), { captureDraggingState: false });
}, [dragPreviewRef, index]);
return ( return (
<Box ref={composedRef}> <Box ref={composedRef}>
{liveText && <VisuallyHidden aria-live="assertive">{liveText}</VisuallyHidden>} {liveText && <VisuallyHidden aria-live="assertive">{liveText}</VisuallyHidden>}
@ -363,7 +363,7 @@ export function Stage({
// to coerce the string value back to a number // to coerce the string value back to a number
const nextValues = values.map((value) => ({ const nextValues = values.map((value) => ({
role: parseInt(value, 10), role: parseInt(value, 10),
action: 'admin::review-workflow.stage.transition', action: 'admin::review-workflows.stage.transition',
})); }));
permissionsHelper.setValue(nextValues); permissionsHelper.setValue(nextValues);

View File

@ -94,7 +94,7 @@ const ComponentFixture = ({
{ {
color: STAGE_COLOR_DEFAULT, color: STAGE_COLOR_DEFAULT,
name: 'something', name: 'something',
permissions: [{ role: 1, action: 'admin::review-workflow.stage.transition' }], permissions: [{ role: 1, action: 'admin::review-workflows.stage.transition' }],
}, },
], ],
...props ...props

View File

@ -38,7 +38,12 @@ import {
} from '../../constants'; } from '../../constants';
import { useReviewWorkflows } from '../../hooks/useReviewWorkflows'; import { useReviewWorkflows } from '../../hooks/useReviewWorkflows';
import { reducer } from '../../reducer'; import { reducer } from '../../reducer';
import { selectIsLoading, selectIsWorkflowDirty, selectCurrentWorkflow } from '../../selectors'; import {
selectIsLoading,
selectIsWorkflowDirty,
selectCurrentWorkflow,
selectRoles,
} from '../../selectors';
import { validateWorkflow } from '../../utils/validateWorkflow'; import { validateWorkflow } from '../../utils/validateWorkflow';
export function ReviewWorkflowsCreateView() { export function ReviewWorkflowsCreateView() {
@ -50,10 +55,13 @@ export function ReviewWorkflowsCreateView() {
const toggleNotification = useNotification(); const toggleNotification = useNotification();
const { collectionTypes, singleTypes, isLoading: isLoadingContentTypes } = useContentTypes(); const { collectionTypes, singleTypes, isLoading: isLoadingContentTypes } = useContentTypes();
const { isLoading: isLoadingWorkflow, meta, workflows } = useReviewWorkflows(); const { isLoading: isLoadingWorkflow, meta, workflows } = useReviewWorkflows();
const { isLoading: isLoadingRoles, roles } = useAdminRoles(); const { isLoading: isLoadingRoles, roles: serverRoles } = useAdminRoles(undefined, {
retry: false,
});
const isLoading = useSelector(selectIsLoading); const isLoading = useSelector(selectIsLoading);
const currentWorkflowIsDirty = useSelector(selectIsWorkflowDirty); const currentWorkflowIsDirty = useSelector(selectIsWorkflowDirty);
const currentWorkflow = useSelector(selectCurrentWorkflow); const currentWorkflow = useSelector(selectCurrentWorkflow);
const roles = useSelector(selectRoles);
const [showLimitModal, setShowLimitModal] = React.useState(false); const [showLimitModal, setShowLimitModal] = React.useState(false);
const { isLoading: isLicenseLoading, getFeature } = useLicenseLimits(); const { isLoading: isLicenseLoading, getFeature } = useLicenseLimits();
const [initialErrors, setInitialErrors] = React.useState(null); const [initialErrors, setInitialErrors] = React.useState(null);
@ -184,7 +192,7 @@ export function ReviewWorkflowsCreateView() {
} }
if (!isLoadingRoles) { if (!isLoadingRoles) {
dispatch(setRoles(roles)); dispatch(setRoles(serverRoles));
} }
dispatch(setIsLoading(isLoadingContentTypes || isLoadingRoles)); dispatch(setIsLoading(isLoadingContentTypes || isLoadingRoles));
@ -201,7 +209,7 @@ export function ReviewWorkflowsCreateView() {
isLoadingContentTypes, isLoadingContentTypes,
isLoadingRoles, isLoadingRoles,
isLoadingWorkflow, isLoadingWorkflow,
roles, serverRoles,
singleTypes, singleTypes,
workflows, workflows,
]); ]);
@ -242,6 +250,21 @@ export function ReviewWorkflowsCreateView() {
currentWorkflow.stages.length, currentWorkflow.stages.length,
]); ]);
React.useEffect(() => {
const filteredRoles = roles.filter((role) => role.code !== 'strapi-super-admin');
if (!isLoading && filteredRoles.length === 0) {
toggleNotification({
blockTransition: true,
type: 'warning',
message: formatMessage({
id: 'Settings.review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles',
}),
});
}
}, [formatMessage, isLoading, roles, toggleNotification]);
return ( return (
<> <>
<Layout.DragLayerRendered /> <Layout.DragLayerRendered />

View File

@ -45,6 +45,7 @@ import {
selectCurrentWorkflow, selectCurrentWorkflow,
selectHasDeletedServerStages, selectHasDeletedServerStages,
selectIsLoading, selectIsLoading,
selectRoles,
selectServerState, selectServerState,
} from '../../selectors'; } from '../../selectors';
import { validateWorkflow } from '../../utils/validateWorkflow'; import { validateWorkflow } from '../../utils/validateWorkflow';
@ -63,13 +64,16 @@ export function ReviewWorkflowsEditView() {
const currentWorkflowIsDirty = useSelector(selectIsWorkflowDirty); const currentWorkflowIsDirty = useSelector(selectIsWorkflowDirty);
const currentWorkflow = useSelector(selectCurrentWorkflow); const currentWorkflow = useSelector(selectCurrentWorkflow);
const hasDeletedServerStages = useSelector(selectHasDeletedServerStages); const hasDeletedServerStages = useSelector(selectHasDeletedServerStages);
const roles = useSelector(selectRoles);
const isLoading = useSelector(selectIsLoading); const isLoading = useSelector(selectIsLoading);
const { const {
allowedActions: { canDelete, canUpdate }, allowedActions: { canDelete, canUpdate },
} = useRBAC(permissions.settings['review-workflows']); } = useRBAC(permissions.settings['review-workflows']);
const [savePrompts, setSavePrompts] = React.useState({}); const [savePrompts, setSavePrompts] = React.useState({});
const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits(); const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();
const { isLoading: isLoadingRoles, roles } = useAdminRoles(); const { isLoading: isLoadingRoles, roles: serverRoles } = useAdminRoles(undefined, {
retry: false,
});
const [showLimitModal, setShowLimitModal] = React.useState(false); const [showLimitModal, setShowLimitModal] = React.useState(false);
const [initialErrors, setInitialErrors] = React.useState(null); const [initialErrors, setInitialErrors] = React.useState(null);
@ -231,7 +235,7 @@ export function ReviewWorkflowsEditView() {
} }
if (!isLoadingRoles) { if (!isLoadingRoles) {
dispatch(setRoles(roles)); dispatch(setRoles(serverRoles));
} }
dispatch(setIsLoading(isLoadingWorkflow || isLoadingContentTypes || isLoadingRoles)); dispatch(setIsLoading(isLoadingWorkflow || isLoadingContentTypes || isLoadingRoles));
@ -247,7 +251,7 @@ export function ReviewWorkflowsEditView() {
isLoadingContentTypes, isLoadingContentTypes,
isLoadingWorkflow, isLoadingWorkflow,
isLoadingRoles, isLoadingRoles,
roles, serverRoles,
singleTypes, singleTypes,
workflow, workflow,
workflows, workflows,
@ -290,6 +294,21 @@ export function ReviewWorkflowsEditView() {
meta.workflowsTotal, meta.workflowsTotal,
]); ]);
React.useEffect(() => {
const filteredRoles = roles.filter((role) => role.code !== 'strapi-super-admin');
if (!isLoading && filteredRoles.length === 0) {
toggleNotification({
blockTransition: true,
type: 'warning',
message: formatMessage({
id: 'Settings.review-workflows.stage.permissions.noPermissions.description',
defaultMessage: 'You dont have the permission to see roles',
}),
});
}
}, [formatMessage, isLoading, roles, toggleNotification]);
// TODO: redirect back to list-view if workflow is not found? // TODO: redirect back to list-view if workflow is not found?
return ( return (