Hey, we have users (authors) in our cms who can create and edit pages as drafts but only specific users (editors) are allowed to publish them / update already published pages.
There are now access rules for the publish / save and unpublish buttons. Unfortunately I can only disable all fields, so an author isn't able to edit a published page and save a new version as a draft.
Do I need a custom "saveDraft"- and "publishButton"?
There is a "readVersions" access control rule. Would it usefull to add more rules?
Yeah it seems you need to
👍 just implemented the custom buttons a few weeks ago and it works well
can you share example code?
@691568994246983690Sure. There is a lot of custom logic in our app, but the important one is the following:
add a custom publish button to the collection
// collection config
admin: {
components: {
edit: {
PublishButton: CustomPublishButton,
},
},
}
just disable the button by yourself if the user role doesn't match
// custom publish button
if (atLeastRole(user.role, "editor")) {
return (
<props.DefaultButton
canPublish={true}
label={publishButtonText}
disabled={props.disabled}
publish={props.publish}
/>
);
}
Hi
@691568994246983690, what is in atLeastRole
trying do something similar based on roles
I defined an array with roles. Each user can have only one role. Here is the code:
export type Role = (typeof roles)[number];
export const roles = ["author", "editor", "admin"] as const;
export const atLeastRole = (role: Role, atLeast: Role) => {
return roles.indexOf(role) >= roles.indexOf(atLeast);
};
import * as React from 'react';
import { CustomPublishButtonType } from 'payload/types';
import { checkRole } from '../../collections/Users/checkRole';
// import { admins } from '../../access/admins';
// import { adminsOrHR } from '../../access/adminsOrHR2';
import { Access } from "payload/config";
export type Role = (typeof roles)[number];
export const roles = ["hr", "academic-staff",'admissions','student-service', "admin"] as const;
export const atLeastRole = (role: Role, atLeast: Role) => {
return roles.indexOf(role) >= roles.indexOf(atLeast);
};
export const ConditionalPublish: CustomPublishButtonType = ({
DefaultButton,
disabled,
label,
publish,
}) => {
if (atLeastRole(user.role, "hr")) {
return <DefaultButton canPublish={false} label={label} disabled={disabled} publish={publish} />
}
if (atLeastRole(user.role, "admin")) {
return <DefaultButton canPublish={true} label={label} disabled={disabled} publish={publish} />
}
}
I am making a publish button with custom access based on roles.
where user.role comes from? do you import it from access config?
export const ConditionalPublish: CustomPublishButtonType = ({
DefaultButton,
disabled,
label,
publish,
}) => {
const admins = ({ req: { user }}) => {
if (user && checkRole(['admin'], user)) {
return true
}
return false
}
if (admins({ req: { user: ['admin'] } })) {
return <DefaultButton canPublish={true} label={label} disabled={disabled} publish={publish} />;
} else {
return <DefaultButton canPublish={false} label={label} disabled={true} publish={publish} />;
}
}
import type { User } from '../../payload-types';
import { useAuth } from 'payload/components/utilities'
export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
DefaultButton,
disabled,
label,
saveDraft,
}) => {
const { user } = useAuth<User>()
if (user && checkRole(['admin'], user)) {
return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
}
if (user && checkRole(['hr'], user)) {
return <DefaultButton label={'Send to Approve'} disabled={disabled} saveDraft={saveDraft} />
}
}
This also have no desired result
Can you please take a look what I am doing wrong
Actually the user role is a select field in my users collection. To get the user in this button component, I use the
useAuth
hook.
const auth = useAuth();
const user = auth.user;
Since I conditionally render the publish button I always pass
canPublish={true}
to it.
Oh I see that your second example is for the draft button. This looks fine. Probably you should return null in all other cases?
Star
Discord
online
Get dedicated engineering support directly from the Payload team.