Skip to content

Commit 7dc0866

Browse files
author
Quentin Decré
committed
fix(DatagridConfigurable): better detect and handle columns changes
1 parent 6472e3a commit 7dc0866

File tree

1 file changed

+76
-12
lines changed

1 file changed

+76
-12
lines changed

packages/ra-ui-materialui/src/list/datagrid/DatagridConfigurable.tsx

+76-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import * as React from 'react';
21
import {
3-
useResourceContext,
42
usePreference,
3+
useResourceContext,
54
useStore,
65
useTranslate,
76
} from 'ra-core';
7+
import * as React from 'react';
88

99
import { Configurable } from '../../preferences';
1010
import { Datagrid, DatagridProps } from './Datagrid';
@@ -50,6 +50,11 @@ export const DatagridConfigurable = ({
5050
ConfigurableDatagridColumn[]
5151
>(`preferences.${finalPreferenceKey}.availableColumns`, []);
5252

53+
const [columns, setColumns] = useStore<string[]>(
54+
`preferences.${finalPreferenceKey}.columns`,
55+
[]
56+
);
57+
5358
// eslint-disable-next-line @typescript-eslint/no-unused-vars
5459
const [_, setOmit] = useStore<string[] | undefined>(
5560
`preferences.${finalPreferenceKey}.omit`,
@@ -58,7 +63,7 @@ export const DatagridConfigurable = ({
5863

5964
React.useEffect(() => {
6065
// first render, or the preference have been cleared
61-
const columns = React.Children.toArray(props.children)
66+
const newAvailableColumns = React.Children.toArray(props.children)
6267
.filter(child => React.isValidElement(child))
6368
.map((child: React.ReactElement, index) => ({
6469
index: String(index),
@@ -67,16 +72,75 @@ export const DatagridConfigurable = ({
6772
child.props.label && typeof child.props.label === 'string' // this list is serializable, so we can't store ReactElement in it
6873
? child.props.label
6974
: child.props.source
70-
? // force the label to be the source
71-
undefined
72-
: // no source or label, generate a label
73-
translate('ra.configurable.Datagrid.unlabeled', {
74-
column: index,
75-
_: `Unlabeled column #%{column}`,
76-
}),
75+
? // force the label to be the source
76+
undefined
77+
: // no source or label, generate a label
78+
translate('ra.configurable.Datagrid.unlabeled', {
79+
column: index,
80+
_: `Unlabeled column #%{column}`,
81+
}),
7782
}));
78-
if (columns.length !== availableColumns.length) {
79-
setAvailableColumns(columns);
83+
const hasChanged = newAvailableColumns.some(column => {
84+
const availableColumn = availableColumns.find(
85+
availableColumn =>
86+
(!!availableColumn.source &&
87+
availableColumn.source === column?.source) ||
88+
(!!availableColumn.label &&
89+
availableColumn.label === column.label)
90+
);
91+
return !availableColumn || availableColumn.index !== column.index;
92+
});
93+
if (hasChanged) {
94+
// first we need to update the columns indexes to match the new availableColumns so we keep the same order
95+
const newColumnsSortedAsOldColumns = columns.flatMap(column => {
96+
const oldColumn = availableColumns.find(
97+
availableColumn => availableColumn.index === column
98+
);
99+
const newColumn = newAvailableColumns.find(
100+
availableColumn =>
101+
(!!availableColumn.source &&
102+
availableColumn.source === oldColumn?.source) ||
103+
(!!availableColumn.label &&
104+
availableColumn.label === oldColumn.label)
105+
);
106+
return newColumn?.index ? [newColumn.index] : [];
107+
});
108+
setColumns([
109+
// we add the old columns in the same order as before
110+
...newColumnsSortedAsOldColumns,
111+
// then we add at the new columns which are not omited
112+
...newAvailableColumns
113+
.filter(
114+
c =>
115+
!availableColumns.some(
116+
ac =>
117+
(!!ac.source && ac.source === c.source) ||
118+
(!!ac.label && ac.label === c.label)
119+
) && !omit?.includes(c.source as string)
120+
)
121+
.map(c => c.index),
122+
]);
123+
124+
// Then we update the available columns to include the new columns while keeping the same order as before
125+
const newAvailableColumnsSortedAsBefore = [
126+
// First the existing columns, in the same order
127+
...(availableColumns
128+
.map(oldAvailableColumn =>
129+
newAvailableColumns.find(
130+
c => c.source === oldAvailableColumn.source
131+
)
132+
)
133+
.filter(c => !!c) as ConfigurableDatagridColumn[]), // Remove undefined columns
134+
// Then the new columns
135+
...newAvailableColumns.filter(
136+
c =>
137+
!availableColumns.some(
138+
oldAvailableColumn =>
139+
oldAvailableColumn.source === c.source
140+
)
141+
),
142+
];
143+
setAvailableColumns(newAvailableColumnsSortedAsBefore);
80144
setOmit(omit);
81145
}
82146
}, [availableColumns]); // eslint-disable-line react-hooks/exhaustive-deps

0 commit comments

Comments
 (0)