GH-2812 Hide delete template and edit template icons unless user has permission (#2818)

* hide delete template and edit template icons unless user has permission

* fix jest tests
This commit is contained in:
Doug Lauder 2022-04-15 12:59:26 -04:00 committed by GitHub
parent ebf02366b4
commit 554453c9e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 139 additions and 60 deletions

View file

@ -15,6 +15,7 @@ import {MemoryRouter, Router} from 'react-router-dom'
import Mutator from '../../mutator'
import {Utils} from '../../utils'
import {Team} from '../../store/teams'
import {IUser} from '../../user'
import {mockDOM, mockStateStore, wrapDNDIntl} from '../../testUtils'
import BoardTemplateSelector from './boardTemplateSelector'
@ -47,6 +48,15 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
updateAt: 0,
modifiedBy: 'user-1',
}
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
email: '',
props: {},
create_at: 0,
update_at: 0,
is_bot: false
}
const template1Title = 'Template 1'
const globalTemplateTitle = 'Template Global'
const boardTitle = 'Board 1'
@ -59,9 +69,8 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
current: team1,
},
users: {
me: {
id: 'user_id_1',
},
me,
boardUsers: [me],
},
boards: {
boards: [
@ -88,6 +97,14 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
dateDisplayPropertyId: 'id-5',
},
],
membersInBoards: {
['1']: {userId: me.id, schemeAdmin: true},
['2']: {userId: me.id, schemeAdmin: true},
},
myBoardMemberships: {
['1']: {userId: me.id, schemeAdmin: true},
['2']: {userId: me.id, schemeAdmin: true},
},
cards: [],
views: [],
},

View file

@ -3,9 +3,14 @@
import {render, within, act, waitFor} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'
import {MockStoreEnhanced} from 'redux-mock-store'
import {Provider as ReduxProvider} from 'react-redux'
import {Board, IPropertyTemplate} from '../../blocks/board'
import {wrapDNDIntl} from '../../testUtils'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'
import {IUser} from '../../user'
import {Team} from '../../store/teams'
import BoardTemplateSelectorItem from './boardTemplateSelectorItem'
@ -42,6 +47,14 @@ jest.mock('../../utils')
jest.mock('../../mutator')
describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
const team1: Team = {
id: 'team-1',
title: 'Team 1',
signupToken: '',
updateAt: 0,
modifiedBy: 'user-1',
}
const template: Board = {
id: '1',
teamId: 'team-1',
@ -80,12 +93,36 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
properties: {},
}
const me: IUser = {
id: 'user-id-1',
username: 'username_1',
email: '',
props: {},
create_at: 0,
update_at: 0,
is_bot: false
}
let store:MockStoreEnhanced<unknown, unknown>
beforeEach(() => {
jest.clearAllMocks()
const state = {
teams: {
current: team1,
},
boards: {
current: '1',
myBoardMemberships: {
['1']: {userId: me.id, schemeAdmin: true},
},
}
}
store = mockStateStore([], state)
})
test('should match snapshot', async () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={false}
template={template}
@ -93,6 +130,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={jest.fn()}
onEdit={jest.fn()}
/>
</ReduxProvider>
,
))
expect(container).toMatchSnapshot()
@ -100,6 +138,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
test('should match snapshot when active', async () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={true}
template={template}
@ -107,6 +146,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={jest.fn()}
onEdit={jest.fn()}
/>
</ReduxProvider>
,
))
expect(container).toMatchSnapshot()
@ -114,6 +154,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
test('should match snapshot with global template', async () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={false}
template={globalTemplate}
@ -121,6 +162,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={jest.fn()}
onEdit={jest.fn()}
/>
</ReduxProvider>
,
))
expect(container).toMatchSnapshot()
@ -131,6 +173,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
const onDelete = jest.fn()
const onEdit = jest.fn()
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={false}
template={template}
@ -138,6 +181,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={onDelete}
onEdit={onEdit}
/>
</ReduxProvider>
,
))
userEvent.click(container.querySelector('.BoardTemplateSelectorItem')!)
@ -152,6 +196,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
const onDelete = jest.fn()
const onEdit = jest.fn()
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={false}
template={template}
@ -159,6 +204,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={onDelete}
onEdit={onEdit}
/>
</ReduxProvider>
,
))
userEvent.click(container.querySelector('.BoardTemplateSelectorItem .EditIcon')!)
@ -176,6 +222,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
const root = document.createElement('div')
root.setAttribute('id', 'focalboard-root-portal')
render(wrapDNDIntl(
<ReduxProvider store={store}>
<BoardTemplateSelectorItem
isActive={false}
template={template}
@ -183,6 +230,7 @@ describe('components/boardTemplateSelector/boardTemplateSelectorItem', () => {
onDelete={onDelete}
onEdit={onEdit}
/>
</ReduxProvider>
,
), {container: document.body.appendChild(root)})
act(() => {

View file

@ -9,8 +9,10 @@ import DeleteIcon from '../../widgets/icons/delete'
import EditIcon from '../../widgets/icons/edit'
import DeleteBoardDialog from '../sidebar/deleteBoardDialog'
import BoardPermissionGate from '../permissions/boardPermissionGate'
import './boardTemplateSelectorItem.scss'
import {Constants} from "../../constants"
import {Constants, Permission} from "../../constants"
type Props = {
isActive: boolean
@ -43,6 +45,11 @@ const BoardTemplateSelectorItem = (props: Props) => {
{/* don't show template menu options for default templates */}
{template.teamId !== Constants.globalTeamId &&
<div className='actions'>
<BoardPermissionGate
boardId={template.id}
teamId={template.teamId}
permissions={[Permission.DeleteBoard]}
>
<IconButton
icon={<DeleteIcon/>}
title={intl.formatMessage({id: 'BoardTemplateSelector.delete-template', defaultMessage: 'Delete'})}
@ -51,11 +58,18 @@ const BoardTemplateSelectorItem = (props: Props) => {
setDeleteOpen(true)
}}
/>
</BoardPermissionGate>
<BoardPermissionGate
boardId={template.id}
teamId={template.teamId}
permissions={[Permission.ManageBoardCards, Permission.ManageBoardProperties]}
>
<IconButton
icon={<EditIcon/>}
title={intl.formatMessage({id: 'BoardTemplateSelector.edit-template', defaultMessage: 'Edit'})}
onClick={onEditHandler}
/>
</BoardPermissionGate>
</div>}
{deleteOpen &&
<DeleteBoardDialog