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:
Jesús Espino 2022-09-15 21:48:06 +02:00 committed by GitHub
parent dfa9d8f452
commit 03d1b584ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 59 additions and 43 deletions

View file

@ -55,6 +55,9 @@ describe('components/rhsChannelBoardItem', () => {
myBoardMemberships: {
[board.id]: {userId: 'user_id_1', schemeAdmin: true},
},
boards: {
[board.id]: board
}
}
}
board.updateAt = 1657311058157

View file

@ -13,6 +13,8 @@ const BoardTypePrivate = 'P'
const boardTypes = [BoardTypeOpen, BoardTypePrivate]
type BoardTypes = typeof boardTypes[number]
type MemberRole = ''|'viewer'|'commenter'|'editor'|'admin'
type Board = {
id: string
teamId: string
@ -55,6 +57,7 @@ type BoardMember = {
boardId: string
userId: string
roles?: string
minimumRole: MemberRole
schemeAdmin: boolean
schemeEditor: boolean
schemeCommenter: boolean

View file

@ -122,6 +122,9 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
myBoardMemberships: {
1: {userId: me.id, schemeAdmin: true},
},
templates: {
[template.id]: template,
},
},
}
store = mockStateStore([], state)

View file

@ -57,12 +57,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot 1`]
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
class="noicon"
/>
</div>
<div
class="menu-option__content"
@ -310,12 +306,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot in p
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
class="noicon"
/>
</div>
<div
class="menu-option__content"
@ -563,12 +555,8 @@ exports[`src/components/shareBoard/userPermissionsRow should match snapshot in t
class="d-flex menu-option__check"
>
<div
class="menu-option__icon"
>
<div
class="empty-icon"
/>
</div>
class="noicon"
/>
</div>
<div
class="menu-option__content"

View file

@ -103,7 +103,7 @@ const TeamPermissionsRow = (): JSX.Element => {
check={true}
icon={board.type === BoardTypePrivate ? <CheckIcon/> : <div className='empty-icon'/>}
name={intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})}
onClick={() => updateBoardType(board, BoardTypePrivate, 'editor')}
onClick={() => updateBoardType(board, BoardTypePrivate, '')}
/>
</Menu>
</MenuWrapper>

View file

@ -36,9 +36,9 @@ const UserPermissionsRow = (props: Props): JSX.Element => {
let currentRole = 'Viewer'
if (member.schemeAdmin) {
currentRole = 'Admin'
} else if (member.schemeEditor) {
} else if (member.schemeEditor || member.minimumRole === 'editor') {
currentRole = 'Editor'
} else if (member.schemeCommenter) {
} else if (member.schemeCommenter || member.minimumRole === 'commenter') {
currentRole = 'Commenter'
}
@ -69,14 +69,15 @@ const UserPermissionsRow = (props: Props): JSX.Element => {
/>
</button>
<Menu position='left'>
<Menu.Text
id='Viewer'
check={true}
icon={currentRole === 'Viewer' ? <CheckIcon/> : <div className='empty-icon'/>}
name={intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})}
onClick={() => props.onUpdateBoardMember(member, 'Viewer')}
/>
{!board.isTemplate &&
{(board.minimumRole === 'viewer' || board.minimumRole === '') &&
<Menu.Text
id='Viewer'
check={true}
icon={currentRole === 'Viewer' ? <CheckIcon/> : null}
name={intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})}
onClick={() => props.onUpdateBoardMember(member, 'Viewer')}
/>}
{!board.isTemplate && (board.minimumRole === '' || board.minimumRole === 'commenter' || board.minimumRole === 'viewer') &&
<Menu.Text
id='Commenter'
check={true}

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import {useAppSelector} from '../store/hooks'
import {getMyBoardMembership, getCurrentBoardId} from '../store/boards'
import {getMyBoardMembership, getCurrentBoardId, getBoard} from '../store/boards'
import {getCurrentTeam} from '../store/teams'
import {Utils} from '../utils'
import {Permission} from '../constants'
@ -13,6 +13,11 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
}
const member = useAppSelector(getMyBoardMembership(boardId))
const board = useAppSelector(getBoard(boardId))
if (!board) {
return false
}
if (!member) {
return false
@ -31,13 +36,13 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
if (adminPermissions.includes(permission) && member.schemeAdmin) {
return true
}
if (editorPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor)) {
if (editorPermissions.includes(permission) && (member.schemeAdmin || member.schemeEditor || board.minimumRole === 'editor')) {
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
}
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
}
}

View file

@ -121,7 +121,15 @@ const BoardPage = (props: Props): JSX.Element => {
const incrementalBoardUpdate = (_: WSClient, boards: Board[]) => {
// 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 activeBoard = teamBoards.find((b: Board) => b.id === activeBoardId)
dispatch(updateBoards(teamBoards))
if (activeBoard) {
dispatch(fetchBoardMembers({
teamId,
boardId: activeBoardId,
}))
}
}
const incrementalBoardMemberUpdate = (_: WSClient, members: BoardMember[]) => {
@ -157,7 +165,7 @@ const BoardPage = (props: Props): JSX.Element => {
wsClient.removeOnChange(incrementalBoardMemberUpdate, 'boardMembers')
wsClient.removeOnReconnect(() => dispatch(loadAction(match.params.boardId)))
}
}, [me?.id])
}, [me?.id, activeBoardId])
const loadOrJoinBoard = useCallback(async (userId: string, boardTeamId: string, boardId: string) => {
// and fetch its data

View file

@ -108,14 +108,6 @@ const Person = (props: PropertyProps): JSX.Element => {
mutator.updateBoardMember(newMember, {...newMember, schemeAdmin: false, schemeEditor: true, schemeCommenter: true, schemeViewer: true})
}, [board, card, propertyTemplate])
if (readOnly) {
return (
<div className={`Person ${props.property.valueClassName(true)}`}>
{me ? formatOptionLabel(me) : propertyValue}
</div>
)
}
const boardUsers = useAppSelector<IUser[]>(getBoardUsersList)
const allowAddUsers = useHasPermissions(board.teamId, board.id, [Permission.ManageBoardRoles])
@ -144,6 +136,14 @@ const Person = (props: PropertyProps): JSX.Element => {
]
}, [boardUsers, allowAddUsers, boardUsersById])
if (readOnly) {
return (
<div className={`Person ${props.property.valueClassName(true)}`}>
{me ? formatOptionLabel(me) : propertyValue}
</div>
)
}
return (
<>
{confirmAddUser &&

View file

@ -234,7 +234,12 @@ export const getSortedTemplates = createSelector(
export function getBoard(boardId: string): (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
}
}