Fix: row indices for Grouped DetailsList and GroupedList to improve a11y experience#17591
Fix: row indices for Grouped DetailsList and GroupedList to improve a11y experience#17591TristanWatanabe merged 37 commits intomicrosoft:masterfrom
Conversation
…d correct offset is passed to DetailsRow which accounts for GroupHeader
…-posinset for GroupedList
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit bb0faa8:
|
Perf Analysis (
|
| Scenario | Render type | Master Ticks | PR Ticks | Iterations | Status |
|---|---|---|---|---|---|
| Avatar | mount | 865 | 918 | 5000 | |
| BaseButton | mount | 865 | 902 | 5000 | |
| Breadcrumb | mount | 2579 | 2605 | 1000 | |
| ButtonNext | mount | 529 | 535 | 5000 | |
| Checkbox | mount | 1540 | 1498 | 5000 | |
| CheckboxBase | mount | 1264 | 1266 | 5000 | |
| ChoiceGroup | mount | 4690 | 4657 | 5000 | |
| ComboBox | mount | 981 | 970 | 1000 | |
| CommandBar | mount | 9902 | 9942 | 1000 | |
| ContextualMenu | mount | 5971 | 5974 | 1000 | |
| DefaultButton | mount | 1086 | 1123 | 5000 | |
| DetailsRow | mount | 3628 | 3650 | 5000 | |
| DetailsRowFast | mount | 3603 | 3729 | 5000 | |
| DetailsRowNoStyles | mount | 3347 | 3458 | 5000 | |
| Dialog | mount | 1442 | 1419 | 1000 | |
| DocumentCardTitle | mount | 139 | 147 | 1000 | |
| Dropdown | mount | 3162 | 3188 | 5000 | |
| FocusTrapZone | mount | 1775 | 1786 | 5000 | |
| FocusZone | mount | 1753 | 1774 | 5000 | |
| IconButton | mount | 1716 | 1722 | 5000 | |
| Label | mount | 331 | 320 | 5000 | |
| Layer | mount | 1768 | 1730 | 5000 | |
| Link | mount | 459 | 455 | 5000 | |
| MakeStyles | mount | 1802 | 1790 | 50000 | |
| MenuButton | mount | 1422 | 1446 | 5000 | |
| MessageBar | mount | 1998 | 1966 | 5000 | |
| Nav | mount | 3116 | 3203 | 1000 | |
| OverflowSet | mount | 1021 | 998 | 5000 | |
| Panel | mount | 1395 | 1388 | 1000 | |
| Persona | mount | 800 | 809 | 1000 | |
| Pivot | mount | 1389 | 1368 | 1000 | |
| PrimaryButton | mount | 1258 | 1245 | 5000 | |
| Rating | mount | 7538 | 7501 | 5000 | |
| SearchBox | mount | 1281 | 1274 | 5000 | |
| Shimmer | mount | 2494 | 2488 | 5000 | |
| Slider | mount | 1936 | 1930 | 5000 | |
| SpinButton | mount | 4859 | 4878 | 5000 | |
| Spinner | mount | 414 | 413 | 5000 | |
| SplitButton | mount | 3066 | 3088 | 5000 | |
| Stack | mount | 489 | 493 | 5000 | |
| StackWithIntrinsicChildren | mount | 1557 | 1516 | 5000 | |
| StackWithTextChildren | mount | 4463 | 4415 | 5000 | |
| SwatchColorPicker | mount | 9919 | 10009 | 5000 | |
| Tabs | mount | 1367 | 1370 | 1000 | |
| TagPicker | mount | 2390 | 2377 | 5000 | |
| TeachingBubble | mount | 11722 | 11702 | 5000 | |
| Text | mount | 421 | 412 | 5000 | |
| TextField | mount | 1349 | 1330 | 5000 | |
| ThemeProvider | mount | 1185 | 1196 | 5000 | |
| ThemeProvider | virtual-rerender | 593 | 587 | 5000 | |
| ThemeProviderNext | mount | 9005 | 9090 | 5000 | |
| Toggle | mount | 807 | 777 | 5000 | |
| buttonNative | mount | 111 | 114 | 5000 |
Perf Analysis (@fluentui/react-northstar)
Perf tests with no regressions
| Scenario | Current PR Ticks | Baseline Ticks | Ratio |
|---|---|---|---|
| ButtonMinimalPerf.default | 182 | 158 | 1.15:1 |
| PortalMinimalPerf.default | 168 | 155 | 1.08:1 |
| ChatDuplicateMessagesPerf.default | 291 | 274 | 1.06:1 |
| RefMinimalPerf.default | 246 | 233 | 1.06:1 |
| AvatarMinimalPerf.default | 200 | 191 | 1.05:1 |
| GridMinimalPerf.default | 334 | 319 | 1.05:1 |
| ButtonSlotsPerf.default | 552 | 529 | 1.04:1 |
| ChatMinimalPerf.default | 604 | 581 | 1.04:1 |
| FlexMinimalPerf.default | 284 | 272 | 1.04:1 |
| HeaderMinimalPerf.default | 351 | 338 | 1.04:1 |
| LabelMinimalPerf.default | 380 | 364 | 1.04:1 |
| ReactionMinimalPerf.default | 371 | 360 | 1.03:1 |
| TableMinimalPerf.default | 401 | 389 | 1.03:1 |
| TextMinimalPerf.default | 349 | 340 | 1.03:1 |
| TextAreaMinimalPerf.default | 481 | 466 | 1.03:1 |
| BoxMinimalPerf.default | 354 | 346 | 1.02:1 |
| ChatWithPopoverPerf.default | 363 | 356 | 1.02:1 |
| HeaderSlotsPerf.default | 747 | 735 | 1.02:1 |
| ListMinimalPerf.default | 502 | 494 | 1.02:1 |
| PopupMinimalPerf.default | 714 | 702 | 1.02:1 |
| SkeletonMinimalPerf.default | 359 | 351 | 1.02:1 |
| ToolbarMinimalPerf.default | 917 | 896 | 1.02:1 |
| AlertMinimalPerf.default | 259 | 256 | 1.01:1 |
| AnimationMinimalPerf.default | 397 | 395 | 1.01:1 |
| AttachmentMinimalPerf.default | 153 | 151 | 1.01:1 |
| ButtonOverridesMissPerf.default | 1671 | 1659 | 1.01:1 |
| ButtonUseCssPerf.default | 780 | 772 | 1.01:1 |
| CardMinimalPerf.default | 536 | 531 | 1.01:1 |
| InputMinimalPerf.default | 1253 | 1242 | 1.01:1 |
| LayoutMinimalPerf.default | 355 | 350 | 1.01:1 |
| MenuButtonMinimalPerf.default | 1560 | 1537 | 1.01:1 |
| ProviderMergeThemesPerf.default | 1672 | 1660 | 1.01:1 |
| SliderMinimalPerf.default | 1586 | 1577 | 1.01:1 |
| SplitButtonMinimalPerf.default | 3701 | 3653 | 1.01:1 |
| TreeMinimalPerf.default | 776 | 768 | 1.01:1 |
| AttachmentSlotsPerf.default | 1125 | 1124 | 1:1 |
| ButtonUseCssNestingPerf.default | 1045 | 1045 | 1:1 |
| CheckboxMinimalPerf.default | 2686 | 2680 | 1:1 |
| DatepickerMinimalPerf.default | 5353 | 5334 | 1:1 |
| DialogMinimalPerf.default | 726 | 728 | 1:1 |
| DividerMinimalPerf.default | 347 | 348 | 1:1 |
| EmbedMinimalPerf.default | 4078 | 4073 | 1:1 |
| FormMinimalPerf.default | 391 | 390 | 1:1 |
| ImageMinimalPerf.default | 363 | 364 | 1:1 |
| ItemLayoutMinimalPerf.default | 1227 | 1233 | 1:1 |
| LoaderMinimalPerf.default | 681 | 679 | 1:1 |
| StatusMinimalPerf.default | 657 | 660 | 1:1 |
| CustomToolbarPrototype.default | 3757 | 3749 | 1:1 |
| VideoMinimalPerf.default | 617 | 614 | 1:1 |
| AccordionMinimalPerf.default | 145 | 146 | 0.99:1 |
| DropdownManyItemsPerf.default | 670 | 679 | 0.99:1 |
| ListNestedPerf.default | 542 | 547 | 0.99:1 |
| MenuMinimalPerf.default | 840 | 847 | 0.99:1 |
| ProviderMinimalPerf.default | 979 | 990 | 0.99:1 |
| TableManyItemsPerf.default | 1836 | 1851 | 0.99:1 |
| TooltipMinimalPerf.default | 939 | 950 | 0.99:1 |
| CarouselMinimalPerf.default | 444 | 453 | 0.98:1 |
| DropdownMinimalPerf.default | 2987 | 3034 | 0.98:1 |
| RadioGroupMinimalPerf.default | 412 | 419 | 0.98:1 |
| SegmentMinimalPerf.default | 340 | 351 | 0.97:1 |
| IconMinimalPerf.default | 595 | 614 | 0.97:1 |
| TreeWith60ListItems.default | 175 | 181 | 0.97:1 |
| ListCommonPerf.default | 605 | 629 | 0.96:1 |
| RosterPerf.default | 1107 | 1151 | 0.96:1 |
| ListWith60ListItems.default | 589 | 628 | 0.94:1 |
Asset size changes
Baseline commit: 8c3a5aa1d2c24b7bb08d688180abbd80979e99e7 (build) |
smhigley
left a comment
There was a problem hiding this comment.
Good job wrangling the weird groupedlist/detailslist interconnectivity 😄. There's one issue with how you're calculating posinset and setsize for GroupedList rows related to how you're getting the group variable, but other than that I like the approach :).
|
@ThomasMichon Totally understandable - I'll try to find another approach |
…enderGroupCell for consumers to use
… to calculate correct index for GroupedDetailsList
…nSet and ariaSetSize
…aSetSize based on group
|
🎉 Handy links: |
|
🎉 Handy links: |
…11y experience (microsoft#17591) * GroupedDetailsList will now have correct row-index for GroupHeader and correct offset is passed to DetailsRow which accounts for GroupHeader * DetailsRow now takes groups as a prop which is used to determine aria-posinset for GroupedList * updated GroupedList examples to pass groups prop to DetailsRow * updated react api file * updated detailsrow documentationa and minor fix * updated react snapshots * updated react examples snapshots * Change files * updated change file * minor * add aria-rowindex attribute to GroupedHeader.base * updated react snapshots * comment cleanup * fix: build errors * fix: build error * added missing dependency * fix CI error * getItemGroup now returns the row item's exact group * remove first for-of loop in getItemGroup * fix CI error * update getItemGroup to remove ! operator * update getTotalRowCount to remove ! operator * update DetailsRow props * remove aria-posinset calculation from DetailsRow * ariaPosinSet and ariaSetSize are now passed in return function of onRenderGroupCell for consumers to use * update GroupedList examples topass ariaPosInSet & ariaSetSize to DetailsRow * update api * ci fix * add useGroupedDetailsListIndexMap for O(1) lookup of helper variables to calculate correct index for GroupedDetailsList * GroupedListSection now passes group to onRenderCell, removes ariaPosInSet and ariaSetSize * DetailsRow now accepts group prop and calculates ariaPosInSet and ariaSetSize based on group * update GroupedList examples to pass group prop to DetailsRow * update API * update DetailsRow type documentation and ci fix * ci fix
| ? (groupHeaderProps: IGroupDividerProps, defaultRender?: IRenderFunction<IGroupDividerProps>) => { | ||
| const { ariaPosInSet, ariaSetSize } = groupHeaderProps; | ||
| const { groupIndex } = groupHeaderProps; | ||
| const groupKey: string | undefined = groups && groupIndex !== undefined ? groups[groupIndex].key : undefined; |
There was a problem hiding this comment.
Hello,
my app throws an error here:
TypeError: Cannot read property 'key' of undefined
(anonymous function)
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/components/DetailsList/DetailsList.base.tsx:365
362 | return onRenderDetailsGroupHeader
363 | ? (groupHeaderProps: IGroupDividerProps, defaultRender?: IRenderFunction) => {
364 | const { groupIndex } = groupHeaderProps;
365 | const groupKey: string | undefined = groups && groupIndex !== undefined ? groups[groupIndex].key : undefined;
| ^ 366 | const totalRowCount: number =
367 | groupKey !== undefined && groupedDetailsListIndexMap[groupKey]
368 | ? groupedDetailsListIndexMap[groupKey].totalRowCount
View compiled
GroupedListSection.render
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/components/GroupedList/GroupedListSection.tsx:246
243 | return (
244 | <div
245 | ref={this._root}
246 | {...(isDraggable && { draggable: true })}
| ^ 247 | className={css(groupedListClassNames && groupedListClassNames.group, this._getDroppingClassName())}
248 | role="presentation"
249 | >
View compiled
▼ 19 stack frames were expanded.
finishClassComponent
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:17485
updateClassComponent
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:17435
beginWork
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:19073
HTMLUnknownElement.callCallback
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:3945
invokeGuardedCallbackDev
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:3994
invokeGuardedCallback
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:4056
beginWork$1
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:23964
performUnitOfWork
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:22776
workLoopSync
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:22707
renderRootSync
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:22670
performSyncWorkOnRoot
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:22293
(anonymous function)
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:11327
unstable_runWithPriority
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/scheduler/cjs/scheduler.development.js:468
runWithPriority$1
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:11276
flushSyncCallbackQueueImpl
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:11322
flushSyncCallbackQueue
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:11309
discreteUpdates$1
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:22420
discreteUpdates
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:3756
dispatchDiscreteEvent
C:/Dev/BRZ365.Viewer3D/BRZ365.Viewer3D.WebApplication/ClientApp/node_modules/react-dom/cjs/react-dom.development.js:5889
▲ 19 stack frames were expanded.
I use groups with childrens
…11y experience (microsoft#17591) * GroupedDetailsList will now have correct row-index for GroupHeader and correct offset is passed to DetailsRow which accounts for GroupHeader * DetailsRow now takes groups as a prop which is used to determine aria-posinset for GroupedList * updated GroupedList examples to pass groups prop to DetailsRow * updated react api file * updated detailsrow documentationa and minor fix * updated react snapshots * updated react examples snapshots * Change files * updated change file * minor * add aria-rowindex attribute to GroupedHeader.base * updated react snapshots * comment cleanup * fix: build errors * fix: build error * added missing dependency * fix CI error * getItemGroup now returns the row item's exact group * remove first for-of loop in getItemGroup * fix CI error * update getItemGroup to remove ! operator * update getTotalRowCount to remove ! operator * update DetailsRow props * remove aria-posinset calculation from DetailsRow * ariaPosinSet and ariaSetSize are now passed in return function of onRenderGroupCell for consumers to use * update GroupedList examples topass ariaPosInSet & ariaSetSize to DetailsRow * update api * ci fix * add useGroupedDetailsListIndexMap for O(1) lookup of helper variables to calculate correct index for GroupedDetailsList * GroupedListSection now passes group to onRenderCell, removes ariaPosInSet and ariaSetSize * DetailsRow now accepts group prop and calculates ariaPosInSet and ariaSetSize based on group * update GroupedList examples to pass group prop to DetailsRow * update API * update DetailsRow type documentation and ci fix * ci fix
…11y experience (microsoft#17591) * GroupedDetailsList will now have correct row-index for GroupHeader and correct offset is passed to DetailsRow which accounts for GroupHeader * DetailsRow now takes groups as a prop which is used to determine aria-posinset for GroupedList * updated GroupedList examples to pass groups prop to DetailsRow * updated react api file * updated detailsrow documentationa and minor fix * updated react snapshots * updated react examples snapshots * Change files * updated change file * minor * add aria-rowindex attribute to GroupedHeader.base * updated react snapshots * comment cleanup * fix: build errors * fix: build error * added missing dependency * fix CI error * getItemGroup now returns the row item's exact group * remove first for-of loop in getItemGroup * fix CI error * update getItemGroup to remove ! operator * update getTotalRowCount to remove ! operator * update DetailsRow props * remove aria-posinset calculation from DetailsRow * ariaPosinSet and ariaSetSize are now passed in return function of onRenderGroupCell for consumers to use * update GroupedList examples topass ariaPosInSet & ariaSetSize to DetailsRow * update api * ci fix * add useGroupedDetailsListIndexMap for O(1) lookup of helper variables to calculate correct index for GroupedDetailsList * GroupedListSection now passes group to onRenderCell, removes ariaPosInSet and ariaSetSize * DetailsRow now accepts group prop and calculates ariaPosInSet and ariaSetSize based on group * update GroupedList examples to pass group prop to DetailsRow * update API * update DetailsRow type documentation and ci fix * ci fix
* cherry-pick: GroupedList: fix virtualization (unstable preview) (#24460) * GroupedList: add new version to address virtualization issues Introduces a new component, GroupedListV2, that is a drop-in replacement for GroupedList. GroupedListV2 addresses a bug with the virtualization implementation in GroupedList. As it is a significant re-write of the internals we've decided to make it a new component so users can opt in to the new component/behavior as needed rather than risk significant breakage with the existing GroupedList implementation. --- Virtualization in GroupedList is powered by List and groups in GroupedList are nested Lists. When nested with two or more levels of groups issues can arise with virtualization that result in the vertical size of the Lists being miscalculated resulting in items not rendering, the scrollbar repeatedly resizing (causing the list to "jump" about), or both. List does work asynchronously which contributes to the issue itself and makes debugging practically impossible as even a simple GroupedList will contain many Lists all of which are virtualized and rendering async. To address this issue we are introducing GroupedListV2 which is a drop-in replacement for GropedList (V1) as it adheres to the same API. Internally GroupedListV2 flattens virtualization into a single List eliminating the virtualization bug described above and making the list easier to reason about and debug. * List: add conditional rendering option Adds support to conditionally render cells in List which helps when rendering flattend GroupedLists as we don't really know if we need to render certain parts of the list (e.g., footers) until we call the render function. Ensure GroupedList <--> GroupedListV2 compatibility. * DetailsList: allow for custom GroupedList renderer This change allows users to provide a custom GroupedList renderer like GroupedListV2. * Update @fluentui/react API snapshot Add GroupedListV2 tests Add DetailsList tests A dd support for ungrouped lists * add perf tests for groupedlist/groupedlistv2 * change files * better types and refactor render functions. * refactor grouped items * typescript * WIP debugging * fix issues from tests - Add proper `getKey()` handling. - Remove selection dependency for "show all" and footer rendering. * Mark GroupedListV2 as unstable * groupedlistv2: update naming - Rename to GroupedListV2_unstable - Update tests to use this name * update api snapshot * update groupedlistv2 import for perf-test * update snapshots * pr feedback * update test snapshot * fix issues in DetailsList * fix type and build errors * fix types * fix build errors * Change files * update import package name for perf tests * Fix: row indices for Grouped DetailsList and GroupedList to improve a11y experience (#17591) * GroupedDetailsList will now have correct row-index for GroupHeader and correct offset is passed to DetailsRow which accounts for GroupHeader * DetailsRow now takes groups as a prop which is used to determine aria-posinset for GroupedList * updated GroupedList examples to pass groups prop to DetailsRow * updated react api file * updated detailsrow documentationa and minor fix * updated react snapshots * updated react examples snapshots * Change files * updated change file * minor * add aria-rowindex attribute to GroupedHeader.base * updated react snapshots * comment cleanup * fix: build errors * fix: build error * added missing dependency * fix CI error * getItemGroup now returns the row item's exact group * remove first for-of loop in getItemGroup * fix CI error * update getItemGroup to remove ! operator * update getTotalRowCount to remove ! operator * update DetailsRow props * remove aria-posinset calculation from DetailsRow * ariaPosinSet and ariaSetSize are now passed in return function of onRenderGroupCell for consumers to use * update GroupedList examples topass ariaPosInSet & ariaSetSize to DetailsRow * update api * ci fix * add useGroupedDetailsListIndexMap for O(1) lookup of helper variables to calculate correct index for GroupedDetailsList * GroupedListSection now passes group to onRenderCell, removes ariaPosInSet and ariaSetSize * DetailsRow now accepts group prop and calculates ariaPosInSet and ariaSetSize based on group * update GroupedList examples to pass group prop to DetailsRow * update API * update DetailsRow type documentation and ci fix * ci fix * fix tests * remove change file * update perf-test dependencies * fix build errors in react-examples * fix imports in doc site * fix path in react-examples * fix imports in example * update list implementation GroupedListV2 depends on some updates to List that were not present in the v7 branch. These List changes broke some DetailsList tests so those have been updated as well. * update API snapshot * change perf-test parameters for groupedlist * clean up perf-test settings * Change files * remove unneeded change files Co-authored-by: Tristan <tristan.watanabe@gmail.com>
Pull request checklist
$ yarn changeDescription of changes
Grouped DetailsList will now follow a linear aria-rowindexing (1 - total number of rows)
useGroupedDetailsListIndexMapfunction which initializes a mapping of each group'skeyand an object value oftotalRowCountandnumOfGroupHeadersBeforeItemwhich are used to help calculate each row's index. The resultinggroupedDetailsListIndexMapmapping it returns allows for constant time lookup when determining each row'saria-rowindex.GroupedList will now have the correct
aria-posinsetandaria-setsizefor each row itemDetailsRownow accepts agroupprop which is used in conjunction with calculating the correctaria-posinsetandaria-setsizefor a row in aGroupedList. Whengroupis passed toDetailsRow, the attributesaria-posinsetandaria-setsizeare automatically added to the row.GroupedListSectionnow provides consumers (via the_onRenderGroupCellfunction) thegroupeach row item belongs to which they can pass as prop toDetailsRowin theonRenderCellfunction they provide. This is also used byonRenderCellinDetailsListin order to help with lookup in thegroupedDetailsListIndexMapmapping forGroupedDetailsList.groupprop toDetailsRow.