feat: add URL deep-linking for DataGrids
- Add PageUrlState utility for URL ↔ state serialization - Add column `id` field for unique column identification in URLs - Update idSelector to return String for URL compatibility - All DataGrid pages now support URL params: search, sort, order, id - Browser URL updates via replaceState (no GoRouter rebuilds) - Add FilterPanelSemantics for filter panel semantic IDs - Add TESTING.md documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
a6c51f757a
commit
c494ace5d8
@@ -45,6 +45,7 @@ enum DataGridColumnAlignment {
|
||||
/// Column definition for DataGrid.
|
||||
class DataGridColumn<T> {
|
||||
const DataGridColumn({
|
||||
required this.id,
|
||||
required this.header,
|
||||
required this.valueBuilder,
|
||||
this.cellBuilder,
|
||||
@@ -58,6 +59,9 @@ class DataGridColumn<T> {
|
||||
this.tooltip,
|
||||
});
|
||||
|
||||
/// Unique identifier for this column (used in URL deep-linking).
|
||||
final String id;
|
||||
|
||||
/// Column header text.
|
||||
final String header;
|
||||
|
||||
|
||||
@@ -15,9 +15,15 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
required this.source,
|
||||
required this.config,
|
||||
required this.idSelector,
|
||||
String? initialSearch,
|
||||
int? initialSortColumnIndex,
|
||||
bool? initialSortDescending,
|
||||
}) : super(DataGridState<T>(
|
||||
sortColumnIndex: config.defaultSortColumn,
|
||||
sortDescending: config.defaultSortDescending,
|
||||
searchQuery: initialSearch ?? '',
|
||||
sortColumnIndex:
|
||||
initialSortColumnIndex ?? config.defaultSortColumn,
|
||||
sortDescending:
|
||||
initialSortDescending ?? config.defaultSortDescending,
|
||||
)) {
|
||||
// Initial load
|
||||
_load();
|
||||
@@ -29,8 +35,13 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
/// Grid configuration.
|
||||
final DataGridConfig<T> config;
|
||||
|
||||
/// Function to extract unique ID from an item.
|
||||
final Object Function(T item) idSelector;
|
||||
/// Function to extract unique ID from an item (used for selection and URL deep-linking).
|
||||
///
|
||||
/// Returns a unique string identifier for each row. Can be:
|
||||
/// - A simple ID field: `(item) => item.id.toString()`
|
||||
/// - A combination of fields: `(item) => '${item.name}_${item.type}'`
|
||||
/// - Any unique identifier suitable for URLs
|
||||
final String Function(T item) idSelector;
|
||||
|
||||
/// Debounce timer for search.
|
||||
Timer? _searchDebounce;
|
||||
@@ -185,7 +196,7 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
if (!config.rowsSelectable) return;
|
||||
|
||||
final id = idSelector(item);
|
||||
final newSelection = Set<Object>.from(state.selectedIds);
|
||||
final newSelection = Set<String>.from(state.selectedIds);
|
||||
|
||||
if (newSelection.contains(id)) {
|
||||
newSelection.remove(id);
|
||||
@@ -287,17 +298,35 @@ class DataGridController<T> extends StateNotifier<DataGridState<T>> {
|
||||
/// idSelector: (c) => c.id,
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// For URL deep-linking, pass initial state from URL params:
|
||||
/// ```dart
|
||||
/// final gridProvider = dataGridProvider<Container>(
|
||||
/// source: source,
|
||||
/// config: config,
|
||||
/// idSelector: (c) => c.id,
|
||||
/// initialSearch: urlState.search,
|
||||
/// initialSortColumnIndex: _columnIndexForId(urlState.sortColumn),
|
||||
/// initialSortDescending: urlState.sortDescending,
|
||||
/// );
|
||||
/// ```
|
||||
StateNotifierProvider<DataGridController<T>, DataGridState<T>>
|
||||
dataGridProvider<T>({
|
||||
required DataGridSource<T> source,
|
||||
required DataGridConfig<T> config,
|
||||
required Object Function(T) idSelector,
|
||||
required String Function(T) idSelector,
|
||||
String? initialSearch,
|
||||
int? initialSortColumnIndex,
|
||||
bool? initialSortDescending,
|
||||
}) {
|
||||
return StateNotifierProvider<DataGridController<T>, DataGridState<T>>(
|
||||
(ref) => DataGridController<T>(
|
||||
source: source,
|
||||
config: config,
|
||||
idSelector: idSelector,
|
||||
initialSearch: initialSearch,
|
||||
initialSortColumnIndex: initialSortColumnIndex,
|
||||
initialSortDescending: initialSortDescending,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ sealed class DataGridState<T> with _$DataGridState<T> {
|
||||
@Default(false) bool sortDescending,
|
||||
|
||||
/// Currently selected item IDs (if selectable).
|
||||
@Default({}) Set<Object> selectedIds,
|
||||
@Default({}) Set<String> selectedIds,
|
||||
|
||||
/// Current page (for paginated mode).
|
||||
@Default(0) int currentPage,
|
||||
|
||||
Reference in New Issue
Block a user