mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.03k stars 1.24k forks source link

[DataGrid] TreeData: allow customizing the rows selected by filtering #10024

Open atlanteh opened 1 year ago

atlanteh commented 1 year ago

Order ID or Support key 💳 (optional)

56081

Duplicates

Latest version

The problem in depth 🔍

When using DataGrid in treeData mode, I'm using the filter model, but the rows that are showing are only the filtered row and the parents of that row. Is there a way to also show all the children of that row? A granular control might be even better because I can also think of a scenario where I want to get all the parents that have a child with a specific value, but would like to see also all the siblings of the filtered row as well. Is this possible today? If not, what are my alternatives?

Your environment 🌎

`npx @mui/envinfo` ``` System: OS: macOS 12.2 Binaries: Node: 16.18.0 - ~/.nvm/versions/node/v16.18.0/bin/node Yarn: 1.22.19 - ~/.nvm/versions/node/v16.18.0/bin/yarn npm: 8.19.2 - ~/.nvm/versions/node/v16.18.0/bin/npm Browsers: Chrome: 115.0.5790.170 Edge: Not Found Safari: 15.3 npmPackages: @emotion/react: ^11.7.1 => 11.11.1 @emotion/styled: ^11.6.0 => 11.11.0 @mui/base: 5.0.0-beta.7 @mui/core-downloads-tracker: 5.14.0 @mui/icons-material: ^5.10.9 => 5.14.0 @mui/lab: ^5.0.0-alpha.114 => 5.0.0-alpha.136 @mui/material: ^5.10.11 => 5.14.0 @mui/private-theming: 5.13.7 @mui/styled-engine: 5.13.2 @mui/system: 5.14.0 @mui/types: 7.2.4 @mui/utils: 5.13.7 @mui/x-data-grid: 6.11.1 @mui/x-data-grid-pro: ^6.11.1 => 6.11.1 @mui/x-date-pickers: 6.11.1 @mui/x-date-pickers-pro: ^6.11.1 => 6.11.1 @mui/x-license-pro: 6.10.0 @types/react: 18.2.14 react: ^18.2.0 => 18.2.0 react-dom: ^18.2.0 => 18.2.0 ```
romgrk commented 1 year ago

No, as far as I know it's not doable.

What you could do instead is implement a filter outside of the grid that would filter the rows you want selected, and pass only those rows to the grid. Would that work for you?

atlanteh commented 1 year ago

This is what I initially thought of doing, but that would be cumbersome, as I'd have to go over all the rows needed to be filtered, going over the entire rows again and check the children/parents needed and add them to the filtered rows. or alternatively building a tree like structure for fast retrieval which I assume the dataGrid already has (or should have) Since you already do it for the parents, I'm assuming you have an inner structure that you can utilize, and just add a hook that we can use to decide whether to show the row or not. Something like:

<DataGrid
  showDependantRow={(row: any, filteredRow: any, level: number) => true}
/>

level might be the distance from the filtered row (direct parent = -1, direct children = 1) by default the filteration can be (row, filteredRow, level) => level <= 0; to maintain current implementation.

romgrk commented 1 year ago

That behavior seems too specific. I think we should rather add an after-filter callback to select/deselect rows according to a user-supplied logic. I have seen a few requests for filtering customization that would be satisfied by such a callback.

We could provide a set of matched rows, and the function is free to walk up/down the tree to select/deselect whatever it sees fit.

@mui/xgrid In general we should probably make the filtering more modular & customizable. Any thoughts on this particular customization?

cherniavskii commented 1 year ago

@romgrk After-filter callback sounds good to me, but it could be cumbersome for this specific use case. How about adding a per-row callback?

diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts b/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts
index 291adc3f3..434a6ae40 100644
--- a/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts
+++ b/packages/grid/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts
@@ -22,6 +22,29 @@ interface FilterRowTreeFromTreeDataParams {

 export const TREE_DATA_STRATEGY = 'tree-data';

+// This is the default logic that could be overriden by the user
+function shouldPass({
+  isMatchingFilters,
+  filteredDescendantCount,
+  isParentMatchingFilters,
+}: {
+  isMatchingFilters: boolean | null;
+  filteredDescendantCount: number;
+  isParentMatchingFilters: boolean;
+}) {
+  switch (isMatchingFilters) {
+    case true: {
+      return true;
+    }
+    case false: {
+      return filteredDescendantCount > 0;
+    }
+    default: {
+      return isParentMatchingFilters;
+    }
+  }
+}
+
 /**
  * A node is visible if one of the following criteria is met:
  * - One of its children is passing the filter
@@ -78,21 +101,11 @@ export const filterRowTreeFromTreeData = (
       });
     }

-    let shouldPassFilters: boolean;
-    switch (isMatchingFilters) {
-      case true: {
-        shouldPassFilters = true;
-        break;
-      }
-      case false: {
-        shouldPassFilters = filteredDescendantCount > 0;
-        break;
-      }
-      default: {
-        shouldPassFilters = isParentMatchingFilters;
-        break;
-      }
-    }
+    const shouldPassFilters = shouldPass({
+      isMatchingFilters,
+      filteredDescendantCount,
+      isParentMatchingFilters,
+    });

     filteredRowsLookup[node.id] = shouldPassFilters;
romgrk commented 1 year ago

I'm not sure how I feel about a per-row callback. I think the use-case is rare enough that it would be fine to provide something with a lesser DX if it solves all the related use-cases properly. We should also consider the performance implications of both, our tree data filtering is kinda slow so I'd be wary of making it even slower in the default case.

mauretanec commented 3 months ago

I think this use case is not so rare. I have similar issue. I have just parent (cluster) and children (item) rows and I would like if some item is returned when filters are applied that also sibling items within the cluster are returned because then when editing the filtered items I need to validate these changes with other items in the cluster and show eventual issues for the user.

Gijs-W commented 2 months ago

I also don't think that this use case is rare, seeing that we have a similar issue