1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
//! Types pertaining to defining and constructing a `Grid`.
use std::{collections::HashMap, future::Future};
use ag_grid_core::imports::log;
use ag_grid_derive::FieldSetter;
use js_sys::Function;
use wasm_bindgen::{prelude::*, JsCast};
use wasm_bindgen_futures::spawn_local;
use web_sys::HtmlElement;
pub use crate::shared::SortMethod;
use crate::{
callbacks::{GetRowsParams, IGetRowsParams},
column::ColumnDef,
convert::ToJsValue,
grid::AgGrid,
types::OneOrMany,
Grid, ToJsValue as ToJsValueMacro,
};
/// An instance of an AG Grid [`GridOptions`].
///
/// With this struct, users can specify the initial options for their grid,
/// before calling the [`GridOptions::build()`] method to receive an instance of
/// [`Grid`]. The various options are fully customisable using the builder
/// pattern, so you only need to specify what you need. The options mirror those
/// used in the AG Grid library.
///
/// [`GridOptions`]: https://www.ag-grid.com/javascript-data-grid/grid-options/
#[derive(FieldSetter, ToJsValueMacro)]
#[js_value(skip_serializing_none)]
pub struct GridOptions<T>
where
T: ToJsValue,
{
// Accessories
// TODO
// Clipboard
// TODO
// Column Definitions
/// Set the column definitions. Fields set here take precedence over those
/// set in `default_col_def`.
column_defs: Option<Vec<ColumnDef>>,
/// Set the default column definition. Fields set here have lower precedence
/// than fields set on a per-column basis in `column_defs`.
default_col_def: Option<ColumnDef>,
// default_col_group_def
// column_types
/// Keeps the order of Columns maintained after new Column Definitions are
/// updated.
maintain_column_order: Option<bool>,
/// If `true`, then dots in field names (e.g. 'address.firstLine') are not
/// treated as deep references. Allows you to use dots in your field name if
/// you prefer.
suppress_dot_field_notation: Option<bool>,
// Column Headers
/// The height in pixels for the row containing the column label header. If
/// not specified, it uses the theme value of `header-height`.
header_height: Option<u32>,
/// The height in pixels for the rows containing header column groups. If
/// not specified, it uses [`GridOptions::header_height`].
group_header_height: Option<u32>,
/// The height in pixels for the row containing the floating filters. If not
/// specified, it uses the theme value of `header-height`.
floating_filters_height: Option<u32>,
// Column Moving
/// Set to `true` to suppress column moving, i.e. to make the columns fixed
/// position.
suppress_movable_columns: Option<bool>,
/// If `true`, the `ag-column-moving` class is not added to the grid while
/// columns are moving. In the default themes, this results in no animation
/// when moving columns.
suppress_column_move_animation: Option<bool>,
/// If `true`, when you drag a column out of the grid (e.g. to the group
/// zone) the column is not hidden.
suppress_drag_leave_hides_columns: Option<bool>,
/// If `true`, when you drag a column into a row group panel the column is
/// not hidden.
suppress_row_group_hides_columns: Option<bool>,
// Column Sizing
/// Set to 'Shift' to have shift-resize as the default resize operation
/// (same as user holding down `Shift` while resizing).
col_resize_default: Option<ResizeMethod>,
/// Suppresses auto-sizing columns for columns. In other words, double
/// clicking a column's header's edge will not auto-size.
suppress_auto_size: Option<bool>,
/// Number of pixels to add to a column width after the auto-sizing
/// calculation. Set this if you want to add extra room to accommodate (for
/// example) sort icons, or some other dynamic nature of the header.
auto_size_padding: Option<u32>,
/// Set this to `true` to skip the `header_name` when `auto_size` is called
/// by default.
skip_header_on_auto_size: Option<bool>,
// Components
// TODO
// Editing
/// Set to 'FullRow' to enable Full Row Editing. Otherwise leave blank to
/// edit one cell at a time.
edit_type: Option<EditType>,
/// Set to `true` to enable Single Click Editing for cells, to start editing
/// with a single click.
single_click_edit: Option<bool>,
/// Set to `true` so that neither single nor double click starts editing.
suppress_click_edit: Option<bool>,
/// Set to `true` to stop cell editing when grid loses focus. The default is
/// that the grid stays editing until focus goes onto another cell.
stop_editing_when_cells_lose_focus: Option<bool>,
/// Set to `true` along with [`GridOptions::enter_moves_down_after_edit`] to
/// have Excel-style behaviour for the `Enter` key, i.e. pressing the
/// `Enter` key will move down to the cell beneath.
enter_moves_down: Option<bool>,
/// Set to `true` along with [`GridOptions::enter_moves_down`] to have
/// Excel-style behaviour for the `Enter` key, i.e. pressing the `Enter` key
/// will move down to the cell beneath.
enter_moves_down_after_edit: Option<bool>,
/// Set to `true` to enable Undo / Redo while editing.
undo_redo_cell_editing: Option<bool>,
/// Set the size of the undo / redo stack.
undo_redo_cell_editing_limit: Option<u32>,
/// Set to `true` to stop the grid updating data after and edit. When this
/// is set, it is intended the application will update the data, e.g. in an
/// external immutable store, and then pass the new dataset to the grid.
read_only_edit: Option<bool>,
// Export
/// Prevent the user from exporting the grid to CSV.
suppress_csv_export: Option<bool>,
/// Prevent the user from exporting the grid to Excel.
suppress_excel_export: Option<bool>,
// TODO
// Filtering
// TODO
// Integrated Charts
// TODO
// Keyboard Navigation
// TODO
// Loading Cell Renderers
// TODO
// Localisation
// TODO
// Master Detail
// TODO
// Miscellaneous
/// Provide a context object that is provided to different callbacks the
/// grid uses. Used for passing additional information to the callbacks by
/// your application.
context: Option<HashMap<String, String>>,
/// Change this value to set the tabIndex order of the Grid within your
/// application.
tab_index: Option<u32>,
/// The number of rows rendered outside the viewable area the grid renders.
/// Having a buffer means the grid will have rows ready to show as the user
/// slowly scrolls vertically.
row_buffer: Option<u32>,
/// Set to `true` to enable debug information from the grid and related
/// components. Will result in additional logging being output, but very
/// useful when investigating problems.
debug: Option<bool>,
// Overlays
// TODO
// Pagination
/// Set whether pagination is enabled.
pagination: Option<bool>,
/// How many rows to load per page. If
/// [`GridOptions::pagination_auto_page_size`] is specified, this property
/// is ignored.
pagination_page_size: Option<u32>,
/// Set to `true` so that the number of rows to load per page is
/// automatically adjusted by the grid so each page shows enough rows to
/// just fill the area designated for the grid. If `false`,
/// [#GridOption::pagination_page_size`] is used.
pagination_auto_page_size: Option<bool>,
/// Set to `true` to have pages split children of groups when using Row
/// Grouping or detail rows with Master Detail.
paginate_child_rows: Option<bool>,
/// If `true`, the default grid controls for navigation are hidden. This is
/// useful if `pagination=true` and you want to provide your own pagination
/// controls. Otherwise, when `pagination=true` the grid automatically shows
/// the necessary controls at the bottom so that the user can navigate
/// through the different pages.
suppress_pagination_panel: Option<bool>,
// Pivot and Aggregation
// TODO
// Rendering
/// Set to `true` to enable Row Animation.
animate_rows: Option<bool>,
/// Set to `true` to have cells flash after data changes.
enable_cell_change_flash: Option<bool>,
/// To be used in combination with
/// [`GridOptions::enable_cell_change_flash`], this configuration
/// will set the delay in milliseconds of how long a cell should remain in
/// its "flashed" state.
cell_flash_delay: Option<u32>,
/// To be used in combination with
/// [`GridOptions::enable_cell_change_flash`], this configuration
/// will set the delay in milliseconds of how long the "flashed" state
/// animation takes to fade away after the timer set by
/// [`GridOptions::cell_flash_delay`] has completed.
cell_fade_delay: Option<u32>,
/// Set to `true` to have cells flash after data changes even when the
/// change is due to filtering.
allow_show_change_after_filter: Option<bool>,
/// Switch between layout options.
dom_layout: Option<DomLayout>,
/// When `true`, the order of rows and columns in the DOM are consistent
/// with what is on screen.
ensure_dom_order: Option<bool>,
/// Set to `true` to operate the grid in RTL (Right to Left) mode.
enable_rtl: Option<bool>,
/// Set to `true` so that the grid doesn't virtualise the columns. For
/// example, if you have 100 columns, but only 10 visible due to scrolling,
/// all 100 will always be rendered.
suppress_column_virtualisation: Option<bool>,
/// Set to `true` so that the grid doesn't virtualise the rows. For example,
/// if you have 100 rows, but only 10 visible due to scrolling, all 100 will
/// always be rendered.
suppress_row_virtualisation: Option<bool>,
/// By default the grid has a limit of rendering a maximum of 500 rows at
/// once (remember the grid only renders rows you can see, so unless your
/// display shows more than 500 rows without vertically scrolling this will
/// never be an issue). This is only relevant if you are manually setting
/// [`GridOptions::row_buffer`] to a high value (rendering more rows than
/// can be seen) or if your grid height is able to display more than 500
/// rows at once.
suppress_max_rendered_row_restriction: Option<bool>,
// Row Drag and Drop
/// Set to `true` to enable Managed Row Dragging.
row_drag_managed: Option<bool>,
/// Set to `true` to enable clicking and dragging anywhere on the row
/// without the need for a drag handle.
row_drag_entire_row: Option<bool>,
/// Set to `true` to enable dragging multiple rows at the same time.
row_drag_multi_row: Option<bool>,
/// Set to `true` to suppress row dragging.
suppress_row_drag: Option<bool>,
/// Set to `true` to suppress moving rows while dragging the row drag
/// waffle. This option highlights the position where the row will be
/// placed and it will only move the row on mouse up.
suppress_move_when_row_dragging: Option<bool>,
// Row Full Width
// TODO
// Row Pinning
// TODO
// RowModel
/// Sets the row model type.
row_model_type: Option<RowModelType>,
// get_row_id
// RowModel: Client Side
/// Set the row data.
row_data: Option<Vec<T>>,
// RowModel: Infinite
datasource: Option<DataSource>,
/// How many extra blank rows to display to the user at the end of the
/// dataset, which sets the vertical scroll and then allows the grid to
/// request viewing more rows of data.
cache_overflow_size: Option<u32>,
/// How many requests to hit the server with concurrently. If the max is
/// reached, requests are queued. Set to `-1` for no maximum restriction on
/// requests.
max_concurrent_datasource_requests: Option<i32>,
/// How many rows for each block in the store, i.e. how many rows returned
/// from the server at a time.
cache_block_size: Option<u32>,
/// How many blocks to keep in the store. Default is no limit, so every
/// requested block is kept. Use this if you have memory concerns, and
/// blocks that were least recently viewed will be purged when the limit is
/// hit. The grid will additionally make sure it has all the blocks needed
/// to display what is currently visible, in case this property is set to a
/// low value.
max_blocks_in_cache: Option<u32>,
/// How many extra blank rows to display to the user at the end of the
/// dataset, which sets the vertical scroll and then allows the grid to
/// request viewing more rows of data.
infinite_initial_row_count: Option<u32>,
// TODO
// RowModel: Server Side
// TODO
// RowModel: Viewport
// TODO
// Scrolling
/// Set to `true` to always show the horizontal scrollbar.
always_show_horizontal_scroll: Option<bool>,
/// Set to `true` to always show the vertical scrollbar.
always_show_vertical_scroll: Option<bool>,
/// Set to `true` to debounce the vertical scrollbar. Can provide smoother
/// scrolling on slow machines.
debounce_vertical_scrollbar: Option<bool>,
/// Set to `true` to never show the horizontal scroll. This is useful if the
/// grid is aligned with another grid and will scroll when the other grid
/// scrolls. (Should not be used in combination with
/// [`GridOptions::always_show_horizontal_scroll`].)
suppress_horizontal_scrollbar: Option<bool>,
/// When `true`, the grid will not scroll to the top when new row data is
/// provided. Use this if you don't want the default behaviour of scrolling
/// to the top every time you load new data.
suppress_scroll_on_new_data: Option<bool>,
/// When `true`, the grid will not allow mousewheel / touchpad scroll when
/// popup elements are present.
suppress_scroll_when_popups_are_open: Option<bool>,
/// When `true`, the grid will not use animation frames when drawing rows
/// while scrolling. Use this if the grid is working fast enough that you
/// don't need animation frames and you don't want the grid to flicker.
suppress_animation_frame: Option<bool>,
/// When `true`, middle clicks will result in click events for cells and
/// rows. Otherwise the browser will use middle click to scroll the grid.
/// Note: Not all browsers fire click events with the middle button. Most
/// will fire only mousedown and mouseup events, which can be used to focus
/// a cell, but will not work to call the onCellClicked function.
suppress_middle_click_scrolls: Option<bool>,
/// When `true`, mouse wheel events will be passed to the browser. Useful if
/// your grid has no vertical scrolls and you want the mouse to scroll the
/// browser page.
suppress_prevent_default_on_mouse_wheel: Option<bool>,
/// Tell the grid how wide in pixels the scrollbar is, which is used in grid
/// width calculations. Set only if using non-standard browser-provided
/// scrollbars, so the grid can use the non-standard size in its
/// calculations.
scrollbar_width: Option<u32>,
// Selection
/// Type of row selection.
row_selection: Option<RowSelection>,
/// Set to `true` to allow multiple rows to be selected using single click.
row_multi_select_with_click: Option<bool>,
// is_row_selectable
/// If `true`, rows will not be deselected if you hold down `Ctrl` and click
/// the row or press `Space`.
suppress_row_deselection: Option<bool>,
/// If `true`, row selection won't happen when rows are clicked. Use when
/// you only want checkbox selection.
suppress_row_click_selection: Option<bool>,
/// If `true`, cells won't be focusable. This means keyboard navigation will
/// be disabled for grid cells, but remain enabled in other elements of the
/// grid such as column headers, floating filters, tool panels.
suppress_cell_focus: Option<bool>,
/// Set to `true` to be able to select the text within cells. Note: When
/// this is set to true, the clipboard service is disabled.
enable_cell_text_selection: Option<bool>,
// Sorting
/// Vector defining the order in which sorting occurs (if sorting is
/// enabled).
sorting_order: Option<Vec<SortMethod>>,
/// Set to `true` to specify that the sort should take accented characters
/// into account. If this feature is turned on the sort will be slower.
accented_sort: Option<bool>,
/// Set to `true` to show the 'no sort' icon.
#[js_value(rename = "unSortIcon")]
unsort_icon: Option<bool>,
/// Set to `true` to suppress multi-sort when the user shift-clicks a column
/// header.
suppress_multi_sort: Option<bool>,
/// Set to `true` to always multi-sort when the user clicks a column header,
/// regardless of key presses.
always_multi_sort: Option<bool>,
/// Set to 'Ctrl' to have multi sorting work using the `Ctrl` (or `Command
/// ⌘` for Mac) key.
multi_sort_key: Option<MultiSortKey>,
/// Set to `true` to suppress sorting of un-sorted data to match original
/// row data.
suppress_maintain_unsorted_order: Option<bool>,
/// When enabled, sorts only the rows added/updated by a transaction.
delta_sort: Option<bool>,
// Styling
/// Default row height in pixels.
row_height: Option<u32>,
/// CSS class(es) for all rows. Provide either a string (class name) or
/// vector of strings (vector of class names).
row_class: Option<OneOrMany<String>>,
/// Set to `true` to not highlight rows by adding the `ag-row-hover` CSS
/// class.
suppress_row_hover_highlight: Option<bool>,
/// Uses CSS `top` instead of CSS `transform` for positioning rows. Useful
/// if the transform function is causing issues such as used in `row
/// spanning`.
suppress_row_transform: Option<bool>,
/// Set to `true` to highlight columns by adding the `ag-column-hover` CSS
/// class.
column_hover_highlight: Option<bool>,
// Tooltips
/// Set to `true` to use the browser's default tooltip instead of using the
/// grid's Tooltip Component.
enable_browser_tooltips: Option<bool>,
/// The delay in milliseconds that it takes for tooltips to show up once an
/// element is hovered over. Note: This property does not work if
/// [`GridOptions::enable_browser_tooltips`] is `true`.
tooltip_show_delay: Option<u32>,
/// The delay in milliseconds that it takes for tooltips to hide once they
/// have been displayed. Note: This property does not work if
/// [`GridOptions::enable_browser_tooltips`] is `true`.
tooltip_hide_delay: Option<u32>,
/// Set to `true` to have tooltips follow the cursor once they are
/// displayed.
tooltip_mouse_track: Option<bool>,
}
impl<T> GridOptions<T>
where
T: ToJsValue,
{
pub fn new() -> Self {
Default::default()
}
/// A finaliser method for the [`GridOptions`] struct. This method
/// constructs the underlying JavaScript grid and returns a handle,
/// [`Grid`], which provides access to the grid APIs.
pub fn build(self, div: HtmlElement) -> Grid {
let grid_options = self.to_js_value();
let js_grid = AgGrid::new(div, grid_options);
Grid {
api: js_grid.gridOptions().api(),
column_api: js_grid.gridOptions().columnApi(),
}
}
}
/// Allowed values for [`GridOptions::multi_sort_key`].
#[derive(ToJsValueMacro)]
pub enum MultiSortKey {
Ctrl,
}
/// Allowed values for [`GridOptions::dom_layout`].
#[derive(ToJsValueMacro)]
pub enum DomLayout {
Normal,
Print,
AutoHeight,
}
/// Allowed values for [`GridOptions::edit_type`].
#[derive(ToJsValueMacro)]
pub enum EditType {
FullRow,
}
/// Allowed values for [`GridOptions::col_resize_default`].
#[derive(ToJsValueMacro)]
pub enum ResizeMethod {
Shift,
}
/// Allowed values for [`GridOptions::row_selection`].
#[derive(ToJsValueMacro)]
pub enum RowSelection {
Single,
Multiple,
}
/// Allowed values for [`GridOptions::row_model_type`].
#[derive(ToJsValueMacro)]
pub enum RowModelType {
Infinite,
Viewport,
ClientSide,
ServerSide,
}
/// A struct passed to the JavaScript grid which is used by AG Grid to fetch the
/// requested data from the server.
#[wasm_bindgen]
#[derive(ToJsValueMacro)]
pub struct DataSource {
#[wasm_bindgen(readonly, getter_with_clone, js_name = getRows)]
pub get_rows: Function,
}
/// Builder for the [`DataSource`].
pub struct DataSourceBuilder {
// Callback the grid calls that the user implements to fetch rows from the
// server.
get_rows: Closure<dyn FnMut(IGetRowsParams)>,
// row_count is deprecated. Use GridOptions.infiniteInitialRowCount instead:
// https://github.com/ag-grid/ag-grid/blob/7358e4286fd52946c4fe24bd26b5fbe7fd3b22d4/community-modules/core/src/ts/interfaces/iDatasource.ts#L7-L9
//row_count: Option<u32>,
}
impl DataSourceBuilder {
/// Start constructing a new `DataSourceBuilder` by providing a callback
/// function which will receive [`GetRowsParams`]. This callback is
/// called by AG Grid to request new rows from the server.
pub fn new<F, Fut, T>(mut get_rows: F) -> Self
where
F: FnMut(GetRowsParams) -> Fut + 'static,
Fut: Future<Output = Result<(Vec<T>, Option<u32>), Box<dyn std::error::Error>>> + 'static,
T: ToJsValue,
{
let get_rows =
Closure::<dyn FnMut(IGetRowsParams)>::new(move |js_params: IGetRowsParams| {
let params = (&js_params).into();
let fut = get_rows(params);
let wrapper = async move {
match fut.await {
Ok((data, last_row_index)) => {
let data = data.to_js_value();
let last_row_index = last_row_index.to_js_value();
js_params
.success_callback()
.call2(&JsValue::null(), &data, &last_row_index)
.expect("failed calling success callback");
}
Err(e) => {
log(&format!("Error calling get_rows callback: {e:?}"));
js_params
.fail_callback()
.call0(&JsValue::null())
.expect("failed calling failure callback");
}
};
};
spawn_local(wrapper)
});
Self { get_rows }
}
/// Finalise construction of a [`DataSource`].
pub fn build(self) -> DataSource {
DataSource {
get_rows: self.get_rows.into_js_value().unchecked_into(),
}
}
}