mirror of
https://github.com/plankanban/planka.git
synced 2025-07-24 15:49:46 +02:00
fix: Hide label actions based on role
This commit is contained in:
parent
0764ca76d3
commit
529309553c
6 changed files with 70 additions and 39 deletions
|
@ -14,6 +14,7 @@ const BoardActions = React.memo(
|
||||||
filterUsers,
|
filterUsers,
|
||||||
filterLabels,
|
filterLabels,
|
||||||
allUsers,
|
allUsers,
|
||||||
|
canEdit,
|
||||||
canEditMemberships,
|
canEditMemberships,
|
||||||
onMembershipCreate,
|
onMembershipCreate,
|
||||||
onMembershipUpdate,
|
onMembershipUpdate,
|
||||||
|
@ -45,6 +46,7 @@ const BoardActions = React.memo(
|
||||||
labels={filterLabels}
|
labels={filterLabels}
|
||||||
allBoardMemberships={memberships}
|
allBoardMemberships={memberships}
|
||||||
allLabels={labels}
|
allLabels={labels}
|
||||||
|
canEdit={canEdit}
|
||||||
onUserAdd={onUserToFilterAdd}
|
onUserAdd={onUserToFilterAdd}
|
||||||
onUserRemove={onUserFromFilterRemove}
|
onUserRemove={onUserFromFilterRemove}
|
||||||
onLabelAdd={onLabelToFilterAdd}
|
onLabelAdd={onLabelToFilterAdd}
|
||||||
|
@ -67,6 +69,7 @@ BoardActions.propTypes = {
|
||||||
filterLabels: PropTypes.array.isRequired,
|
filterLabels: PropTypes.array.isRequired,
|
||||||
allUsers: PropTypes.array.isRequired,
|
allUsers: PropTypes.array.isRequired,
|
||||||
/* eslint-enable react/forbid-prop-types */
|
/* eslint-enable react/forbid-prop-types */
|
||||||
|
canEdit: PropTypes.bool.isRequired,
|
||||||
canEditMemberships: PropTypes.bool.isRequired,
|
canEditMemberships: PropTypes.bool.isRequired,
|
||||||
onMembershipCreate: PropTypes.func.isRequired,
|
onMembershipCreate: PropTypes.func.isRequired,
|
||||||
onMembershipUpdate: PropTypes.func.isRequired,
|
onMembershipUpdate: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -15,6 +15,7 @@ const Filters = React.memo(
|
||||||
labels,
|
labels,
|
||||||
allBoardMemberships,
|
allBoardMemberships,
|
||||||
allLabels,
|
allLabels,
|
||||||
|
canEdit,
|
||||||
onUserAdd,
|
onUserAdd,
|
||||||
onUserRemove,
|
onUserRemove,
|
||||||
onLabelAdd,
|
onLabelAdd,
|
||||||
|
@ -74,6 +75,7 @@ const Filters = React.memo(
|
||||||
title={t('common.filterByLabels', {
|
title={t('common.filterByLabels', {
|
||||||
context: 'title',
|
context: 'title',
|
||||||
})}
|
})}
|
||||||
|
canEdit={canEdit}
|
||||||
onSelect={onLabelAdd}
|
onSelect={onLabelAdd}
|
||||||
onDeselect={onLabelRemove}
|
onDeselect={onLabelRemove}
|
||||||
onCreate={onLabelCreate}
|
onCreate={onLabelCreate}
|
||||||
|
@ -108,6 +110,7 @@ Filters.propTypes = {
|
||||||
allBoardMemberships: PropTypes.array.isRequired,
|
allBoardMemberships: PropTypes.array.isRequired,
|
||||||
allLabels: PropTypes.array.isRequired,
|
allLabels: PropTypes.array.isRequired,
|
||||||
/* eslint-enable react/forbid-prop-types */
|
/* eslint-enable react/forbid-prop-types */
|
||||||
|
canEdit: PropTypes.bool.isRequired,
|
||||||
onUserAdd: PropTypes.func.isRequired,
|
onUserAdd: PropTypes.func.isRequired,
|
||||||
onUserRemove: PropTypes.func.isRequired,
|
onUserRemove: PropTypes.func.isRequired,
|
||||||
onLabelAdd: PropTypes.func.isRequired,
|
onLabelAdd: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -8,45 +8,51 @@ import { Button } from 'semantic-ui-react';
|
||||||
import styles from './Item.module.scss';
|
import styles from './Item.module.scss';
|
||||||
import globalStyles from '../../styles.module.scss';
|
import globalStyles from '../../styles.module.scss';
|
||||||
|
|
||||||
const Item = React.memo(({ name, color, isPersisted, isActive, onSelect, onDeselect, onEdit }) => {
|
const Item = React.memo(
|
||||||
const handleToggleClick = useCallback(() => {
|
({ name, color, isPersisted, isActive, canEdit, onSelect, onDeselect, onEdit }) => {
|
||||||
if (isActive) {
|
const handleToggleClick = useCallback(() => {
|
||||||
onDeselect();
|
if (isActive) {
|
||||||
} else {
|
onDeselect();
|
||||||
onSelect();
|
} else {
|
||||||
}
|
onSelect();
|
||||||
}, [isActive, onSelect, onDeselect]);
|
}
|
||||||
|
}, [isActive, onSelect, onDeselect]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<Button
|
<Button
|
||||||
fluid
|
fluid
|
||||||
content={name}
|
content={name}
|
||||||
active={isActive}
|
active={isActive}
|
||||||
disabled={!isPersisted}
|
disabled={!isPersisted}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
styles.labelButton,
|
styles.labelButton,
|
||||||
isActive && styles.labelButtonActive,
|
isActive && styles.labelButtonActive,
|
||||||
globalStyles[`background${upperFirst(camelCase(color))}`],
|
globalStyles[`background${upperFirst(camelCase(color))}`],
|
||||||
|
)}
|
||||||
|
onClick={handleToggleClick}
|
||||||
|
/>
|
||||||
|
{canEdit && (
|
||||||
|
<Button
|
||||||
|
icon="pencil"
|
||||||
|
size="small"
|
||||||
|
floated="right"
|
||||||
|
disabled={!isPersisted}
|
||||||
|
className={styles.editButton}
|
||||||
|
onClick={onEdit}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
onClick={handleToggleClick}
|
</div>
|
||||||
/>
|
);
|
||||||
<Button
|
},
|
||||||
icon="pencil"
|
);
|
||||||
size="small"
|
|
||||||
disabled={!isPersisted}
|
|
||||||
className={styles.editButton}
|
|
||||||
onClick={onEdit}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Item.propTypes = {
|
Item.propTypes = {
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
color: PropTypes.string.isRequired,
|
color: PropTypes.string.isRequired,
|
||||||
isPersisted: PropTypes.bool.isRequired,
|
isPersisted: PropTypes.bool.isRequired,
|
||||||
isActive: PropTypes.bool.isRequired,
|
isActive: PropTypes.bool.isRequired,
|
||||||
|
canEdit: PropTypes.bool.isRequired,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
onDeselect: PropTypes.func.isRequired,
|
onDeselect: PropTypes.func.isRequired,
|
||||||
onEdit: PropTypes.func.isRequired,
|
onEdit: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 0;
|
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
|
||||||
|
@ -18,6 +17,7 @@
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
margin-right: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 8px 32px 8px 10px;
|
padding: 8px 32px 8px 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -18,7 +18,18 @@ const StepTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LabelsStep = React.memo(
|
const LabelsStep = React.memo(
|
||||||
({ items, currentIds, title, onSelect, onDeselect, onCreate, onUpdate, onDelete, onBack }) => {
|
({
|
||||||
|
items,
|
||||||
|
currentIds,
|
||||||
|
title,
|
||||||
|
canEdit,
|
||||||
|
onSelect,
|
||||||
|
onDeselect,
|
||||||
|
onCreate,
|
||||||
|
onUpdate,
|
||||||
|
onDelete,
|
||||||
|
onBack,
|
||||||
|
}) => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const [step, openStep, handleBack] = useSteps();
|
const [step, openStep, handleBack] = useSteps();
|
||||||
const [search, handleSearchChange] = useField('');
|
const [search, handleSearchChange] = useField('');
|
||||||
|
@ -140,6 +151,7 @@ const LabelsStep = React.memo(
|
||||||
color={item.color}
|
color={item.color}
|
||||||
isPersisted={item.isPersisted}
|
isPersisted={item.isPersisted}
|
||||||
isActive={currentIds.includes(item.id)}
|
isActive={currentIds.includes(item.id)}
|
||||||
|
canEdit={canEdit}
|
||||||
onSelect={() => handleSelect(item.id)}
|
onSelect={() => handleSelect(item.id)}
|
||||||
onDeselect={() => handleDeselect(item.id)}
|
onDeselect={() => handleDeselect(item.id)}
|
||||||
onEdit={() => handleEdit(item.id)}
|
onEdit={() => handleEdit(item.id)}
|
||||||
|
@ -147,12 +159,14 @@ const LabelsStep = React.memo(
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Button
|
{canEdit && (
|
||||||
fluid
|
<Button
|
||||||
content={t('action.createNewLabel')}
|
fluid
|
||||||
className={styles.addButton}
|
content={t('action.createNewLabel')}
|
||||||
onClick={handleAddClick}
|
className={styles.addButton}
|
||||||
/>
|
onClick={handleAddClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Popup.Content>
|
</Popup.Content>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -165,6 +179,7 @@ LabelsStep.propTypes = {
|
||||||
currentIds: PropTypes.array.isRequired,
|
currentIds: PropTypes.array.isRequired,
|
||||||
/* eslint-enable react/forbid-prop-types */
|
/* eslint-enable react/forbid-prop-types */
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
canEdit: PropTypes.bool,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
onDeselect: PropTypes.func.isRequired,
|
onDeselect: PropTypes.func.isRequired,
|
||||||
onCreate: PropTypes.func.isRequired,
|
onCreate: PropTypes.func.isRequired,
|
||||||
|
@ -175,6 +190,7 @@ LabelsStep.propTypes = {
|
||||||
|
|
||||||
LabelsStep.defaultProps = {
|
LabelsStep.defaultProps = {
|
||||||
title: 'common.labels',
|
title: 'common.labels',
|
||||||
|
canEdit: true,
|
||||||
onBack: undefined,
|
onBack: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import selectors from '../selectors';
|
import selectors from '../selectors';
|
||||||
import entryActions from '../entry-actions';
|
import entryActions from '../entry-actions';
|
||||||
|
import { BoardMembershipRoles } from '../constants/Enums';
|
||||||
import BoardActions from '../components/BoardActions';
|
import BoardActions from '../components/BoardActions';
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
|
@ -12,6 +13,7 @@ const mapStateToProps = (state) => {
|
||||||
const labels = selectors.selectLabelsForCurrentBoard(state);
|
const labels = selectors.selectLabelsForCurrentBoard(state);
|
||||||
const filterUsers = selectors.selectFilterUsersForCurrentBoard(state);
|
const filterUsers = selectors.selectFilterUsersForCurrentBoard(state);
|
||||||
const filterLabels = selectors.selectFilterLabelsForCurrentBoard(state);
|
const filterLabels = selectors.selectFilterLabelsForCurrentBoard(state);
|
||||||
|
const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
memberships,
|
memberships,
|
||||||
|
@ -19,6 +21,7 @@ const mapStateToProps = (state) => {
|
||||||
filterUsers,
|
filterUsers,
|
||||||
filterLabels,
|
filterLabels,
|
||||||
allUsers,
|
allUsers,
|
||||||
|
canEdit: !!currentUserMembership && currentUserMembership.role === BoardMembershipRoles.EDITOR,
|
||||||
canEditMemberships: isCurrentUserManager,
|
canEditMemberships: isCurrentUserManager,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue