1
- import * as React from 'react' ;
2
1
import {
3
- useResourceContext ,
4
2
usePreference ,
3
+ useResourceContext ,
5
4
useStore ,
6
5
useTranslate ,
7
6
} from 'ra-core' ;
7
+ import * as React from 'react' ;
8
8
9
9
import { Configurable } from '../../preferences' ;
10
10
import { Datagrid , DatagridProps } from './Datagrid' ;
@@ -50,6 +50,11 @@ export const DatagridConfigurable = ({
50
50
ConfigurableDatagridColumn [ ]
51
51
> ( `preferences.${ finalPreferenceKey } .availableColumns` , [ ] ) ;
52
52
53
+ const [ columns , setColumns ] = useStore < string [ ] > (
54
+ `preferences.${ finalPreferenceKey } .columns` ,
55
+ [ ]
56
+ ) ;
57
+
53
58
// eslint-disable-next-line @typescript-eslint/no-unused-vars
54
59
const [ _ , setOmit ] = useStore < string [ ] | undefined > (
55
60
`preferences.${ finalPreferenceKey } .omit` ,
@@ -58,7 +63,7 @@ export const DatagridConfigurable = ({
58
63
59
64
React . useEffect ( ( ) => {
60
65
// first render, or the preference have been cleared
61
- const columns = React . Children . toArray ( props . children )
66
+ const newAvailableColumns = React . Children . toArray ( props . children )
62
67
. filter ( child => React . isValidElement ( child ) )
63
68
. map ( ( child : React . ReactElement , index ) => ( {
64
69
index : String ( index ) ,
@@ -67,16 +72,82 @@ export const DatagridConfigurable = ({
67
72
child . props . label && typeof child . props . label === 'string' // this list is serializable, so we can't store ReactElement in it
68
73
? child . props . label
69
74
: 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
+ } ) ,
77
82
} ) ) ;
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 ) ;
80
151
setOmit ( omit ) ;
81
152
}
82
153
} , [ availableColumns ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
0 commit comments