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/
3.91k stars 1.19k forks source link

[data grid] Implement Row spanning #207

Open oliviertassinari opened 3 years ago

oliviertassinari commented 3 years ago

TODO

Benchmarks

Screenshot 2023-03-02 at 01 02 57 Screenshot 2023-03-02 at 01 05 48 Screenshot 2023-03-02 at 00 58 57 Screenshot 2023-03-02 at 00 59 59 Screenshot 2023-03-02 at 01 00 26

User requests

oliviertassinari commented 10 months ago

@cherniavskii Did we consider to implement this in two steps? A first quick and dirty, unstable API, like AG Grid uses, we could warn about it (I'm sure many people would be OK), and then a proper solution later on.

cherniavskii commented 10 months ago

@oliviertassinari Yes, that's the plan - see https://www.notion.so/mui-org/xGrid-Support-new-use-cases-with-new-features-d05424cedf6f490eb547e6802c5f4a30

moumine9 commented 10 months ago

Hello Everyone, upvotting this feature again.

barrykaplan commented 8 months ago

From a paying customer (yes, there are some of us), some insight the scheduling would be very helpful. We are running out of time and need to make a call whether to swap over to ag-grid or some such.

jithinvariyar commented 8 months ago

I needed this feature so I searched for it, only to find out that it's a long-awaited feature that has been "coming Soon™" for over 3 years. 🥲

dzinreach commented 7 months ago

Seems like this feature is still not implemented, even for the paid plans, right? So, is there a hack to make row spanning for one-to-many record relationships work on the data grid?

oliviertassinari commented 7 months ago

A quick workaround: https://codesandbox.io/p/sandbox/romantic-joji-7hhvfx?file=%2Fsrc%2FDemo.tsx%3A71%2C61

https://github.com/mui/mui-x/assets/3165635/6b073ed2-630b-4cdd-bcc0-e311ee85c4b1

The API looks like this:

const rows = [
  {
    id: 1,
    lastName: "Snow",
    firstName: "Jon",
    age: 35,
    rowSpan: { age: 2 },
  },
  { id: 2, lastName: "Lannister", firstName: "Cersei", age: 42 },
  { id: 3, lastName: "Lannister", firstName: "Jaime", age: 45 },

It's implemented with a cell slot.

function MyCell(props: GridCellProps) {
  let style = {
    // TODO, shouldn't be needed, fix in the core.
    minWidth: props.width,
    maxWidth: props.width,
    minHeight: props.height,
    maxHeight: props.height === "auto" ? "none" : props.height,
    ...props.style,
  };
  const apiRef = useGridApiContext();
  const row = apiRef.current.getRow(props.rowId);
  if (row && row.rowSpan && row.rowSpan[props.column.field]) {
    const span = row.rowSpan[props.column.field];
    style = {
      ...style,
      minHeight: props.height * span,
      maxHeight: props.height * span,
      backgroundColor: "#fff",
      zIndex: 1,
    };
  }
  return <GridCell {...props} style={style} />;
}
yehudamakarov commented 7 months ago

everyone give kudos to @joserodolfofreitas for getting this on the roadmap!

yehudamakarov commented 6 months ago

Does someone have another example (the first one being #207 (comment)) of how this feature would be used? This could help us once we create a demo in the docs. Thanks

for now

dzinreach commented 6 months ago

My use case for the row spanning is for 1:Many record relationships on a report.

Think: Contacts < Cases < Documents

So the rowspan is based on checking the table id/key and the record id, so if the previous record has the same table id and record id, then it should be combined together into one row and rowspan for all of the other columns.

The real challenge is knowing the relationships between columns, and being able to have multiple tables with 1:Many relationships on the same data grid.

Imagine a Contact record spans 4 rows, because they have 4 Document Records, and the Document Records are spread over 2 Cases. So, each Case would have a rowspan of 2.

I’ve set this up in a custom .NET C# reporting platform, which checks the parent_table_id on each column and then the table_id and rec_id on each row.

oliviertassinari commented 5 months ago

Regarding the behavior with filtering, we might want the same as with Excel:

https://github.com/mui/mui-x/assets/3165635/3b925c17-64aa-47ec-8601-e9cb2d10bf33

Rows span is not just a matter of expending to the next row, but about linking two twos together. When one is filtered, no span, when sorting changes their position, likely no span as well.

alexvazquez commented 4 months ago

Is this already implemented? Since i exactly need to do this

Katsuchiyo commented 3 months ago

Any estimation on timeline of the feature?

jeffreyschultz commented 3 weeks ago

Bumping. This feature would great as we are trying to replicate a real-world form within the data grid, and it has extreme row nesting under parent call values to aggregate the children under the same group.

Would anyone from the team be willing to drop some thoughts about how this would be implemented if someone from the community would like to work on a PR? @flaviendelangle @joserodolfofreitas

jeffreyschultz commented 2 weeks ago

@flaviendelangle @joserodolfofreitas

Is there someone that I need to email or call because I pay for the premium license, and for my comment to not even so much as get a response is not acceptable.

joserodolfofreitas commented 1 week ago

@jeffreyschultz, I will reach out to arrange a short user interview. We'd love to better understand your use case.

@Katsuchiyo, we're wrapping up pivoting, and after that, we'll tackle Row spanning, so we're loosely talking about the possibility of releasing it next quarter (Q3 2024).

jeffreyschultz commented 5 days ago

@joserodolfofreitas

I believe that my use case is a bit more advanced than just row spanning, but it is needed none the less. Here is an excel mockup of a current process artifact that is captured within the security field. We are attempting to convert a manual process that is captured on paper into a more automated workflow, and are attempting to replicate the original form as much as possible to ease adoption.

image

You will notice that Event aggregates Indicator, and Indicator aggregates Action. Every Action is essentially its own row (includes Est. Location, Start Time, End Time, Assignment, and Act. Location), however, they are nested under their parent which groups them together. The odd column you will probably notice is Decision, and this is scoped to the entire Indicator--a specific decision needs to be made once an Indicator has been confirmed.

We also dynamically build the columns under Assets based on what is available to that team. So the number of columns is determined by backing data elsewhere in the app.

I believe that the following is beyond the scope of row spanning, however, I am providing it for completeness to give you better insight into what we would be trying to achieve.

  1. We want to provide the ability to directly add/remove new Event, Indicator, and Action rows within this grid, which almost seems as though a tree data structure would be best for easier management of the backing data.

  2. We want to support drag and drop of nested Indicator and Action rows to new parents; in the event of Indicator, that would be another Event, and for Action, that would be another Indicator.

  3. It would be great if sorting honored the nesting of the rows, so that Action rows sorted under its' Indicator, and Indicator rows sorted under its' Event.

Can this visual design be easily achieved with what is available in the Data Grid at this time? If so, would you be able to point me to someone that could provide some advice?

vladyslav-n commented 3 days ago

Upvoting

joserodolfofreitas commented 3 days ago

@jeffreyschultz, thank you very much for sharing your use case!

  1. We want to provide the ability to directly add/remove new Event, Indicator, and Action rows within this grid, which almost seems as though a tree data structure would be best for easier management of the backing data.

We initially thought about the idea that row spanning is reflected in the data with repeated values on each row, like in the following example:

x-ray-rowspanning

But we may indeed need a way to define the hierarchy of cells to support your following described scenarios.

  1. We want to support drag and drop of nested Indicator and Action rows to new parents; in the event of Indicator, that would be another Event, and for Action, that would be another Indicator.

That's an interesting use case, unfortunately, outside the scope of the initial version, but we'll keep an eye out for a workaround (It's a tough one though).

  1. It would be great if sorting honored the nesting of the rows, so that Action rows sorted under its' Indicator, and Indicator rows sorted under its' Event.

That's also an interesting use case. We're not planning to constrain sorting like this by default, but we can likely provide a recipe using a custom comparator.

Can this visual design be easily achieved with what is available in the Data Grid at this time? If so, would you be able to point me to someone that could provide some advice?

That's not supported at this time, and although Row spanning is one of the highest priorities for the next quarter, I'm afraid the initial version won't have out-of-the-box support for these most advanced use cases based on a defined hierarchy. Even the bolder borders on the created groups might be challenging. But as mentioned before, we'll try to find workarounds within the initial implementation so your use case can be unblocked. And we'll certainly consider a follow-up to support such use cases out-of-the-box. Thanks again for sharing it.

jeffreyschultz commented 3 days ago

@jeffreyschultz, thank you very much for sharing your use case!

  1. We want to provide the ability to directly add/remove new Event, Indicator, and Action rows within this grid, which almost seems as though a tree data structure would be best for easier management of the backing data.

We initially thought about the idea that row spanning is reflected in the data with repeated values on each row, like in the following example:

Yeah, that was one of my thoughts as well. It would certainly make it easier from your side to handle that. You mark which columns are to group, and then the cell renders a rowspan attribute for that number of rows along with ensuring the sort brings those rows together.

It seems to me that a combination of styling changes, row grouping, and row spanning could possibly get me most of the way there? The row grouping layout is different than what I am looking for, but is it possible change the rendering to something more like this? Instead of a dropdown, you get a row spanned cell?

joserodolfofreitas commented 3 days ago

It seems to me that a combination of styling changes, row grouping, and row spanning could possibly get me most of the way there? The row grouping layout is different than what I am looking for, but is it possible change the rendering to something more like this? Instead of a dropdown, you get a row spanned cell?

@jeffreyschultz, yeah, maybe you can use multiple grouping columns. Now, honestly, I think it seems close enough, but it's deceivingly hard to move from the drop-down to the row-spanning display. We'll discuss some alternatives and let you know.

We can keep the discussion about this use case on https://github.com/mui/mui-x/issues/13646.