Skip to content

Commit 7e16ae8

Browse files
authored
fix(AnalyticalTable): reconcile columnOrder with columns on reorder (#8290)
1 parent a3f03c7 commit 7e16ae8

File tree

2 files changed

+88
-7
lines changed

2 files changed

+88
-7
lines changed

packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2034,6 +2034,7 @@ describe('AnalyticalTable', () => {
20342034
});
20352035
});
20362036
});
2037+
20372038
it('columns drag & drop', () => {
20382039
const localCols = [...columns];
20392040
localCols.pop();
@@ -2058,6 +2059,78 @@ describe('AnalyticalTable', () => {
20582059
cy.get('@reorder').should('have.been.calledTwice');
20592060
});
20602061

2062+
it('columns drag & drop: reorder then add/remove column', () => {
2063+
const baseCols = [
2064+
{ accessor: 'name', Header: 'Name' },
2065+
{ accessor: 'age', Header: 'Age' },
2066+
{ accessor: 'friend.name', Header: 'Friend Name' },
2067+
];
2068+
const extraCol = { accessor: 'friend.age', Header: 'Friend Age' };
2069+
const reorder = cy.spy().as('reorder');
2070+
2071+
const TestComp = () => {
2072+
const [cols, setCols] = useState(baseCols);
2073+
return (
2074+
<>
2075+
<Button
2076+
onClick={() => {
2077+
setCols((prev) => (prev.length === 3 ? [...prev, extraCol] : prev.slice(0, 3)));
2078+
}}
2079+
>
2080+
Toggle Column
2081+
</Button>
2082+
<AnalyticalTable data={data} columns={cols} onColumnsReorder={reorder} />
2083+
</>
2084+
);
2085+
};
2086+
2087+
const dataTransferById = (colId) => ({
2088+
getData: () => colId,
2089+
});
2090+
2091+
cy.mount(<TestComp />);
2092+
// name -> age => [age, name, friend.name]
2093+
cy.get('[data-column-id="name"]')
2094+
.trigger('dragstart')
2095+
.trigger('drop', { dataTransfer: dataTransferById('age') });
2096+
cy.get('[data-column-id]').each(($col, index) => {
2097+
cy.wrap($col).should('have.text', ['Age', 'Name', 'Friend Name'][index]);
2098+
});
2099+
2100+
// add friend.age => [age, name, friend.name, friend.age]
2101+
cy.findByText('Toggle Column').click();
2102+
cy.get('[data-column-id]').should('have.length', 4);
2103+
cy.get('[data-column-id]').each(($col, index) => {
2104+
cy.wrap($col).should('have.text', ['Age', 'Name', 'Friend Name', 'Friend Age'][index]);
2105+
});
2106+
cy.get('[role="separator"]').eq(0).click();
2107+
2108+
// friend.age -> age => [friend.age, age, name, friend.name]
2109+
cy.get('[data-column-id="age"]')
2110+
.trigger('dragstart')
2111+
.trigger('drop', { dataTransfer: dataTransferById('friend.age') });
2112+
cy.get('[data-column-id]').each(($col, index) => {
2113+
cy.wrap($col).should('have.text', ['Friend Age', 'Age', 'Name', 'Friend Name'][index]);
2114+
});
2115+
2116+
// remove friend.age => [age, name, friend.name]
2117+
cy.findByText('Toggle Column').click();
2118+
cy.get('[data-column-id]').should('have.length', 3);
2119+
cy.get('[data-column-id]').each(($col, index) => {
2120+
cy.wrap($col).should('have.text', ['Age', 'Name', 'Friend Name'][index]);
2121+
});
2122+
2123+
// friend.name -> age => [friend.name, age, name]
2124+
cy.get('[data-column-id="age"]')
2125+
.trigger('dragstart')
2126+
.trigger('drop', { dataTransfer: dataTransferById('friend.name') });
2127+
cy.get('[data-column-id]').each(($col, index) => {
2128+
cy.wrap($col).should('have.text', ['Friend Name', 'Age', 'Name'][index]);
2129+
});
2130+
2131+
cy.get('@reorder').should('have.callCount', 3);
2132+
});
2133+
20612134
it('w/o selection column', () => {
20622135
cy.mount(
20632136
<AnalyticalTable

packages/main/src/components/AnalyticalTable/hooks/useDragAndDrop.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
2-
import type { ReactTableHooks, TableInstance } from '../types/index.js';
3-
4-
const getColumnId = (column) => {
5-
return typeof column.accessor === 'string' ? column.accessor : column.id;
6-
};
2+
import type { ColumnType, ReactTableHooks, TableInstance } from '../types/index.js';
73

84
function getHeaderProps(
95
props: Record<string, unknown>,
@@ -39,7 +35,19 @@ function getHeaderProps(
3935
const draggedColId = e.dataTransfer.getData('text');
4036
if (droppedColId === draggedColId) return;
4137

42-
const internalColumnOrder = columnOrder.length > 0 ? columnOrder : columns.map((col) => getColumnId(col));
38+
// Reconciliation uses same approach as visibleColumns in plugin-hooks/useColumnOrder.js of react-table
39+
const columnOrderCopy = [...columnOrder];
40+
const columnsCopy = [...columns];
41+
const columnsInOrder: ColumnType[] = [];
42+
43+
while (columnsCopy.length && columnOrderCopy.length) {
44+
const targetId = columnOrderCopy.shift();
45+
const foundIndex = columnsCopy.findIndex((col) => col.id === targetId);
46+
if (foundIndex > -1) {
47+
columnsInOrder.push(columnsCopy.splice(foundIndex, 1)[0]);
48+
}
49+
}
50+
const internalColumnOrder = [...columnsInOrder, ...columnsCopy].map((col) => col.id);
4351
const droppedColIdx = internalColumnOrder.findIndex((col) => col === droppedColId);
4452
const draggedColIdx = internalColumnOrder.findIndex((col) => col === draggedColId);
4553

@@ -50,7 +58,7 @@ function getHeaderProps(
5058
setColumnOrder(tempCols);
5159

5260
if (typeof onColumnsReorder === 'function') {
53-
const columnsNewOrder = tempCols.map((tempColId) => columns.find((col) => getColumnId(col) === tempColId));
61+
const columnsNewOrder = tempCols.map((tempColId) => columns.find((col) => col.id === tempColId));
5462
onColumnsReorder(
5563
enrichEventWithDetails(e, {
5664
columnsNewOrder,

0 commit comments

Comments
 (0)