@@ -12,20 +12,22 @@ import 'ag-grid-community/styles/ag-grid.css';
12
12
import 'ag-grid-community/styles/ag-theme-alpine.css' ;
13
13
import { Grid , useTheme } from '@mui/material' ;
14
14
import { useIntl } from 'react-intl' ;
15
- import { CellEditingStoppedEvent , ColumnState , SortChangedEvent } from 'ag-grid-community' ;
16
- import BottomRightButtons from './BottomRightButtons' ;
15
+ import { ColDef , GridApi , GridOptions } from 'ag-grid-community' ;
16
+ import BottomRightButtons , { BottomRightButtonsProps } from './BottomRightButtons' ;
17
17
import FieldConstants from '../../../../utils/constants/fieldConstants' ;
18
18
19
+ type AgGridFn < TFn extends keyof GridOptions , TData > = NonNullable < GridOptions < TData > [ TFn ] > ;
20
+
19
21
export const ROW_DRAGGING_SELECTION_COLUMN_DEF = [
20
22
{
21
23
rowDrag : true ,
22
24
headerCheckboxSelection : true ,
23
25
checkboxSelection : true ,
24
26
maxWidth : 50 ,
25
27
} ,
26
- ] ;
28
+ ] as const satisfies Readonly < ColDef [ ] > ;
27
29
28
- const style = ( customProps : any ) => ( {
30
+ const style = ( customProps : object = { } ) => ( {
29
31
grid : ( theme : any ) => ( {
30
32
width : 'auto' ,
31
33
height : '100%' ,
@@ -83,21 +85,23 @@ const style = (customProps: any) => ({
83
85
} ) ,
84
86
} ) ;
85
87
86
- export interface CustomAgGridTableProps {
88
+ export interface CustomAgGridTableProps < TData , TValue > {
87
89
name : string ;
88
- columnDefs : any ;
89
- makeDefaultRowData : any ;
90
- csvProps : unknown ;
91
- cssProps : unknown ;
92
- defaultColDef : unknown ;
90
+ columnDefs : ColDef < TData , TValue > [ ] ;
91
+ makeDefaultRowData : ( ) => unknown ;
92
+ csvProps : BottomRightButtonsProps [ 'csvProps' ] ;
93
+ cssProps ?: object ;
94
+ defaultColDef : GridOptions < TData > [ 'defaultColDef' ] ;
93
95
pagination : boolean ;
94
96
paginationPageSize : number ;
95
97
suppressRowClickSelection : boolean ;
96
98
alwaysShowVerticalScroll : boolean ;
97
99
stopEditingWhenCellsLoseFocus : boolean ;
98
100
}
99
101
100
- function CustomAgGridTable ( {
102
+ // TODO: rename ContingencyAgGridTable
103
+ // TODO: used only once in gridexplore, move to gridexplore?
104
+ function CustomAgGridTable < TData = unknown , TValue = unknown > ( {
101
105
name,
102
106
columnDefs,
103
107
makeDefaultRowData,
@@ -109,11 +113,10 @@ function CustomAgGridTable({
109
113
suppressRowClickSelection,
110
114
alwaysShowVerticalScroll,
111
115
stopEditingWhenCellsLoseFocus,
112
- ...props
113
- } : CustomAgGridTableProps ) {
116
+ } : Readonly < CustomAgGridTableProps < TData , TValue > > ) {
114
117
const theme : any = useTheme ( ) ;
115
- const [ gridApi , setGridApi ] = useState < any > ( null ) ;
116
- const [ selectedRows , setSelectedRows ] = useState ( [ ] ) ;
118
+ const [ gridApi , setGridApi ] = useState < GridApi < TData > > ( ) ;
119
+ const [ selectedRows , setSelectedRows ] = useState < TData [ ] > ( [ ] ) ;
117
120
const [ newRowAdded , setNewRowAdded ] = useState ( false ) ;
118
121
const [ isSortApplied , setIsSortApplied ] = useState ( false ) ;
119
122
@@ -124,15 +127,15 @@ function CustomAgGridTable({
124
127
} ) ;
125
128
const { append, remove, update, swap, move } = useFieldArrayOutput ;
126
129
127
- const rowData = watch ( name ) ;
130
+ const rowData = watch ( name ) ; // TODO: use correct types for useFormContext<...>()
128
131
129
132
const isFirstSelected = Boolean (
130
- rowData ?. length && gridApi ?. api . getRowNode ( rowData [ 0 ] [ FieldConstants . AG_GRID_ROW_UUID ] ) ?. isSelected ( )
133
+ rowData ?. length && gridApi ?. getRowNode ( rowData [ 0 ] [ FieldConstants . AG_GRID_ROW_UUID ] ) ?. isSelected ( )
131
134
) ;
132
135
133
136
const isLastSelected = Boolean (
134
137
rowData ?. length &&
135
- gridApi ?. api . getRowNode ( rowData [ rowData . length - 1 ] [ FieldConstants . AG_GRID_ROW_UUID ] ) ?. isSelected ( )
138
+ gridApi ?. getRowNode ( rowData [ rowData . length - 1 ] [ FieldConstants . AG_GRID_ROW_UUID ] ) ?. isSelected ( )
136
139
) ;
137
140
138
141
const noRowSelected = selectedRows . length === 0 ;
@@ -146,26 +149,26 @@ function CustomAgGridTable({
146
149
[ getValues , name ]
147
150
) ;
148
151
149
- const handleMoveRowUp = ( ) => {
152
+ const handleMoveRowUp = useCallback ( ( ) => {
150
153
selectedRows
151
- . map ( ( row ) => getIndex ( row ) )
154
+ . map ( getIndex )
152
155
. sort ( )
153
156
. forEach ( ( idx ) => {
154
157
swap ( idx , idx - 1 ) ;
155
158
} ) ;
156
- } ;
159
+ } , [ getIndex , selectedRows , swap ] ) ;
157
160
158
- const handleMoveRowDown = ( ) => {
161
+ const handleMoveRowDown = useCallback ( ( ) => {
159
162
selectedRows
160
- . map ( ( row ) => getIndex ( row ) )
163
+ . map ( getIndex )
161
164
. sort ( )
162
165
. reverse ( )
163
166
. forEach ( ( idx ) => {
164
167
swap ( idx , idx + 1 ) ;
165
168
} ) ;
166
- } ;
169
+ } , [ getIndex , selectedRows , swap ] ) ;
167
170
168
- const handleDeleteRows = ( ) => {
171
+ const handleDeleteRows = useCallback ( ( ) => {
169
172
if ( selectedRows . length === rowData . length ) {
170
173
remove ( ) ;
171
174
} else {
@@ -174,52 +177,59 @@ function CustomAgGridTable({
174
177
remove ( idx ) ;
175
178
} ) ;
176
179
}
177
- } ;
178
-
179
- useEffect ( ( ) => {
180
- if ( gridApi ) {
181
- gridApi . api . refreshCells ( {
182
- force : true ,
183
- } ) ;
184
- }
185
- } , [ gridApi , rowData ] ) ;
180
+ } , [ getIndex , remove , rowData . length , selectedRows ] ) ;
186
181
187
- const handleAddRow = ( ) => {
182
+ const handleAddRow = useCallback ( ( ) => {
188
183
append ( makeDefaultRowData ( ) ) ;
189
184
setNewRowAdded ( true ) ;
190
- } ;
185
+ } , [ append , makeDefaultRowData ] ) ;
191
186
192
187
useEffect ( ( ) => {
193
- if ( gridApi ) {
194
- gridApi . api . sizeColumnsToFit ( ) ;
195
- }
188
+ gridApi ?. refreshCells ( {
189
+ force : true ,
190
+ } ) ;
191
+ } , [ gridApi , rowData ] ) ;
192
+
193
+ useEffect ( ( ) => {
194
+ gridApi ?. sizeColumnsToFit ( ) ;
196
195
} , [ columnDefs , gridApi ] ) ;
197
196
198
197
const intl = useIntl ( ) ;
199
- const getLocaleText = useCallback (
200
- ( params : any ) => {
201
- const key = `agGrid.${ params . key } ` ;
202
- return intl . messages [ key ] || params . defaultValue ;
203
- } ,
198
+ const getLocaleText = useCallback < AgGridFn < 'getLocaleText' , TData > > (
199
+ ( params ) => intl . formatMessage ( { id : `agGrid.${ params . key } ` , defaultMessage : params . defaultValue } ) ,
204
200
[ intl ]
205
201
) ;
206
202
207
- const onGridReady = ( params : any ) => {
208
- setGridApi ( params ) ;
209
- } ;
203
+ const onGridReady = useCallback < AgGridFn < 'onGridReady' , TData > > ( ( event ) => {
204
+ setGridApi ( event . api ) ;
205
+ } , [ ] ) ;
206
+
207
+ const onRowDragEnd = useCallback < AgGridFn < 'onRowDragEnd' , TData > > (
208
+ ( e ) => move ( getIndex ( e . node . data ) , e . overIndex ) ,
209
+ [ getIndex , move ]
210
+ ) ;
211
+
212
+ const onSelectionChanged = useCallback < AgGridFn < 'onSelectionChanged' , TData > > (
213
+ // @ts -expect-error TODO manage null api case (not possible at runtime?)
214
+ ( ) => setSelectedRows ( gridApi . getSelectedRows ( ) ) ,
215
+ [ gridApi ]
216
+ ) ;
210
217
211
- const onRowDataUpdated = ( ) => {
212
- setNewRowAdded ( false ) ;
213
- if ( gridApi ?. api ) {
214
- // update due to new appended row, let's scroll
215
- const lastIndex = rowData . length - 1 ;
216
- gridApi . api . paginationGoToLastPage ( ) ;
217
- gridApi . api . ensureIndexVisible ( lastIndex , 'bottom' ) ;
218
- }
219
- } ;
218
+ const onRowDataUpdated = useCallback < AgGridFn < 'onRowDataUpdated' , TData > > (
219
+ ( /* event */ ) => {
220
+ setNewRowAdded ( false ) ;
221
+ if ( gridApi ) {
222
+ // update due to new appended row, let's scroll
223
+ const lastIndex = rowData . length - 1 ;
224
+ gridApi . paginationGoToLastPage ( ) ;
225
+ gridApi . ensureIndexVisible ( lastIndex , 'bottom' ) ;
226
+ }
227
+ } ,
228
+ [ gridApi , rowData . length ]
229
+ ) ;
220
230
221
- const onCellEditingStopped = useCallback (
222
- ( event : CellEditingStoppedEvent ) => {
231
+ const onCellEditingStopped = useCallback < AgGridFn < 'onCellEditingStopped' , TData > > (
232
+ ( event ) => {
223
233
const rowIndex = getIndex ( event . data ) ;
224
234
if ( rowIndex === - 1 ) {
225
235
return ;
@@ -229,15 +239,22 @@ function CustomAgGridTable({
229
239
[ getIndex , update ]
230
240
) ;
231
241
232
- const onSortChanged = useCallback ( ( event : SortChangedEvent ) => {
233
- const isAnycolumnhasSort = event . api . getColumnState ( ) . some ( ( col : ColumnState ) => col . sort ) ;
234
- setIsSortApplied ( isAnycolumnhasSort ) ;
235
- } , [ ] ) ;
242
+ const onSortChanged = useCallback < AgGridFn < 'onSortChanged' , TData > > (
243
+ ( event ) => setIsSortApplied ( event . api . getColumnState ( ) . some ( ( col ) => col . sort ) ) ,
244
+ [ ]
245
+ ) ;
246
+
247
+ const getRowId = useCallback < AgGridFn < 'getRowId' , TData > > (
248
+ // @ts -expect-error: we don't know at compile time if TData has a "FieldConstants.AG_GRID_ROW_UUID" field
249
+ // TODO maybe force TData type to have this field?
250
+ ( row ) => row . data [ FieldConstants . AG_GRID_ROW_UUID ] ,
251
+ [ ]
252
+ ) ;
236
253
237
254
return (
238
255
< Grid container spacing = { 2 } >
239
256
< Grid item xs = { 12 } className = { theme . aggrid . theme } sx = { style ( cssProps ) . grid } >
240
- < AgGridReact
257
+ < AgGridReact < TData >
241
258
rowData = { rowData }
242
259
onGridReady = { onGridReady }
243
260
getLocaleText = { getLocaleText }
@@ -246,23 +263,21 @@ function CustomAgGridTable({
246
263
domLayout = "autoHeight"
247
264
rowDragEntireRow
248
265
rowDragManaged
249
- onRowDragEnd = { ( e ) => move ( getIndex ( e . node . data ) , e . overIndex ) }
266
+ onRowDragEnd = { onRowDragEnd }
250
267
suppressBrowserResizeObserver
268
+ defaultColDef = { defaultColDef }
251
269
columnDefs = { columnDefs }
252
270
detailRowAutoHeight
253
- onSelectionChanged = { ( ) => {
254
- setSelectedRows ( gridApi . api . getSelectedRows ( ) ) ;
255
- } }
271
+ onSelectionChanged = { onSelectionChanged }
256
272
onRowDataUpdated = { newRowAdded ? onRowDataUpdated : undefined }
257
273
onCellEditingStopped = { onCellEditingStopped }
258
274
onSortChanged = { onSortChanged }
259
- getRowId = { ( row ) => row . data [ FieldConstants . AG_GRID_ROW_UUID ] }
275
+ getRowId = { getRowId }
260
276
pagination = { pagination }
261
277
paginationPageSize = { paginationPageSize }
262
278
suppressRowClickSelection = { suppressRowClickSelection }
263
279
alwaysShowVerticalScroll = { alwaysShowVerticalScroll }
264
280
stopEditingWhenCellsLoseFocus = { stopEditingWhenCellsLoseFocus }
265
- { ...props }
266
281
/>
267
282
</ Grid >
268
283
< BottomRightButtons
0 commit comments