Only allow viewer role in temaPermissionRow for templates (#3672)

* Only allow viewer role in temaPermissionRow for templates

* set type

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-08-12 19:15:45 +02:00 committed by GitHub
parent 3a9212b17a
commit 724c036c8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 656 additions and 15 deletions

View file

@ -0,0 +1,485 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`src/components/shareBoard/teamPermissionsRow should match snapshot 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<div
class="ml-3"
>
<strong>
Everyone at Test Team Team
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
None
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div>
<div
aria-label="Editor"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Editor
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Commenter"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Commenter
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Viewer
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="None"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
<div
class="menu-name"
>
None
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Cancel
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`src/components/shareBoard/teamPermissionsRow should match snapshot in plugin mode 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<i
class="CompassIcon icon-mattermost user-item__img"
/>
<div
class="ml-3"
>
<strong>
Everyone at Test Team Team
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
None
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div>
<div
aria-label="Editor"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Editor
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Commenter"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Commenter
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Viewer
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="None"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
<div
class="menu-name"
>
None
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Cancel
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`src/components/shareBoard/teamPermissionsRow should match snapshot in template 1`] = `
<div>
<div
class="user-item"
>
<div
class="user-item__content"
>
<i
class="CompassIcon icon-mattermost user-item__img"
/>
<div
class="ml-3"
>
<strong>
Everyone at Test Team Team
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
None
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
<div
class="Menu noselect left "
>
<div
class="menu-contents"
>
<div
class="menu-options"
>
<div />
<div />
<div>
<div
aria-label="Viewer"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Viewer
</div>
<div
class="noicon"
/>
</div>
</div>
<div>
<div
aria-label="None"
class="MenuOption TextOption menu-option"
role="button"
>
<div
class="d-flex menu-option__check"
>
<svg
class="CheckIcon Icon"
viewBox="0 0 100 100"
xmlns="http://www.w3.org/2000/svg"
>
<polyline
points="20,60 40,80 80,40"
/>
</svg>
</div>
<div
class="menu-name"
>
None
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
<div
class="menu-spacer hideOnWidescreen"
/>
<div
class="menu-options hideOnWidescreen"
>
<div
aria-label="Cancel"
class="MenuOption TextOption menu-option menu-cancel"
role="button"
>
<div
class="d-flex"
>
<div
class="noicon"
/>
</div>
<div
class="menu-name"
>
Cancel
</div>
<div
class="noicon"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View file

@ -0,0 +1,150 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {act, render} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import {Provider as ReduxProvider} from 'react-redux'
import thunk from 'redux-thunk'
import React from 'react'
import {MemoryRouter} from 'react-router'
import {mocked} from 'jest-mock'
import {IUser} from '../../user'
import {TestBlockFactory} from '../../test/testBlockFactory'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'
import {Utils} from '../../utils'
import TeamPermissionsRow from './teamPermissionsRow'
jest.useFakeTimers()
const boardId = '1'
jest.mock('../../utils')
const mockedUtils = mocked(Utils, true)
const board = TestBlockFactory.createBoard()
board.id = boardId
board.teamId = 'team-id'
board.channelId = 'channel_1'
describe('src/components/shareBoard/teamPermissionsRow', () => {
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
email: '',
nickname: '',
firstname: '',
lastname: '',
props: {},
create_at: 0,
update_at: 0,
is_bot: false,
roles: 'system_user',
}
const state = {
teams: {
current: {id: 'team-id', title: 'Test Team'},
},
users: {
me,
boardUsers: [me],
blockSubscriptions: [],
},
boards: {
current: board.id,
boards: {
[board.id]: board,
},
templates: [],
membersInBoards: {
[board.id]: {},
},
myBoardMemberships: {
[board.id]: {userId: me.id, schemeAdmin: true},
},
},
}
beforeEach(() => {
jest.clearAllMocks()
})
test('should match snapshot', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(false)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<TeamPermissionsRow/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
test('should match snapshot in plugin mode', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const store = mockStateStore([thunk], state)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<TeamPermissionsRow/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
test('should match snapshot in template', async () => {
let container: Element | undefined
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
const testState = {
...state,
boards: {
...state.boards,
boards: {},
templates: {
[board.id]: {...board, isTemplate: true},
}
}
}
const store = mockStateStore([thunk], testState)
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<TeamPermissionsRow/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
const buttonElement = container?.querySelector('.user-item__button')
expect(buttonElement).toBeDefined()
userEvent.click(buttonElement!)
expect(container).toMatchSnapshot()
})
})

View file

@ -42,7 +42,11 @@ const TeamPermissionsRow = (): JSX.Element => {
if (board.type === BoardTypeOpen && board.minimumRole === 'admin') {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
}else if (board.type === BoardTypeOpen && board.minimumRole === 'editor') {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
if (board.isTemplate) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
} else {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
}
}else if (board.type === BoardTypeOpen && board.minimumRole === 'commenter') {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
}else if (board.type === BoardTypeOpen && board.minimumRole === 'viewer') {
@ -71,20 +75,22 @@ const TeamPermissionsRow = (): JSX.Element => {
/>
</button>
<Menu position='left'>
<Menu.Text
id='Editor'
check={board.minimumRole === '' || board.minimumRole === 'editor' }
icon={board.type === BoardTypeOpen && board.minimumRole === 'editor' ? <CheckIcon/> : null}
name={intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})}
onClick={() => updateBoardType(board, BoardTypeOpen, 'editor')}
/>
<Menu.Text
id='Commenter'
check={board.minimumRole === 'commenter'}
icon={board.type === BoardTypeOpen && board.minimumRole === 'commenter' ? <CheckIcon/> : null}
name={intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})}
onClick={() => updateBoardType(board, BoardTypeOpen, 'commenter')}
/>
{!board.isTemplate &&
<Menu.Text
id='Editor'
check={board.minimumRole === '' || board.minimumRole === 'editor' }
icon={board.type === BoardTypeOpen && board.minimumRole === 'editor' ? <CheckIcon/> : null}
name={intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})}
onClick={() => updateBoardType(board, BoardTypeOpen, 'editor')}
/>}
{!board.isTemplate &&
<Menu.Text
id='Commenter'
check={board.minimumRole === 'commenter'}
icon={board.type === BoardTypeOpen && board.minimumRole === 'commenter' ? <CheckIcon/> : null}
name={intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})}
onClick={() => updateBoardType(board, BoardTypeOpen, 'commenter')}
/>}
<Menu.Text
id='Viewer'
check={board.minimumRole === 'viewer'}