Skip to content

Commit d39112d

Browse files
authored
fix: Allow dynamic change of table selection #2445 (#2452)
1 parent 6caeebf commit d39112d

File tree

2 files changed

+100
-33
lines changed

2 files changed

+100
-33
lines changed

ui/src/table.test.tsx

+84-20
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ describe('Table.tsx', () => {
260260
const { getByTestId } = render(<XTable model={tableProps} />)
261261
expect(getByTestId(name).style.height).toBe('290px')
262262
})
263-
264263
})
265264

266265
describe('Wave calls', () => {
@@ -366,6 +365,71 @@ describe('Table.tsx', () => {
366365
expect(wave.args[name]).toMatchObject(['rowname2'])
367366
})
368367

368+
it('Updates single selection', () => {
369+
const { getAllByRole, rerender } = render(<XTable model={{ ...tableProps, single: true }} />)
370+
const radioButtons = getAllByRole('radio')
371+
372+
rerender(<XTable model={{ ...tableProps, single: true, value: 'rowname1' }} />)
373+
374+
expect(radioButtons[0].firstChild).toHaveClass('is-checked')
375+
expect(wave.args[name]).toMatchObject(['rowname1'])
376+
})
377+
378+
it('Updates multiple selection', () => {
379+
const { getAllByRole, rerender } = render(<XTable model={{ ...tableProps, multiple: true }} />)
380+
const checkboxes = getAllByRole('checkbox')
381+
382+
rerender(<XTable model={{ ...tableProps, multiple: true, values: ['rowname1', 'rowname2'] }} />)
383+
384+
expect(checkboxes[1].firstChild).toHaveClass('is-checked')
385+
expect(checkboxes[2].firstChild).toHaveClass('is-checked')
386+
expect(wave.args[name]).toMatchObject(['rowname1', 'rowname2'])
387+
})
388+
389+
it('Clears single selection', () => {
390+
const { getAllByRole, rerender } = render(<XTable model={{ ...tableProps, single: true, value: 'rowname1' }} />)
391+
const radioButtons = getAllByRole('radio')
392+
393+
expect(radioButtons[0].firstChild).toHaveClass('is-checked')
394+
expect(wave.args[name]).toMatchObject(['rowname1'])
395+
396+
rerender(<XTable model={{ ...tableProps, single: true, value: undefined }} />)
397+
398+
expect(radioButtons[0].firstChild).not.toHaveClass('is-checked')
399+
expect(wave.args[name]).toMatchObject([])
400+
})
401+
402+
it('Clears multiple selection', () => {
403+
const { getAllByRole, rerender } = render(<XTable model={{ ...tableProps, multiple: true, values: ['rowname1', 'rowname2'] }} />)
404+
const checkBoxes = getAllByRole('checkbox')
405+
406+
expect(checkBoxes[1].firstChild).toHaveClass('is-checked')
407+
expect(checkBoxes[2].firstChild).toHaveClass('is-checked')
408+
expect(wave.args[name]).toMatchObject(['rowname1', 'rowname2'])
409+
410+
rerender(<XTable model={{ ...tableProps, multiple: true, values: [] }} />)
411+
412+
expect(checkBoxes[1].firstChild).not.toHaveClass('is-checked')
413+
expect(checkBoxes[2].firstChild).not.toHaveClass('is-checked')
414+
expect(wave.args[name]).toMatchObject([])
415+
})
416+
417+
it('Does not fire event on single selection update', () => {
418+
const { rerender } = render(<XTable model={{ ...tableProps, single: true, events: ['select'] }} />)
419+
420+
rerender(<XTable model={{ ...tableProps, single: true, events: ['select'], value: 'rowname1', }} />)
421+
422+
expect(emitMock).toHaveBeenCalledTimes(0)
423+
})
424+
425+
it('Does not fire event on multiple selection update', () => {
426+
const { rerender } = render(<XTable model={{ ...tableProps, multiple: true, events: ['select'] }} />)
427+
428+
rerender(<XTable model={{ ...tableProps, multiple: true, events: ['select'], values: ['rowname1', 'rowname2'] }} />)
429+
430+
expect(emitMock).toHaveBeenCalledTimes(0)
431+
})
432+
369433
it('Fires event - multiple selection - select single', () => {
370434
const { getAllByRole } = render(<XTable model={{ ...tableProps, multiple: true, events: ['select'] }} />)
371435
const checkboxes = getAllByRole('checkbox')
@@ -1689,7 +1753,7 @@ describe('Table.tsx', () => {
16891753

16901754
//collapse all groups
16911755
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
1692-
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21, cell11, cell31])
1756+
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21, cell11, cell31])
16931757
})
16941758

16951759
it('Expands all group by list - fire event', () => {
@@ -1700,8 +1764,8 @@ describe('Table.tsx', () => {
17001764

17011765
//open all groups
17021766
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
1703-
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21, cell11, cell31])
1704-
})
1767+
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21, cell11, cell31])
1768+
})
17051769

17061770
it('Collapses group by list - fire event', () => {
17071771
const { container, getAllByText, getByTestId } = render(<XTable model={{ ...tableProps, events: ['group_change'] }} />)
@@ -1715,9 +1779,9 @@ describe('Table.tsx', () => {
17151779

17161780
//collapse 1st group
17171781
fireEvent.click(container.querySelector('.ms-GroupHeader-expand')!)
1718-
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21])
1782+
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21])
17191783
})
1720-
1784+
17211785
it('Expands group by list - fire event', () => {
17221786
const { container, getAllByText, getByTestId } = render(<XTable model={{ ...tableProps, events: ['group_change'] }} />)
17231787

@@ -1726,8 +1790,8 @@ describe('Table.tsx', () => {
17261790

17271791
//open 1st group
17281792
fireEvent.click(container.querySelector('.ms-GroupHeader-expand')!)
1729-
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21])
1730-
})
1793+
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', [cell21])
1794+
})
17311795
})
17321796

17331797
describe('Groups', () => {
@@ -1836,7 +1900,7 @@ describe('Table.tsx', () => {
18361900
//collapse all groups
18371901
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
18381902
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA', 'GroupB'])
1839-
expect(emitMock).toHaveBeenCalledTimes(1)
1903+
expect(emitMock).toHaveBeenCalledTimes(1)
18401904
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount)
18411905
})
18421906

@@ -1850,7 +1914,7 @@ describe('Table.tsx', () => {
18501914
//open all groups
18511915
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
18521916
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA', 'GroupB'])
1853-
expect(emitMock).toHaveBeenCalledTimes(1)
1917+
expect(emitMock).toHaveBeenCalledTimes(1)
18541918
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount + items)
18551919
})
18561920

@@ -1871,40 +1935,40 @@ describe('Table.tsx', () => {
18711935

18721936
fireEvent.click(container.querySelector('.ms-GroupHeader-expand')!)
18731937
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA'])
1874-
expect(emitMock).toHaveBeenCalledTimes(1)
1938+
expect(emitMock).toHaveBeenCalledTimes(1)
18751939
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount + items - filteredItem)
1876-
})
1940+
})
18771941

18781942
it('Collapses all groups when some already collapsed - fire event', () => {
18791943
const { container, getAllByRole } = render(<XTable model={{ ...tableProps, events: ['group_change'] }} />)
18801944

18811945
//collapse all groups
18821946
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
18831947
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA', 'GroupB'])
1884-
expect(emitMock).toHaveBeenCalledTimes(1)
1885-
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount)
1948+
expect(emitMock).toHaveBeenCalledTimes(1)
1949+
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount)
18861950
emitMock.mockClear()
18871951

18881952
//open all groups
18891953
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
18901954
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA', 'GroupB'])
1891-
expect(emitMock).toHaveBeenCalledTimes(1)
1892-
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount + items)
1955+
expect(emitMock).toHaveBeenCalledTimes(1)
1956+
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount + items)
18931957
emitMock.mockClear()
18941958

18951959
//collapse GroupA
18961960
fireEvent.click(container.querySelector('.ms-GroupHeader-expand')!)
18971961
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupA'])
1898-
expect(emitMock).toHaveBeenCalledTimes(1)
1962+
expect(emitMock).toHaveBeenCalledTimes(1)
18991963
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount + filteredItem)
19001964
emitMock.mockClear()
19011965

19021966
//collapse all groups
19031967
fireEvent.click(container.querySelector('.ms-DetailsHeader-collapseButton')!)
19041968
expect(emitMock).toHaveBeenCalledWith(tableProps.name, 'group_change', ['GroupB'])
1905-
expect(emitMock).toHaveBeenCalledTimes(1)
1906-
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount)
1907-
})
1969+
expect(emitMock).toHaveBeenCalledTimes(1)
1970+
expect(getAllByRole('row')).toHaveLength(headerRow + groupHeaderRowsCount)
1971+
})
19081972

19091973
it('Checks if expanded state is preserved after sort', () => {
19101974
const { container, getAllByRole } = render(<XTable model={tableProps} />)

ui/src/table.tsx

+16-13
Original file line numberDiff line numberDiff line change
@@ -500,24 +500,24 @@ const
500500
: groups?.map(group => group.name)
501501
wave.emit(m.name, 'group_change', changedGroups)
502502
}
503-
expandedRefs.current = isAllCollapsed ? {} : null
503+
expandedRefs.current = isAllCollapsed ? {} : null
504504
},
505505
onToggleCollapse = ({ key, isCollapsed }: Fluent.IGroup) => {
506506
if (m.events?.includes('group_change')) {
507507
wave.emit(m.name, 'group_change', [key])
508-
}
508+
}
509509
if (expandedRefs.current) {
510510
isCollapsed
511511
? expandedRefs.current[key] = false
512512
: delete expandedRefs.current[key]
513513
} else {
514-
if (groups){
514+
if (groups) {
515515
expandedRefs.current = groups?.reduce((acc, { name }) => {
516-
if (name != key){
516+
if (name != key) {
517517
acc[name] = false
518518
}
519519
return acc
520-
}, {} as { [key: S]: B })
520+
}, {} as { [key: S]: B })
521521
}
522522
}
523523
},
@@ -1024,17 +1024,20 @@ export const
10241024
React.useEffect(() => {
10251025
skipNextEventEmit.current = true
10261026
wave.args[m.name] = []
1027-
if (isSingle && m.value) {
1028-
selection.setKeySelected(m.value, true, false)
1029-
wave.args[m.name] = [m.value]
1030-
}
1031-
else if (isMultiple && m.values) {
1032-
m.values.forEach(v => selection.setKeySelected(v, true, false))
1033-
wave.args[m.name] = m.values
1027+
if (isSingle || isMultiple) {
1028+
selection.setAllSelected(false)
1029+
if (m.value) {
1030+
selection.setKeySelected(m.value, true, false)
1031+
wave.args[m.name] = [m.value]
1032+
}
1033+
if (m.values) {
1034+
m.values.forEach(v => selection.setKeySelected(v, true, false))
1035+
wave.args[m.name] = m.values
1036+
}
10341037
}
10351038
skipNextEventEmit.current = false
10361039
// eslint-disable-next-line react-hooks/exhaustive-deps
1037-
}, [])
1040+
}, [m.values, m.value])
10381041

10391042
useUpdateOnlyEffect(() => {
10401043
setFilteredItems(items)

0 commit comments

Comments
 (0)