mirror of
https://github.com/mattermost/focalboard.git
synced 2024-11-27 08:31:20 +02:00
Merge branch 'main' into weblate-focalboard-webapp
This commit is contained in:
commit
5ef504e584
@ -167,6 +167,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
|
||||
<CardActionsMenuIcon/>
|
||||
<CardActionsMenu
|
||||
cardId={card.id}
|
||||
boardId={card.boardId}
|
||||
onClickDelete={() => openConfirmationDialogBox(card)}
|
||||
onClickDuplicate={() => {
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
|
||||
|
@ -48,6 +48,7 @@ describe('components/cardActionsMenu', () => {
|
||||
<ReduxProvider store={store}>
|
||||
<CardActionsMenu
|
||||
cardId='123'
|
||||
boardId='345'
|
||||
onClickDelete={jest.fn()}
|
||||
/>
|
||||
</ReduxProvider>,
|
||||
@ -64,6 +65,7 @@ describe('components/cardActionsMenu', () => {
|
||||
<ReduxProvider store={store}>
|
||||
<CardActionsMenu
|
||||
cardId='123'
|
||||
boardId='345'
|
||||
onClickDelete={jest.fn()}
|
||||
onClickDuplicate={jest.fn()}
|
||||
/>
|
||||
@ -81,6 +83,7 @@ describe('components/cardActionsMenu', () => {
|
||||
<ReduxProvider store={store}>
|
||||
<CardActionsMenu
|
||||
cardId='123'
|
||||
boardId='345'
|
||||
onClickDelete={jest.fn()}
|
||||
>
|
||||
<React.Fragment>
|
||||
|
@ -15,9 +15,11 @@ import {sendFlashMessage} from '../flashMessages'
|
||||
import {IUser} from '../../user'
|
||||
import {getMe} from '../../store/users'
|
||||
import {useAppSelector} from '../../store/hooks'
|
||||
import TelemetryClient, {TelemetryActions, TelemetryCategory} from '../../telemetry/telemetryClient'
|
||||
|
||||
type Props = {
|
||||
cardId: string
|
||||
boardId: string
|
||||
onClickDelete: () => void
|
||||
onClickDuplicate?: () => void
|
||||
children?: ReactNode
|
||||
@ -29,6 +31,18 @@ export const CardActionsMenu = (props: Props): JSX.Element => {
|
||||
const me = useAppSelector<IUser|null>(getMe)
|
||||
const intl = useIntl()
|
||||
|
||||
const handleDeleteCard = () => {
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteCard, {board: props.boardId, card: props.cardId})
|
||||
props.onClickDelete()
|
||||
}
|
||||
|
||||
const handleDuplicateCard = () => {
|
||||
if (props.onClickDuplicate) {
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: props.boardId, card: props.cardId})
|
||||
props.onClickDuplicate()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu position='left'>
|
||||
<BoardPermissionGate permissions={[Permission.ManageBoardCards]}>
|
||||
@ -36,14 +50,14 @@ export const CardActionsMenu = (props: Props): JSX.Element => {
|
||||
icon={<DeleteIcon/>}
|
||||
id='delete'
|
||||
name={intl.formatMessage({id: 'CardActionsMenu.delete', defaultMessage: 'Delete'})}
|
||||
onClick={props.onClickDelete}
|
||||
onClick={handleDeleteCard}
|
||||
/>
|
||||
{props.onClickDuplicate &&
|
||||
<Menu.Text
|
||||
icon={<DuplicateIcon/>}
|
||||
id='duplicate'
|
||||
name={intl.formatMessage({id: 'CardActionsMenu.duplicate', defaultMessage: 'Duplicate'})}
|
||||
onClick={props.onClickDuplicate}
|
||||
onClick={handleDuplicateCard}
|
||||
/>}
|
||||
</BoardPermissionGate>
|
||||
{me?.id !== 'single-user' &&
|
||||
|
@ -120,6 +120,7 @@ const CardDialog = (props: Props): JSX.Element => {
|
||||
const menu = (
|
||||
<CardActionsMenu
|
||||
cardId={props.cardId}
|
||||
boardId={board.id}
|
||||
onClickDelete={handleDeleteButtonOnClick}
|
||||
>
|
||||
{!isTemplate &&
|
||||
|
@ -92,6 +92,7 @@ const GalleryCard = (props: Props) => {
|
||||
<CardActionsMenuIcon/>
|
||||
<CardActionsMenu
|
||||
cardId={card!.id}
|
||||
boardId={card!.boardId}
|
||||
onClickDelete={() => setShowConfirmationDialogBox(true)}
|
||||
onClickDuplicate={() => {
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
|
||||
|
@ -105,6 +105,7 @@ const KanbanCard = (props: Props) => {
|
||||
<CardActionsMenuIcon/>
|
||||
<CardActionsMenu
|
||||
cardId={card!.id}
|
||||
boardId={card!.boardId}
|
||||
onClickDelete={handleDeleteButtonOnClick}
|
||||
onClickDuplicate={() => {
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,12 +3,13 @@
|
||||
|
||||
import React from 'react'
|
||||
import {Provider as ReduxProvider} from 'react-redux'
|
||||
import {render, screen, waitFor} from '@testing-library/react'
|
||||
import {render, screen} from '@testing-library/react'
|
||||
import configureStore from 'redux-mock-store'
|
||||
import '@testing-library/jest-dom'
|
||||
import userEvents from '@testing-library/user-event'
|
||||
|
||||
import 'isomorphic-fetch'
|
||||
import {mocked} from 'jest-mock'
|
||||
|
||||
import {TestBlockFactory} from '../../test/testBlockFactory'
|
||||
import {FetchMock} from '../../test/fetchMock'
|
||||
@ -20,6 +21,8 @@ import {Utils, IDType} from '../../utils'
|
||||
|
||||
import {wrapDNDIntl} from '../../testUtils'
|
||||
|
||||
import Mutator from '../../mutator'
|
||||
|
||||
import Table from './table'
|
||||
|
||||
global.fetch = FetchMock.fn
|
||||
@ -28,6 +31,11 @@ beforeEach(() => {
|
||||
FetchMock.fn.mockReset()
|
||||
})
|
||||
|
||||
jest.mock('../../mutator')
|
||||
jest.mock('../../utils')
|
||||
jest.mock('../../telemetry/telemetryClient')
|
||||
const mockedMutator = mocked(Mutator, true)
|
||||
|
||||
describe('components/table/Table', () => {
|
||||
const board = TestBlockFactory.createBoard()
|
||||
const view = TestBlockFactory.createBoardView(board)
|
||||
@ -675,8 +683,67 @@ describe('components/table/Table extended', () => {
|
||||
userEvents.click(deleteBtn)
|
||||
const dailogDeleteBtn = screen.getByRole('button', {name: 'Delete'})
|
||||
userEvents.click(dailogDeleteBtn)
|
||||
await waitFor(() => {
|
||||
expect(global.fetch).toHaveBeenCalledWith(`http://localhost/api/v2/boards/${board.id}/blocks/${card1.id}`, {headers: {Accept: 'application/json', Authorization: '', 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest'}, method: 'DELETE'})
|
||||
expect(mockedMutator.deleteBlock).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
test('should have Duplicate Button', async () => {
|
||||
const board = TestBlockFactory.createBoard()
|
||||
|
||||
const modifiedById = Utils.createGuid(IDType.User)
|
||||
board.cardProperties.push({
|
||||
id: modifiedById,
|
||||
name: 'Last Modified By',
|
||||
type: 'updatedBy',
|
||||
options: [],
|
||||
})
|
||||
const card1 = TestBlockFactory.createCard(board)
|
||||
card1.title = 'card1'
|
||||
const card2 = TestBlockFactory.createCard(board)
|
||||
card2.title = 'card2'
|
||||
const view = TestBlockFactory.createBoardView(board)
|
||||
view.fields.viewType = 'table'
|
||||
view.fields.groupById = undefined
|
||||
view.fields.visiblePropertyIds = ['property1', 'property2', modifiedById]
|
||||
const mockStore = configureStore([])
|
||||
const store = mockStore({
|
||||
...state,
|
||||
cards: {
|
||||
cards: {
|
||||
[card1.id]: card1,
|
||||
[card2.id]: card2,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const component = wrapDNDIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Table
|
||||
board={board}
|
||||
activeView={view}
|
||||
visibleGroups={[]}
|
||||
cards={[card1, card2]}
|
||||
views={[view]}
|
||||
selectedCardIds={[]}
|
||||
readonly={false}
|
||||
cardIdToFocusOnRender=''
|
||||
showCard={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
onCardClicked={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
/>
|
||||
</ReduxProvider>,
|
||||
)
|
||||
|
||||
const {getByTitle, getByRole, getAllByTitle, container} = render(component)
|
||||
const card1Name = getByTitle(card1.title)
|
||||
userEvents.hover(card1Name)
|
||||
const menuBtn = getAllByTitle('MenuBtn')
|
||||
userEvents.click(menuBtn[0])
|
||||
const duplicateBtn = getByRole('button', {name: 'Duplicate'})
|
||||
expect(duplicateBtn).not.toBe(null)
|
||||
userEvents.click(duplicateBtn)
|
||||
expect(mockedMutator.duplicateCard).toBeCalledTimes(1)
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
@ -14,15 +14,14 @@ import {useSortable} from '../../hooks/sortable'
|
||||
import {Utils} from '../../utils'
|
||||
|
||||
import PropertyValueElement from '../propertyValueElement'
|
||||
import Menu from '../../widgets/menu'
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
import IconButton from '../../widgets/buttons/iconButton'
|
||||
import CompassIcon from '../../widgets/icons/compassIcon'
|
||||
import OptionsIcon from '../../widgets/icons/options'
|
||||
import DeleteIcon from '../../widgets/icons/delete'
|
||||
import Tooltip from '../../widgets/tooltip'
|
||||
import ConfirmationDialogBox, {ConfirmationDialogBoxProps} from '../confirmationDialogBox'
|
||||
import TelemetryClient, {TelemetryActions, TelemetryCategory} from '../../telemetry/telemetryClient'
|
||||
import CardActionsMenu from '../cardActionsMenu/cardActionsMenu'
|
||||
|
||||
import {useColumnResize} from './tableColumnResizeContext'
|
||||
|
||||
@ -39,7 +38,7 @@ type Props = {
|
||||
isSelected: boolean
|
||||
focusOnMount: boolean
|
||||
isLastCard: boolean
|
||||
showCard: (cardId: string) => void
|
||||
showCard: (cardId?: string) => void
|
||||
readonly: boolean
|
||||
addCard: (groupByOptionId?: string) => Promise<void>
|
||||
onClick?: (e: React.MouseEvent<HTMLDivElement>, card: Card) => void
|
||||
@ -184,14 +183,27 @@ const TableRow = (props: Props) => {
|
||||
icon={<OptionsIcon/>}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
icon={<DeleteIcon/>}
|
||||
id='delete'
|
||||
name={intl.formatMessage({id: 'TableRow.delete', defaultMessage: 'Delete'})}
|
||||
onClick={handleDeleteButtonOnClick}
|
||||
/>
|
||||
</Menu>
|
||||
<CardActionsMenu
|
||||
cardId={card.id}
|
||||
boardId={card.boardId}
|
||||
onClickDelete={handleDeleteButtonOnClick}
|
||||
onClickDuplicate={() => {
|
||||
mutator.duplicateCard(
|
||||
card.id,
|
||||
board.id,
|
||||
false,
|
||||
intl.formatMessage({id: 'TableRow.DuplicateCard', defaultMessage: 'duplicate card'}),
|
||||
false,
|
||||
{},
|
||||
async (newCardId) => {
|
||||
props.showCard(newCardId)
|
||||
},
|
||||
async () => {
|
||||
props.showCard(undefined)
|
||||
},
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</MenuWrapper>
|
||||
)}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user