New button using default template in kanban view. (#3444)
* New button using default template in kanban view.
This commit is contained in:
parent
880a7754f7
commit
04b553621f
7 changed files with 169 additions and 3 deletions
|
@ -104,6 +104,7 @@ const BoardTemplateSelectorPreview = (props: Props) => {
|
|||
readonly={false}
|
||||
onCardClicked={() => null}
|
||||
addCard={() => Promise.resolve()}
|
||||
addCardFromTemplate={() => Promise.resolve()}
|
||||
showCard={() => null}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={() => null}
|
||||
|
|
|
@ -68,6 +68,7 @@ const CardDialog = (props: Props): JSX.Element => {
|
|||
card.fields.isTemplate,
|
||||
intl.formatMessage({id: 'Mutator.new-template-from-card', defaultMessage: 'new template from card'}),
|
||||
true,
|
||||
{},
|
||||
async (newCardId) => {
|
||||
props.showCard(newCardId)
|
||||
},
|
||||
|
|
|
@ -258,8 +258,17 @@ const CenterPanel = (props: Props) => {
|
|||
}
|
||||
}, [selectedCardIds])
|
||||
|
||||
const addCardFromTemplate = useCallback(async (cardTemplateId: string) => {
|
||||
const {activeView, board} = props
|
||||
const addCardFromTemplate = useCallback(async (cardTemplateId: string, groupByOptionId?: string) => {
|
||||
const {activeView, board, groupByProperty} = props
|
||||
|
||||
const propertiesThatMeetFilters = CardFilter.propertiesThatMeetFilterGroup(activeView.fields.filter, board.cardProperties)
|
||||
if ((activeView.fields.viewType === 'board' || activeView.fields.viewType === 'table') && groupByProperty) {
|
||||
if (groupByOptionId) {
|
||||
propertiesThatMeetFilters[groupByProperty.id] = groupByOptionId
|
||||
} else {
|
||||
delete propertiesThatMeetFilters[groupByProperty.id]
|
||||
}
|
||||
}
|
||||
|
||||
mutator.performAsUndoGroup(async () => {
|
||||
const [, newCardId] = await mutator.duplicateCard(
|
||||
|
@ -268,6 +277,7 @@ const CenterPanel = (props: Props) => {
|
|||
true,
|
||||
intl.formatMessage({id: 'Mutator.new-card-from-template', defaultMessage: 'new card from template'}),
|
||||
false,
|
||||
propertiesThatMeetFilters,
|
||||
async (cardId) => {
|
||||
dispatch(updateView({...activeView, fields: {...activeView.fields, cardOrder: [...activeView.fields.cardOrder, cardId]}}))
|
||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.CreateCardViaTemplate, {board: props.board.id, view: props.activeView.id, card: cardId, cardTemplateId})
|
||||
|
@ -421,6 +431,7 @@ const CenterPanel = (props: Props) => {
|
|||
readonly={props.readonly}
|
||||
onCardClicked={cardClicked}
|
||||
addCard={addCard}
|
||||
addCardFromTemplate={addCardFromTemplate}
|
||||
showCard={showCard}
|
||||
hiddenCardsCount={props.hiddenCardsCount}
|
||||
showHiddenCardCountNotification={hiddenCardCountNotifyHandler}
|
||||
|
|
|
@ -88,6 +88,12 @@ describe('src/component/kanban/kanban', () => {
|
|||
board_id_1: {userId: 'user_id_1', schemeAdmin: true},
|
||||
},
|
||||
},
|
||||
views: {
|
||||
views: {
|
||||
boardView: activeView,
|
||||
},
|
||||
current: 'boardView',
|
||||
},
|
||||
contents: {},
|
||||
comments: {
|
||||
comments: {},
|
||||
|
@ -126,6 +132,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -162,6 +169,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -197,6 +205,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -234,6 +243,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -281,6 +291,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -328,6 +339,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -376,6 +388,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={mockedAddCard}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -415,6 +428,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -454,6 +468,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -500,6 +515,7 @@ describe('src/component/kanban/kanban', () => {
|
|||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={jest.fn()}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
|
@ -514,3 +530,128 @@ describe('src/component/kanban/kanban', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('src/component/kanban/kanban', () => {
|
||||
const board = TestBlockFactory.createBoard()
|
||||
const activeView = TestBlockFactory.createBoardView(board)
|
||||
const card1 = TestBlockFactory.createCard(board)
|
||||
card1.id = 'id1'
|
||||
card1.fields.properties = {id: 'property_value_id_1'}
|
||||
const card2 = TestBlockFactory.createCard(board)
|
||||
card2.id = 'id2'
|
||||
card2.fields.properties = {id: 'property_value_id_1'}
|
||||
const card3 = TestBlockFactory.createCard(board)
|
||||
card3.id = 'id3'
|
||||
card3.fields.properties = {id: 'property_value_id_2'}
|
||||
activeView.fields.kanbanCalculations = {
|
||||
id1: {
|
||||
calculation: 'countEmpty',
|
||||
propertyId: '1',
|
||||
|
||||
},
|
||||
}
|
||||
activeView.fields.defaultTemplateId = "defaultTemplateId"
|
||||
const optionQ1:IPropertyOption = {
|
||||
color: 'propColorOrange',
|
||||
id: 'property_value_id_1',
|
||||
value: 'Q1',
|
||||
}
|
||||
const optionQ2:IPropertyOption = {
|
||||
color: 'propColorBlue',
|
||||
id: 'property_value_id_2',
|
||||
value: 'Q2',
|
||||
}
|
||||
const optionQ3:IPropertyOption = {
|
||||
color: 'propColorDefault',
|
||||
id: 'property_value_id_3',
|
||||
value: 'Q3',
|
||||
}
|
||||
|
||||
const groupProperty: IPropertyTemplate = {
|
||||
id: 'id',
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
options: [optionQ1, optionQ2],
|
||||
}
|
||||
|
||||
const state = {
|
||||
users: {
|
||||
me: {
|
||||
id: 'user_id_1',
|
||||
props: {},
|
||||
},
|
||||
},
|
||||
cards: {
|
||||
cards: [card1, card2, card3],
|
||||
},
|
||||
teams: {
|
||||
current: {id: 'team-id'},
|
||||
},
|
||||
boards: {
|
||||
current: 'board_id_1',
|
||||
boards: {
|
||||
board_id_1: {id: 'board_id_1'},
|
||||
},
|
||||
myBoardMemberships: {
|
||||
board_id_1: {userId: 'user_id_1', schemeAdmin: true},
|
||||
},
|
||||
},
|
||||
views: {
|
||||
views: {
|
||||
boardView: activeView,
|
||||
},
|
||||
current: 'boardView',
|
||||
},
|
||||
contents: {},
|
||||
comments: {
|
||||
comments: {},
|
||||
},
|
||||
}
|
||||
const store = mockStateStore([], state)
|
||||
beforeAll(() => {
|
||||
console.error = jest.fn()
|
||||
mockDOM()
|
||||
})
|
||||
beforeEach(jest.resetAllMocks)
|
||||
test('return kanban and click on New if view have already have defaultTemplateId', () => {
|
||||
const mockedAddCard = jest.fn()
|
||||
render(wrapDNDIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Kanban
|
||||
board={board}
|
||||
activeView={activeView}
|
||||
cards={[card1, card2]}
|
||||
groupByProperty={groupProperty}
|
||||
visibleGroups={[
|
||||
{
|
||||
option: optionQ1,
|
||||
cards: [card1, card2],
|
||||
}, {
|
||||
option: optionQ2,
|
||||
cards: [card3],
|
||||
},
|
||||
]}
|
||||
hiddenGroups={[
|
||||
{
|
||||
option: optionQ3,
|
||||
cards: [],
|
||||
},
|
||||
]}
|
||||
selectedCardIds={[]}
|
||||
readonly={false}
|
||||
onCardClicked={jest.fn()}
|
||||
addCard={jest.fn()}
|
||||
addCardFromTemplate={mockedAddCard}
|
||||
showCard={jest.fn()}
|
||||
hiddenCardsCount={0}
|
||||
showHiddenCardCountNotification={jest.fn()}
|
||||
/>
|
||||
</ReduxProvider>,
|
||||
), {wrapper: MemoryRouter})
|
||||
const allButtonsNew = screen.getAllByRole('button', {name: '+ New'})
|
||||
expect(allButtonsNew).not.toBeNull()
|
||||
userEvent.click(allButtonsNew[0])
|
||||
expect(mockedAddCard).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -6,6 +6,9 @@ import {FormattedMessage, injectIntl, IntlShape} from 'react-intl'
|
|||
|
||||
import withScrolling, {createHorizontalStrength, createVerticalStrength} from 'react-dnd-scrolling'
|
||||
|
||||
import {useAppSelector} from '../../store/hooks'
|
||||
import {getCurrentView} from '../../store/views'
|
||||
|
||||
import {Position} from '../cardDetail/cardDetailContents'
|
||||
|
||||
import {Board, IPropertyOption, IPropertyTemplate, BoardGroup} from '../../blocks/board'
|
||||
|
@ -40,6 +43,7 @@ type Props = {
|
|||
readonly: boolean
|
||||
onCardClicked: (e: React.MouseEvent, card: Card) => void
|
||||
addCard: (groupByOptionId?: string, show?:boolean) => Promise<void>
|
||||
addCardFromTemplate: (cardTemplateId: string, groupByOptionId?: string) => void
|
||||
showCard: (cardId?: string) => void
|
||||
hiddenCardsCount: number
|
||||
showHiddenCardCountNotification: (show: boolean) => void
|
||||
|
@ -50,6 +54,7 @@ const hStrength = createHorizontalStrength(Utils.isMobile() ? 60 : 250)
|
|||
const vStrength = createVerticalStrength(Utils.isMobile() ? 60 : 250)
|
||||
|
||||
const Kanban = (props: Props) => {
|
||||
const currentView = useAppSelector(getCurrentView)
|
||||
const {board, activeView, cards, groupByProperty, visibleGroups, hiddenGroups, hiddenCardsCount} = props
|
||||
|
||||
if (!groupByProperty) {
|
||||
|
@ -292,7 +297,11 @@ const Kanban = (props: Props) => {
|
|||
<BoardPermissionGate permissions={[Permission.ManageBoardCards]}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
props.addCard(group.option.id, true)
|
||||
if(currentView.fields.defaultTemplateId) {
|
||||
props.addCardFromTemplate(currentView.fields.defaultTemplateId, group.option.id)
|
||||
} else {
|
||||
props.addCard(group.option.id, true)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -115,6 +115,7 @@ const KanbanCard = (props: Props) => {
|
|||
false,
|
||||
'duplicate card',
|
||||
false,
|
||||
{},
|
||||
async (newCardId) => {
|
||||
props.showCard(newCardId)
|
||||
},
|
||||
|
|
|
@ -975,6 +975,7 @@ class Mutator {
|
|||
fromTemplate = false,
|
||||
description = 'duplicate card',
|
||||
asTemplate = false,
|
||||
propertyOverrides?: Record<string, string>,
|
||||
afterRedo?: (newCardId: string) => Promise<void>,
|
||||
beforeUndo?: () => Promise<void>,
|
||||
): Promise<[Block[], string]> {
|
||||
|
@ -1004,6 +1005,7 @@ class Mutator {
|
|||
const patch = {
|
||||
updatedFields: {
|
||||
icon: newRootBlock.fields.icon,
|
||||
properties: {...newRootBlock.fields.properties, ...propertyOverrides}
|
||||
},
|
||||
title: newRootBlock.title,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue