Fixing minimum board roles behavior (#3836)
* Fixing minimum board roles behavior * fix unit tests * fix lint issues * update snapshot * attempt fix for unit test Co-authored-by: Scott Bishel <scott.bishel@mattermost.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
parent
dfa9d8f452
commit
03d1b584ca
10 changed files with 59 additions and 43 deletions
|
@ -55,6 +55,9 @@ describe('components/rhsChannelBoardItem', () => {
|
||||||
myBoardMemberships: {
|
myBoardMemberships: {
|
||||||
[board.id]: {userId: 'user_id_1', schemeAdmin: true},
|
[board.id]: {userId: 'user_id_1', schemeAdmin: true},
|
||||||
},
|
},
|
||||||
|
boards: {
|
||||||
|
[board.id]: board
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
board.updateAt = 1657311058157
|
board.updateAt = 1657311058157
|
||||||
|
|
|
@ -13,6 +13,8 @@ const BoardTypePrivate = 'P'
|
||||||
const boardTypes = [BoardTypeOpen, BoardTypePrivate]
|
const boardTypes = [BoardTypeOpen, BoardTypePrivate]
|
||||||
type BoardTypes = typeof boardTypes[number]
|
type BoardTypes = typeof boardTypes[number]
|
||||||
|
|
||||||
|
type MemberRole = ''|'viewer'|'commenter'|'editor'|'admin'
|
||||||
|
|
||||||
type Board = {
|
type Board = {
|
||||||
id: string
|
id: string
|
||||||
teamId: string
|
teamId: string
|
||||||
|
@ -55,6 +57,7 @@ type BoardMember = {
|
||||||
boardId: string
|
boardId: string
|
||||||
userId: string
|
userId: string
|
||||||
roles?: string
|
roles?: string
|
||||||
|
minimumRole: MemberRole
|
||||||
schemeAdmin: boolean
|
schemeAdmin: boolean
|
||||||
schemeEditor: boolean
|
schemeEditor: boolean
|
||||||
schemeCommenter: boolean
|
schemeCommenter: boolean
|
||||||
|
|
|
@ -122,6 +122,9 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
|
||||||
myBoardMemberships: {
|
myBoardMemberships: {
|
||||||
1: {userId: me.id, schemeAdmin: true},
|
1: {userId: me.id, schemeAdmin: true},
|
||||||
},
|
},
|
||||||
|
templates: {
|
||||||
|
[template.id]: template,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
store = mockStateStore([], state)
|
store = mockStateStore([], state)
|
||||||
|
|
|
@ -57,12 +57,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot 1`]
|
||||||
class="d-flex menu-option__check"
|
class="d-flex menu-option__check"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="menu-option__icon"
|
class="noicon"
|
||||||
>
|
/>
|
||||||
<div
|
|
||||||
class="empty-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="menu-option__content"
|
class="menu-option__content"
|
||||||
|
@ -310,12 +306,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot in p
|
||||||
class="d-flex menu-option__check"
|
class="d-flex menu-option__check"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="menu-option__icon"
|
class="noicon"
|
||||||
>
|
/>
|
||||||
<div
|
|
||||||
class="empty-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="menu-option__content"
|
class="menu-option__content"
|
||||||
|
@ -563,12 +555,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot in t
|
||||||
class="d-flex menu-option__check"
|
class="d-flex menu-option__check"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="menu-option__icon"
|
class="noicon"
|
||||||
>
|
/>
|
||||||
<div
|
|
||||||
class="empty-icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="menu-option__content"
|
class="menu-option__content"
|
||||||
|
|
|
@ -103,7 +103,7 @@ const TeamPermissionsRow = (): JSX.Element => {
|
||||||
check={true}
|
check={true}
|
||||||
icon={board.type === BoardTypePrivate ? <CheckIcon/> : <div className='empty-icon'/>}
|
icon={board.type === BoardTypePrivate ? <CheckIcon/> : <div className='empty-icon'/>}
|
||||||
name={intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})}
|
name={intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})}
|
||||||
onClick={() => updateBoardType(board, BoardTypePrivate, 'editor')}
|
onClick={() => updateBoardType(board, BoardTypePrivate, '')}
|
||||||
/>
|
/>
|
||||||
</Menu>
|
</Menu>
|
||||||
</MenuWrapper>
|
</MenuWrapper>
|
||||||
|
|
|
@ -36,9 +36,9 @@ const UserPermissionsRow = (props: Props): JSX.Element => {
|
||||||
let currentRole = 'Viewer'
|
let currentRole = 'Viewer'
|
||||||
if (member.schemeAdmin) {
|
if (member.schemeAdmin) {
|
||||||
currentRole = 'Admin'
|
currentRole = 'Admin'
|
||||||
} else if (member.schemeEditor) {
|
} else if (member.schemeEditor || member.minimumRole === 'editor') {
|
||||||
currentRole = 'Editor'
|
currentRole = 'Editor'
|
||||||
} else if (member.schemeCommenter) {
|
} else if (member.schemeCommenter || member.minimumRole === 'commenter') {
|
||||||
currentRole = 'Commenter'
|
currentRole = 'Commenter'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,14 +69,15 @@ const UserPermissionsRow = (props: Props): JSX.Element => {
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<Menu position='left'>
|
<Menu position='left'>
|
||||||
<Menu.Text
|
{(board.minimumRole === 'viewer' || board.minimumRole === '') &&
|
||||||
id='Viewer'
|
<Menu.Text
|
||||||
check={true}
|
id='Viewer'
|
||||||
icon={currentRole === 'Viewer' ? <CheckIcon/> : <div className='empty-icon'/>}
|
check={true}
|
||||||
name={intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})}
|
icon={currentRole === 'Viewer' ? <CheckIcon/> : null}
|
||||||
onClick={() => props.onUpdateBoardMember(member, 'Viewer')}
|
name={intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})}
|
||||||
/>
|
onClick={() => props.onUpdateBoardMember(member, 'Viewer')}
|
||||||
{!board.isTemplate &&
|
/>}
|
||||||
|
{!board.isTemplate && (board.minimumRole === '' || board.minimumRole === 'commenter' || board.minimumRole === 'viewer') &&
|
||||||
<Menu.Text
|
<Menu.Text
|
||||||
id='Commenter'
|
id='Commenter'
|
||||||
check={true}
|
check={true}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {useAppSelector} from '../store/hooks'
|
import {useAppSelector} from '../store/hooks'
|
||||||
import {getMyBoardMembership, getCurrentBoardId} from '../store/boards'
|
import {getMyBoardMembership, getCurrentBoardId, getBoard} from '../store/boards'
|
||||||
import {getCurrentTeam} from '../store/teams'
|
import {getCurrentTeam} from '../store/teams'
|
||||||
import {Utils} from '../utils'
|
import {Utils} from '../utils'
|
||||||
import {Permission} from '../constants'
|
import {Permission} from '../constants'
|
||||||
|
@ -13,6 +13,11 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = useAppSelector(getMyBoardMembership(boardId))
|
const member = useAppSelector(getMyBoardMembership(boardId))
|
||||||
|
const board = useAppSelector(getBoard(boardId))
|
||||||
|
|
||||||
|
if (!board) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return false
|
return false
|
||||||
|
@ -31,13 +36,13 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
|
||||||
if (adminPermissions.includes(permission) && member.schemeAdmin) {
|
if (adminPermissions.includes(permission) && member.schemeAdmin) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (editorPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor)) {
|
if (editorPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || board.minimumRole === 'editor')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (commenterPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || member.schemeCommenter)) {
|
if (commenterPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || member.schemeCommenter || board.minimumRole === 'commenter')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (viewerPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || member.schemeCommenter || member.schemeViewer)) {
|
if (viewerPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || member.schemeCommenter || member.schemeViewer || board.minimumRole === 'viewer')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,15 @@ const BoardPage = (props: Props): JSX.Element => {
|
||||||
const incrementalBoardUpdate = (_: WSClient, boards: Board[]) => {
|
const incrementalBoardUpdate = (_: WSClient, boards: Board[]) => {
|
||||||
// only takes into account the entities that belong to the team or the user boards
|
// only takes into account the entities that belong to the team or the user boards
|
||||||
const teamBoards = boards.filter((b: Board) => b.teamId === Constants.globalTeamId || b.teamId === teamId)
|
const teamBoards = boards.filter((b: Board) => b.teamId === Constants.globalTeamId || b.teamId === teamId)
|
||||||
|
const activeBoard = teamBoards.find((b: Board) => b.id === activeBoardId)
|
||||||
dispatch(updateBoards(teamBoards))
|
dispatch(updateBoards(teamBoards))
|
||||||
|
|
||||||
|
if (activeBoard) {
|
||||||
|
dispatch(fetchBoardMembers({
|
||||||
|
teamId,
|
||||||
|
boardId: activeBoardId,
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const incrementalBoardMemberUpdate = (_: WSClient, members: BoardMember[]) => {
|
const incrementalBoardMemberUpdate = (_: WSClient, members: BoardMember[]) => {
|
||||||
|
@ -157,7 +165,7 @@ const BoardPage = (props: Props): JSX.Element => {
|
||||||
wsClient.removeOnChange(incrementalBoardMemberUpdate, 'boardMembers')
|
wsClient.removeOnChange(incrementalBoardMemberUpdate, 'boardMembers')
|
||||||
wsClient.removeOnReconnect(() => dispatch(loadAction(match.params.boardId)))
|
wsClient.removeOnReconnect(() => dispatch(loadAction(match.params.boardId)))
|
||||||
}
|
}
|
||||||
}, [me?.id])
|
}, [me?.id, activeBoardId])
|
||||||
|
|
||||||
const loadOrJoinBoard = useCallback(async (userId: string, boardTeamId: string, boardId: string) => {
|
const loadOrJoinBoard = useCallback(async (userId: string, boardTeamId: string, boardId: string) => {
|
||||||
// and fetch its data
|
// and fetch its data
|
||||||
|
|
|
@ -108,14 +108,6 @@ const Person = (props: PropertyProps): JSX.Element => {
|
||||||
mutator.updateBoardMember(newMember, {...newMember, schemeAdmin: false, schemeEditor: true, schemeCommenter: true, schemeViewer: true})
|
mutator.updateBoardMember(newMember, {...newMember, schemeAdmin: false, schemeEditor: true, schemeCommenter: true, schemeViewer: true})
|
||||||
}, [board, card, propertyTemplate])
|
}, [board, card, propertyTemplate])
|
||||||
|
|
||||||
if (readOnly) {
|
|
||||||
return (
|
|
||||||
<div className={`Person ${props.property.valueClassName(true)}`}>
|
|
||||||
{me ? formatOptionLabel(me) : propertyValue}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const boardUsers = useAppSelector<IUser[]>(getBoardUsersList)
|
const boardUsers = useAppSelector<IUser[]>(getBoardUsersList)
|
||||||
|
|
||||||
const allowAddUsers = useHasPermissions(board.teamId, board.id, [Permission.ManageBoardRoles])
|
const allowAddUsers = useHasPermissions(board.teamId, board.id, [Permission.ManageBoardRoles])
|
||||||
|
@ -144,6 +136,14 @@ const Person = (props: PropertyProps): JSX.Element => {
|
||||||
]
|
]
|
||||||
}, [boardUsers, allowAddUsers, boardUsersById])
|
}, [boardUsers, allowAddUsers, boardUsersById])
|
||||||
|
|
||||||
|
if (readOnly) {
|
||||||
|
return (
|
||||||
|
<div className={`Person ${props.property.valueClassName(true)}`}>
|
||||||
|
{me ? formatOptionLabel(me) : propertyValue}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{confirmAddUser &&
|
{confirmAddUser &&
|
||||||
|
|
|
@ -234,7 +234,12 @@ export const getSortedTemplates = createSelector(
|
||||||
|
|
||||||
export function getBoard(boardId: string): (state: RootState) => Board|null {
|
export function getBoard(boardId: string): (state: RootState) => Board|null {
|
||||||
return (state: RootState): Board|null => {
|
return (state: RootState): Board|null => {
|
||||||
return state.boards.boards[boardId] || state.boards.templates[boardId] || null
|
if (state.boards.boards && state.boards.boards[boardId]) {
|
||||||
|
return state.boards.boards[boardId]
|
||||||
|
} else if (state.boards.templates && state.boards.templates[boardId]) {
|
||||||
|
return state.boards.templates[boardId]
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue