diff --git a/packages/main/src/components/AnalyticalTable/hooks/useGroupBy.ts b/packages/main/src/components/AnalyticalTable/hooks/useGroupBy.ts index f6b86fd02bc..cb5187670b5 100644 --- a/packages/main/src/components/AnalyticalTable/hooks/useGroupBy.ts +++ b/packages/main/src/components/AnalyticalTable/hooks/useGroupBy.ts @@ -24,6 +24,7 @@ actions.toggleGroupBy = 'toggleGroupBy'; * * This is a fork of react-table's `useGroupBy` with the following changes: * - Aggregate grouped columns that define an `aggregate` above their own grouping level, instead of copying the first leaf value + * - Derive `canGroupBy` from `disableGroupBy` only (no self-seed), so runtime `groupable` toggling works — like `useSortBy`/`useFilters` */ export const useGroupBy: PluginHook = (hooks: ReactTableHooks) => { hooks.getGroupByToggleProps = [defaultGetGroupByToggleProps]; @@ -154,12 +155,11 @@ function useInstance(instance: TableInstance) { column.canGroupBy = accessor ? getFirstDefined( - column.canGroupBy, columnDisableGroupBy === true ? false : undefined, disableGroupBy === true ? false : undefined, true, ) - : getFirstDefined(column.canGroupBy, defaultColumnGroupBy, defaultCanGroupBy, false); + : getFirstDefined(defaultColumnGroupBy, defaultCanGroupBy, false); if (column.canGroupBy) { column.toggleGroupBy = () => instance.toggleGroupBy(column.id); diff --git a/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.gallery.tsx b/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.gallery.tsx index 9b1fce5ae65..bf80a9cd252 100644 --- a/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.gallery.tsx +++ b/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.gallery.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import type { AnalyticalTableColumnDefinition } from '../index.js'; import { AnalyticalTable } from '../index.js'; @@ -88,3 +88,32 @@ export const GroupingAggregationHarness = () => { /> ); }; + +const toggleData = [ + { name: 'Alpha', status: 'active' }, + { name: 'Bravo', status: 'active' }, + { name: 'Charlie', status: 'inactive' }, + { name: 'Delta', status: 'active' }, + { name: 'Echo', status: 'inactive' }, +]; + +// Toggling `groupable` at runtime must flip `column.canGroupBy` so the Group/Ungroup affordance +// appears and disappears accordingly. +export const GroupableRuntimeToggleHarness = ({ initialGroupable = false }: { initialGroupable?: boolean }) => { + const [groupable, setGroupable] = useState(initialGroupable); + const columns = useMemo( + () => [ + { Header: 'Name', accessor: 'name', width: 200 }, + { Header: 'Status', accessor: 'status', width: 200 }, + ], + [], + ); + return ( + <> + + + + ); +}; diff --git a/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.spec.tsx b/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.spec.tsx index 0ba592830d7..71a414c89fc 100644 --- a/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.spec.tsx +++ b/packages/main/src/components/AnalyticalTable/test/AnalyticalTableGrouping.spec.tsx @@ -1,7 +1,13 @@ +import type { Page } from '@playwright/test'; import { expect, test } from '../../../../../../playwright/fixtures/gallery-fixtures.js'; -import type { GroupingAggregationHarness } from './AnalyticalTableGrouping.gallery.js'; +import type { GroupableRuntimeToggleHarness, GroupingAggregationHarness } from './AnalyticalTableGrouping.gallery.js'; const STORY = 'AnalyticalTableGrouping/GroupingAggregationHarness'; +const TOGGLE_STORY = 'AnalyticalTableGrouping/GroupableRuntimeToggleHarness'; + +const listItem = (page: Page, text: string) => page.locator(`[ui5-li][text="${text}"]`); +const popover = (page: Page) => page.locator('[data-component-name="ATHeaderPopover"]'); +const openHeaderPopover = (page: Page, text: string) => page.getByText(text, { exact: true }).click(); test.describe('AnalyticalTable', () => { test('grouped column is aggregated on ancestor group rows', async ({ mount, page }) => { @@ -21,4 +27,25 @@ test.describe('AnalyticalTable', () => { await expect(enUs).toHaveAttribute('data-agg-status', 'finished'); await expect(enUs).toHaveText('all finished'); }); + + test('runtime groupable toggle', async ({ mount, page }) => { + await mount(TOGGLE_STORY, { initialGroupable: false }); + + // Grouping is the only header option, so while disabled the header has no popover at all. + await openHeaderPopover(page, 'Status'); + await expect(popover(page)).toHaveCount(0); + + // Enable at runtime → the popover with the Group item appears, and grouping applies. + await page.getByTestId('toggle-groupable').click(); + await openHeaderPopover(page, 'Status'); + await expect(listItem(page, 'Group')).toBeVisible(); + await listItem(page, 'Group').click(); + await expect(page.getByText('active (3)', { exact: true })).toBeVisible(); + await expect(page.getByText('inactive (2)', { exact: true })).toBeVisible(); + + // Disable at runtime → with no other option left, the header popover is gone again. + await page.getByTestId('toggle-groupable').click(); + await openHeaderPopover(page, 'Status'); + await expect(popover(page)).toHaveCount(0); + }); });