1- import * as React from 'react' ;
21import {
3- useResourceContext ,
42 usePreference ,
3+ useResourceContext ,
54 useStore ,
65 useTranslate ,
76} from 'ra-core' ;
7+ import * as React from 'react' ;
88
99import { Configurable } from '../../preferences' ;
1010import { 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,82 @@ 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 =>
131+ ( ! ! c . source &&
132+ c . source === oldAvailableColumn . source ) ||
133+ ( ! ! c . label &&
134+ c . label === oldAvailableColumn . label )
135+ )
136+ )
137+ . filter ( c => ! ! c ) as ConfigurableDatagridColumn [ ] ) , // Remove undefined columns
138+ // Then the new columns
139+ ...newAvailableColumns . filter (
140+ c =>
141+ ! availableColumns . some (
142+ oldAvailableColumn =>
143+ ( ! ! oldAvailableColumn . source &&
144+ oldAvailableColumn . source === c . source ) ||
145+ ( ! ! oldAvailableColumn . label &&
146+ oldAvailableColumn . label === c . label )
147+ )
148+ ) ,
149+ ] ;
150+ setAvailableColumns ( newAvailableColumnsSortedAsBefore ) ;
80151 setOmit ( omit ) ;
81152 }
82153 } , [ availableColumns ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
0 commit comments