@redsift/ds-mcp-server 12.5.3-muiv6 → 12.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/demos/patterns/_shared/StateDebugPanel.tsx +2 -2
- package/data/demos/patterns/_shared/columns.tsx +12 -3
- package/data/demos/patterns/_shared/defaults.ts +1 -1
- package/data/demos/patterns/_shared/filter-helpers.ts +1 -1
- package/data/demos/patterns/_shared/helpers.tsx +1 -1
- package/data/demos/patterns/_shared/server-logic.ts +1 -1
- package/data/demos/patterns/_shared/story-helpers.ts +106 -22
- package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +1 -18
- package/data/demos/patterns/crossfiltered-datagrid-server-side/CrossfilteredDatagridServerSide.interaction.stories.tsx +1 -1
- package/data/demos/patterns/crossfiltered-datagrid-server-side/example.tsx +10 -10
- package/data/demos/patterns/drilldowned-datagrid-client-side/example.tsx +1 -1
- package/data/demos/patterns/drilldowned-datagrid-server-side/example.tsx +1 -1
- package/data/demos/patterns/single-datagrid-client-side/SingleDatagridClientSide.interaction.stories.tsx +1 -1
- package/data/demos/patterns/single-datagrid-client-side/example.tsx +4 -4
- package/data/demos/patterns/single-datagrid-server-side/SingleDatagridServerSide.interaction.stories.tsx +1 -1
- package/data/demos/patterns/single-datagrid-server-side/example.tsx +4 -4
- package/data/demos/patterns/stateful-single-datagrid-client-side/StatefulSingleDatagridClientSide.interaction.stories.tsx +129 -1
- package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +6 -5
- package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +134 -1
- package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +6 -5
- package/data/demos/patterns/tabbed-datagrid-server-side/example.tsx +1 -1
- package/data/docs/components/dashboard/Dashboard.json +2 -2
- package/data/docs/components/table/DataGrid.json +6 -6
- package/data/docs/components/table/GridToolbarFilterSemanticField.json +1 -1
- package/data/docs/components/table/StatefulDataGrid.json +6 -6
- package/data/docs/components/table/Toolbar.json +8 -2
- package/data/docs/components.json +25 -19
- package/data/docs/llms-full.txt +46 -44
- package/data/docs/llms.txt +4 -4
- package/data/docs/patterns-catalog.md +24 -25
- package/data/docs/patterns.json +4 -4
- package/data/metadata.json +2 -2
- package/data/patterns/crossfiltered-datagrid-server-side.mdx +1 -1
- package/data/patterns/drilldowned-datagrid-client-side.mdx +1 -1
- package/data/patterns/drilldowned-datagrid-server-side.mdx +1 -1
- package/data/patterns/single-datagrid-client-side.mdx +7 -7
- package/data/patterns/single-datagrid-server-side.mdx +4 -4
- package/data/patterns/stateful-single-datagrid-client-side.mdx +36 -21
- package/data/patterns/stateful-single-datagrid-server-side.mdx +46 -18
- package/data/patterns/tabbed-datagrid-server-side.mdx +1 -1
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { GridApiPremium } from '@mui/x-data-grid-premium';
|
|
3
3
|
|
|
4
4
|
// localStorage key categories — must match @redsift/table internals
|
|
5
5
|
const LS_CATEGORIES = [
|
|
@@ -13,7 +13,7 @@ const LS_CATEGORIES = [
|
|
|
13
13
|
];
|
|
14
14
|
|
|
15
15
|
interface StateDebugPanelProps {
|
|
16
|
-
apiRef: React.MutableRefObject<
|
|
16
|
+
apiRef: React.MutableRefObject<GridApiPremium | null>;
|
|
17
17
|
useRouter: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
|
|
18
18
|
localStorageVersion?: number;
|
|
19
19
|
}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { createColumn, TextCell } from '@redsift/table';
|
|
3
3
|
import { Flexbox, Icon, IconButtonLink, Pill } from '@redsift/design-system';
|
|
4
4
|
import { mdiArrowRight, mdiCheck, mdiClose } from '@redsift/icons';
|
|
5
|
-
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid-
|
|
5
|
+
import { GridColDef, GridRenderCellParams } from '@mui/x-data-grid-premium';
|
|
6
6
|
import { Row } from './data';
|
|
7
7
|
|
|
8
8
|
// -- Option constants -------------------------------------------------------
|
|
@@ -80,6 +80,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
80
80
|
field: 'Items',
|
|
81
81
|
headerName: 'Item',
|
|
82
82
|
flex: 1,
|
|
83
|
+
display: 'flex',
|
|
83
84
|
...createColumn('string'),
|
|
84
85
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value}</TextCell>,
|
|
85
86
|
},
|
|
@@ -88,6 +89,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
88
89
|
field: 'Category',
|
|
89
90
|
headerName: 'Category',
|
|
90
91
|
width: 120,
|
|
92
|
+
display: 'flex',
|
|
91
93
|
...createColumn('singleSelect'),
|
|
92
94
|
valueOptions: CATEGORY_OPTIONS,
|
|
93
95
|
renderCell: ({ value }: GridRenderCellParams) => <Pill color={categoryColor(value)}>{value}</Pill>,
|
|
@@ -97,6 +99,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
97
99
|
field: 'Paid',
|
|
98
100
|
headerName: 'Price',
|
|
99
101
|
width: 100,
|
|
102
|
+
display: 'flex',
|
|
100
103
|
...createColumn('number'),
|
|
101
104
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{formatCurrency(value as number)}</TextCell>,
|
|
102
105
|
},
|
|
@@ -105,8 +108,9 @@ export const columns: GridColDef<Row>[] = [
|
|
|
105
108
|
field: 'Date',
|
|
106
109
|
headerName: 'Date',
|
|
107
110
|
width: 140,
|
|
111
|
+
display: 'flex',
|
|
108
112
|
...createColumn('date'),
|
|
109
|
-
valueGetter: (
|
|
113
|
+
valueGetter: (value: string) => parseDate(value),
|
|
110
114
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDate(value as Date) : '—'}</TextCell>,
|
|
111
115
|
},
|
|
112
116
|
// DateTime
|
|
@@ -114,8 +118,9 @@ export const columns: GridColDef<Row>[] = [
|
|
|
114
118
|
field: 'DateTime',
|
|
115
119
|
headerName: 'Date & Time',
|
|
116
120
|
width: 180,
|
|
121
|
+
display: 'flex',
|
|
117
122
|
...createColumn('dateTime'),
|
|
118
|
-
valueGetter: (
|
|
123
|
+
valueGetter: (value: string) => parseDate(value),
|
|
119
124
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDateTime(value as Date) : '—'}</TextCell>,
|
|
120
125
|
},
|
|
121
126
|
// Boolean — in stock
|
|
@@ -123,6 +128,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
123
128
|
field: 'InStock',
|
|
124
129
|
headerName: 'In Stock',
|
|
125
130
|
width: 90,
|
|
131
|
+
display: 'flex',
|
|
126
132
|
type: 'boolean',
|
|
127
133
|
renderCell: ({ value }: GridRenderCellParams) =>
|
|
128
134
|
value ? (
|
|
@@ -136,6 +142,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
136
142
|
field: 'Allergens',
|
|
137
143
|
headerName: 'Allergens',
|
|
138
144
|
flex: 1,
|
|
145
|
+
display: 'flex',
|
|
139
146
|
...createColumn('multiSelect'),
|
|
140
147
|
valueOptions: ALLERGEN_OPTIONS,
|
|
141
148
|
sortable: false,
|
|
@@ -158,6 +165,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
158
165
|
field: 'Tags',
|
|
159
166
|
headerName: 'Tags',
|
|
160
167
|
flex: 1,
|
|
168
|
+
display: 'flex',
|
|
161
169
|
...createColumn('tags'),
|
|
162
170
|
valueOptions: TAG_OPTIONS,
|
|
163
171
|
sortable: false,
|
|
@@ -180,6 +188,7 @@ export const columns: GridColDef<Row>[] = [
|
|
|
180
188
|
field: 'actions',
|
|
181
189
|
headerName: '',
|
|
182
190
|
width: 56,
|
|
191
|
+
display: 'flex',
|
|
183
192
|
hideable: false,
|
|
184
193
|
sortable: false,
|
|
185
194
|
filterable: false,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-
|
|
1
|
+
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
|
|
2
2
|
import { Row, allRows } from './data';
|
|
3
3
|
import { Aggregates, computeAggregates, applyFilters } from './filter-helpers';
|
|
4
4
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRef, useState } from 'react';
|
|
2
|
-
import { within, waitFor, userEvent } from '@storybook/testing-library';
|
|
2
|
+
import { within, waitFor, userEvent, fireEvent } from '@storybook/testing-library';
|
|
3
3
|
import { expect } from '@storybook/jest';
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
@@ -366,13 +366,19 @@ export const clickHeaderCheckbox = async (canvasElement: HTMLElement) => {
|
|
|
366
366
|
|
|
367
367
|
/** Click a row checkbox by row index (0-based, within the visible page). */
|
|
368
368
|
export const clickRowCheckbox = async (canvasElement: HTMLElement, rowIndex: number) => {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
369
|
+
// Wait for BOTH the row AND its checkbox to be present.
|
|
370
|
+
// Server-side grids may render rows before checkboxes are mounted.
|
|
371
|
+
await waitFor(
|
|
372
|
+
() => {
|
|
373
|
+
const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
|
|
374
|
+
expect(rows.length).toBeGreaterThan(rowIndex);
|
|
375
|
+
const cb = rows[rowIndex].querySelector('input[type="checkbox"]');
|
|
376
|
+
expect(cb).toBeTruthy();
|
|
377
|
+
},
|
|
378
|
+
{ timeout: 5000 }
|
|
379
|
+
);
|
|
373
380
|
const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
|
|
374
|
-
const checkbox = rows[rowIndex].querySelector('input[type="checkbox"]')
|
|
375
|
-
if (!checkbox) throw new Error(`Could not find checkbox in row ${rowIndex}`);
|
|
381
|
+
const checkbox = rows[rowIndex].querySelector('input[type="checkbox"]')!;
|
|
376
382
|
await userEvent.click(checkbox);
|
|
377
383
|
// Wait for React and MUI DataGrid to process the selection change
|
|
378
384
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
@@ -946,18 +952,39 @@ export const waitForPaginationEnabled = async (canvasElement: HTMLElement, direc
|
|
|
946
952
|
|
|
947
953
|
/**
|
|
948
954
|
* Change the page size via the MUI pagination "Rows per page" select.
|
|
949
|
-
*
|
|
955
|
+
* MUI Material v7's `useSlot()` applies `.MuiTablePagination-select` to the
|
|
956
|
+
* Select wrapper, NOT the inner display div that has the `onMouseDown` handler.
|
|
957
|
+
* We target `[role="combobox"]` inside the pagination toolbar instead, which is
|
|
958
|
+
* the actual interactive element rendered by `SelectInput`.
|
|
959
|
+
* `userEvent.click` in the Storybook Playwright runner doesn't reliably
|
|
960
|
+
* trigger mouseDown on MUI Select, so we use `fireEvent.mouseDown` directly,
|
|
961
|
+
* then `userEvent.click` to select the option in the dropdown.
|
|
950
962
|
*/
|
|
951
963
|
export const changePageSize = async (canvasElement: HTMLElement, newSize: number) => {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
964
|
+
// Wait for the pagination combobox to be present
|
|
965
|
+
await waitFor(
|
|
966
|
+
() => {
|
|
967
|
+
const el = canvasElement.querySelector('.MuiTablePagination-toolbar [role="combobox"]');
|
|
968
|
+
expect(el).toBeTruthy();
|
|
969
|
+
},
|
|
970
|
+
{ timeout: 5000 }
|
|
971
|
+
);
|
|
972
|
+
|
|
973
|
+
const select = canvasElement.querySelector('.MuiTablePagination-toolbar [role="combobox"]') as HTMLElement;
|
|
974
|
+
|
|
975
|
+
// Use fireEvent.mouseDown to reliably open MUI v7 Select dropdown
|
|
976
|
+
fireEvent.mouseDown(select);
|
|
977
|
+
|
|
978
|
+
// Wait for the dropdown to render (MUI uses a portal on document.body)
|
|
979
|
+
await waitFor(
|
|
980
|
+
() => {
|
|
981
|
+
const options = document.querySelectorAll('[role="option"]');
|
|
982
|
+
expect(options.length).toBeGreaterThan(0);
|
|
983
|
+
},
|
|
984
|
+
{ timeout: 5000 }
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
const options = document.querySelectorAll('[role="option"]');
|
|
961
988
|
const target = Array.from(options).find((opt) => opt.textContent === String(newSize));
|
|
962
989
|
if (!target) throw new Error(`Could not find page size option "${newSize}"`);
|
|
963
990
|
await userEvent.click(target);
|
|
@@ -976,17 +1003,18 @@ export const openColumnsPanel = async (canvasElement: HTMLElement) => {
|
|
|
976
1003
|
await userEvent.click(btn);
|
|
977
1004
|
// Wait for the panel to appear on document.body
|
|
978
1005
|
await waitFor(() => {
|
|
979
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
1006
|
+
const panel = document.querySelector('.MuiDataGrid-columnsManagement');
|
|
980
1007
|
expect(panel).toBeTruthy();
|
|
981
1008
|
});
|
|
982
1009
|
};
|
|
983
1010
|
|
|
984
1011
|
/** Toggle a column's visibility in the columns panel by its label text. */
|
|
985
1012
|
export const toggleColumnInPanel = async (fieldLabel: string) => {
|
|
986
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
1013
|
+
const panel = document.querySelector('.MuiDataGrid-columnsManagement');
|
|
987
1014
|
if (!panel) throw new Error('Columns panel is not open');
|
|
988
|
-
|
|
989
|
-
const
|
|
1015
|
+
// MUI v8 renders each column toggle as a baseCheckbox slot with class columnsManagementRow
|
|
1016
|
+
const rows = Array.from(panel.querySelectorAll('.MuiDataGrid-columnsManagementRow'));
|
|
1017
|
+
const target = rows.find((row) => row.textContent?.includes(fieldLabel));
|
|
990
1018
|
if (!target) throw new Error(`Could not find column "${fieldLabel}" in columns panel`);
|
|
991
1019
|
const checkbox = target.querySelector('input[type="checkbox"]') as HTMLElement | null;
|
|
992
1020
|
if (!checkbox) throw new Error(`Could not find checkbox for column "${fieldLabel}"`);
|
|
@@ -998,7 +1026,7 @@ export const closeColumnsPanel = async () => {
|
|
|
998
1026
|
// Press Escape to close the panel
|
|
999
1027
|
await userEvent.keyboard('{Escape}');
|
|
1000
1028
|
await waitFor(() => {
|
|
1001
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
1029
|
+
const panel = document.querySelector('.MuiDataGrid-columnsManagement');
|
|
1002
1030
|
expect(panel).toBeFalsy();
|
|
1003
1031
|
});
|
|
1004
1032
|
};
|
|
@@ -1190,6 +1218,12 @@ interface SyncAssertionOptions {
|
|
|
1190
1218
|
checkDensity?: boolean;
|
|
1191
1219
|
/** Whether to check column order sync */
|
|
1192
1220
|
checkColumnOrder?: boolean;
|
|
1221
|
+
/** Whether to check row grouping sync */
|
|
1222
|
+
checkRowGrouping?: boolean;
|
|
1223
|
+
/** Whether to check aggregation sync */
|
|
1224
|
+
checkAggregation?: boolean;
|
|
1225
|
+
/** Whether to check pivot sync */
|
|
1226
|
+
checkPivot?: boolean;
|
|
1193
1227
|
}
|
|
1194
1228
|
|
|
1195
1229
|
/**
|
|
@@ -1208,6 +1242,9 @@ export const assertAllStatesInSync = async ({
|
|
|
1208
1242
|
checkPagination = true,
|
|
1209
1243
|
checkDensity = true,
|
|
1210
1244
|
checkColumnOrder = false,
|
|
1245
|
+
checkRowGrouping = false,
|
|
1246
|
+
checkAggregation = false,
|
|
1247
|
+
checkPivot = false,
|
|
1211
1248
|
}: SyncAssertionOptions) => {
|
|
1212
1249
|
await waitFor(
|
|
1213
1250
|
() => {
|
|
@@ -1314,6 +1351,53 @@ export const assertAllStatesInSync = async ({
|
|
|
1314
1351
|
expect(urlColumnOrder).toBe(inner);
|
|
1315
1352
|
}
|
|
1316
1353
|
}
|
|
1354
|
+
|
|
1355
|
+
// --- Row Grouping ---
|
|
1356
|
+
if (checkRowGrouping) {
|
|
1357
|
+
const lsKey = `${pathname}:${localStorageVersion}:rowGroupingModel`;
|
|
1358
|
+
const lsRaw = localStorage.getItem(lsKey);
|
|
1359
|
+
const lsRowGrouping = lsRaw ? JSON.parse(lsRaw) : '';
|
|
1360
|
+
|
|
1361
|
+
const urlRowGrouping = url.get('_rowGrouping');
|
|
1362
|
+
if (lsRowGrouping && urlRowGrouping) {
|
|
1363
|
+
// localStorage: `_rowGrouping=[a,b,c]`
|
|
1364
|
+
// URL: `_rowGrouping=a,b,c`
|
|
1365
|
+
const lsParams = new URLSearchParams(lsRowGrouping);
|
|
1366
|
+
const lsValue = lsParams.get('_rowGrouping') ?? '';
|
|
1367
|
+
const inner = lsValue.startsWith('[') && lsValue.endsWith(']') ? lsValue.slice(1, -1) : lsValue;
|
|
1368
|
+
expect(urlRowGrouping).toBe(inner);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// --- Aggregation ---
|
|
1373
|
+
if (checkAggregation) {
|
|
1374
|
+
const lsKey = `${pathname}:${localStorageVersion}:aggregationModel`;
|
|
1375
|
+
const lsRaw = localStorage.getItem(lsKey);
|
|
1376
|
+
const lsAggregation = lsRaw ? JSON.parse(lsRaw) : '';
|
|
1377
|
+
|
|
1378
|
+
const urlAggregation = url.get('_aggregation');
|
|
1379
|
+
if (lsAggregation && urlAggregation) {
|
|
1380
|
+
// Both use same format: `_aggregation=field.func,...`
|
|
1381
|
+
const lsParams = new URLSearchParams(lsAggregation);
|
|
1382
|
+
const lsValue = lsParams.get('_aggregation') ?? '';
|
|
1383
|
+
expect(urlAggregation).toBe(lsValue);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// --- Pivot ---
|
|
1388
|
+
if (checkPivot) {
|
|
1389
|
+
const lsKey = `${pathname}:${localStorageVersion}:pivotModel`;
|
|
1390
|
+
const lsRaw = localStorage.getItem(lsKey);
|
|
1391
|
+
const lsPivot = lsRaw ? JSON.parse(lsRaw) : '';
|
|
1392
|
+
|
|
1393
|
+
const urlPivot = url.get('_pivot');
|
|
1394
|
+
if (lsPivot && urlPivot) {
|
|
1395
|
+
// Both use same format: `_pivot=cols:f1;rows:f2;vals:f3.sum`
|
|
1396
|
+
const lsParams = new URLSearchParams(lsPivot);
|
|
1397
|
+
const lsValue = lsParams.get('_pivot') ?? '';
|
|
1398
|
+
expect(urlPivot).toBe(lsValue);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1317
1401
|
},
|
|
1318
1402
|
{ timeout: 5000 }
|
|
1319
1403
|
);
|
|
@@ -133,15 +133,12 @@ const assertState = async (
|
|
|
133
133
|
// Items, Tags). Then uncheck all 8 persistent filters one by one.
|
|
134
134
|
// Reverse: same clicks in reverse order, then uncheck again.
|
|
135
135
|
//
|
|
136
|
-
// Split into Forward and Reverse halves so each story stays within the
|
|
137
|
-
// Storybook test-runner's timeout (38 total steps is too many for one story).
|
|
138
|
-
//
|
|
139
136
|
// The client-side pattern uses Dashboard + WithFilters with crossfilter2.
|
|
140
137
|
// Each DataCard/Chart field has its own crossfilter dimension, and cross-
|
|
141
138
|
// filtered aggregates exclude the queried field's own filter.
|
|
142
139
|
// ---------------------------------------------------------------------------
|
|
143
140
|
|
|
144
|
-
export const
|
|
141
|
+
export const ComprehensiveToggleSequence: Story = {
|
|
145
142
|
render: () => <Example />,
|
|
146
143
|
play: async ({ canvasElement }) => {
|
|
147
144
|
const canvas = within(canvasElement);
|
|
@@ -233,20 +230,6 @@ export const ComprehensiveToggleForward: Story = {
|
|
|
233
230
|
// -- U8: -Seasonal (bar) → back to full dataset -------------------------
|
|
234
231
|
await clickBarChartBar(canvasElement, 'Seasonal');
|
|
235
232
|
await assertState(canvasElement, S0_NONE, categoryListbox, allergenListbox);
|
|
236
|
-
},
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
export const ComprehensiveToggleReverse: Story = {
|
|
240
|
-
render: () => <Example />,
|
|
241
|
-
play: async ({ canvasElement }) => {
|
|
242
|
-
const canvas = within(canvasElement);
|
|
243
|
-
await waitForGridToLoad(canvas);
|
|
244
|
-
|
|
245
|
-
const categoryListbox = getListbox(canvas, /filter by category/i);
|
|
246
|
-
const allergenListbox = getListbox(canvas, /filter by allergen/i);
|
|
247
|
-
|
|
248
|
-
// == Step 0: No filters — full dataset ==================================
|
|
249
|
-
await assertState(canvasElement, S0_NONE, categoryListbox, allergenListbox);
|
|
250
233
|
|
|
251
234
|
// == Reverse sequence (add filters in opposite order) ===================
|
|
252
235
|
|
|
@@ -133,7 +133,7 @@ const assertState = async (
|
|
|
133
133
|
// Comprehensive toggle sequence — identical to client but with server waits.
|
|
134
134
|
//
|
|
135
135
|
// Split into Forward and Reverse halves so each story stays within the
|
|
136
|
-
// Storybook test-runner's
|
|
136
|
+
// Storybook test-runner's 15-second timeout (38 total steps is too many).
|
|
137
137
|
// ---------------------------------------------------------------------------
|
|
138
138
|
|
|
139
139
|
export const ComprehensiveToggleForward: Story = {
|
|
@@ -2,9 +2,9 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
|
2
2
|
import { DataGrid } from '@redsift/table';
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
4
|
import { DataCard, DataRow } from '@redsift/dashboard';
|
|
5
|
-
import { BarChart, PieChart } from '@redsift/charts';
|
|
5
|
+
import { BarChart, PieChart, ArcDatum, BarDatum } from '@redsift/charts';
|
|
6
6
|
import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
|
|
7
|
-
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-
|
|
7
|
+
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
|
|
8
8
|
import { Row } from '../_shared/data';
|
|
9
9
|
import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
|
|
10
10
|
import { fetchBakeryData, FetchResult } from '../_shared/api-client';
|
|
@@ -211,8 +211,8 @@ export default () => {
|
|
|
211
211
|
}}
|
|
212
212
|
data={itemsChartData}
|
|
213
213
|
sliceRole="option"
|
|
214
|
-
onSliceClick={(datum:
|
|
215
|
-
const key = datum.data.key
|
|
214
|
+
onSliceClick={(datum: ArcDatum) => {
|
|
215
|
+
const key = datum.data.key;
|
|
216
216
|
setFilterModel((prev) => {
|
|
217
217
|
const selected = getSelectedFromFilterModel(prev, 'Items');
|
|
218
218
|
const next = selected.includes(key) ? selected.filter((v) => v !== key) : [...selected, key];
|
|
@@ -220,8 +220,8 @@ export default () => {
|
|
|
220
220
|
});
|
|
221
221
|
setPage(0);
|
|
222
222
|
}}
|
|
223
|
-
isSliceSelected={(datum:
|
|
224
|
-
itemsSelection.length === 0 || itemsSelection.includes(datum.data.key
|
|
223
|
+
isSliceSelected={(datum: ArcDatum) =>
|
|
224
|
+
itemsSelection.length === 0 || itemsSelection.includes(datum.data.key)
|
|
225
225
|
}
|
|
226
226
|
/>
|
|
227
227
|
|
|
@@ -246,8 +246,8 @@ export default () => {
|
|
|
246
246
|
barProps={{ gap: 20 }}
|
|
247
247
|
data={tagsChartData}
|
|
248
248
|
barRole="option"
|
|
249
|
-
onBarClick={(datum:
|
|
250
|
-
const key = datum.data.key
|
|
249
|
+
onBarClick={(datum: BarDatum) => {
|
|
250
|
+
const key = String(datum.data.key);
|
|
251
251
|
setFilterModel((prev) => {
|
|
252
252
|
const selected = getSelectedFromFilterModel(prev, 'Tags');
|
|
253
253
|
const next = selected.includes(key) ? selected.filter((v) => v !== key) : [...selected, key];
|
|
@@ -255,8 +255,8 @@ export default () => {
|
|
|
255
255
|
});
|
|
256
256
|
setPage(0);
|
|
257
257
|
}}
|
|
258
|
-
isBarSelected={(datum:
|
|
259
|
-
tagsSelection.length === 0 || tagsSelection.includes(datum.data.key
|
|
258
|
+
isBarSelected={(datum: BarDatum) =>
|
|
259
|
+
tagsSelection.length === 0 || tagsSelection.includes(String(datum.data.key))
|
|
260
260
|
}
|
|
261
261
|
/>
|
|
262
262
|
</Flexbox>
|
|
@@ -3,7 +3,7 @@ import { DataGrid } from '@redsift/table';
|
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
4
|
import { DataCard, DataRow } from '@redsift/dashboard';
|
|
5
5
|
import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
|
|
6
|
-
import { GridFilterModel } from '@mui/x-data-grid-
|
|
6
|
+
import { GridFilterModel } from '@mui/x-data-grid-premium';
|
|
7
7
|
import { rows } from '../_shared/data';
|
|
8
8
|
import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
|
|
9
9
|
import { CustomToolbar } from '../_shared/helpers';
|
|
@@ -3,7 +3,7 @@ import { DataGrid } from '@redsift/table';
|
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
4
|
import { DataCard, DataRow } from '@redsift/dashboard';
|
|
5
5
|
import { mdiShapeOutline, mdiToggleSwitch, mdiFoodOff } from '@redsift/icons';
|
|
6
|
-
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-
|
|
6
|
+
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
|
|
7
7
|
import { Row } from '../_shared/data';
|
|
8
8
|
import { columns, CATEGORY_OPTIONS, ALLERGEN_OPTIONS } from '../_shared/columns';
|
|
9
9
|
import { fetchBakeryData, FetchResult } from '../_shared/api-client';
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { within, userEvent } from '@storybook/testing-library';
|
|
4
4
|
import { expect } from '@storybook/jest';
|
|
5
|
-
import { GridFilterModel } from '@mui/x-data-grid-
|
|
5
|
+
import { GridFilterModel } from '@mui/x-data-grid-premium';
|
|
6
6
|
|
|
7
7
|
import Example from './example';
|
|
8
8
|
import WithLoadingExample from './with-loading';
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { DataGrid } from '@redsift/table';
|
|
2
|
+
import { DataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
|
-
import { GridFilterModel, GridRowSelectionModel } from '@mui/x-data-grid-
|
|
4
|
+
import { GridFilterModel, GridRowSelectionModel } from '@mui/x-data-grid-premium';
|
|
5
5
|
import { rows } from '../_shared/data';
|
|
6
6
|
import { columns } from '../_shared/columns';
|
|
7
7
|
import { CustomToolbar, BulkActionBar } from '../_shared/helpers';
|
|
8
8
|
import { DEFAULT_FILTER_MODEL, DEFAULT_SORT_MODEL } from '../_shared/defaults';
|
|
9
9
|
|
|
10
10
|
export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }) => {
|
|
11
|
-
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(
|
|
11
|
+
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<div style={{ width: '100%' }}>
|
|
15
15
|
<Flexbox flexDirection="column" gap="0px">
|
|
16
16
|
<BulkActionBar
|
|
17
|
-
count={selectionModel
|
|
17
|
+
count={getSelectionCount(selectionModel)}
|
|
18
18
|
onLog={() => console.log('Selected:', selectionModel)}
|
|
19
19
|
onDelete={() => console.log('Delete:', selectionModel)}
|
|
20
20
|
/>
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { within, userEvent, waitFor } from '@storybook/testing-library';
|
|
4
4
|
import { expect } from '@storybook/jest';
|
|
5
|
-
import { GridFilterModel } from '@mui/x-data-grid-
|
|
5
|
+
import { GridFilterModel } from '@mui/x-data-grid-premium';
|
|
6
6
|
|
|
7
7
|
import Example from './example';
|
|
8
8
|
import WithLoadingExample from './with-loading';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { DataGrid } from '@redsift/table';
|
|
2
|
+
import { DataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
|
-
import { GridFilterModel, GridRowSelectionModel, GridSortModel } from '@mui/x-data-grid-
|
|
4
|
+
import { GridFilterModel, GridRowSelectionModel, GridSortModel } from '@mui/x-data-grid-premium';
|
|
5
5
|
import { Row } from '../_shared/data';
|
|
6
6
|
import { columns } from '../_shared/columns';
|
|
7
7
|
import { fetchBakeryData } from '../_shared/api-client';
|
|
@@ -16,7 +16,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
|
|
|
16
16
|
const [pageSize, setPageSize] = useState(10);
|
|
17
17
|
const [sortModel, setSortModel] = useState<GridSortModel>(DEFAULT_SORT_MODEL);
|
|
18
18
|
const [filterModel, setFilterModel] = useState<GridFilterModel>(initialFilterModel ?? DEFAULT_FILTER_MODEL);
|
|
19
|
-
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(
|
|
19
|
+
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
|
|
20
20
|
|
|
21
21
|
const quickFilterText = (filterModel as { quickFilterValues?: string[] }).quickFilterValues?.join(' ') || '';
|
|
22
22
|
const debounceRef = useRef<ReturnType<typeof setTimeout>>();
|
|
@@ -54,7 +54,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
|
|
|
54
54
|
<div style={{ width: '100%' }}>
|
|
55
55
|
<Flexbox flexDirection="column" gap="0px">
|
|
56
56
|
<BulkActionBar
|
|
57
|
-
count={selectionModel
|
|
57
|
+
count={getSelectionCount(selectionModel)}
|
|
58
58
|
onLog={() => console.log('Selected:', selectionModel)}
|
|
59
59
|
onDelete={() => console.log('Delete:', selectionModel)}
|
|
60
60
|
/>
|