@redsift/ds-mcp-server 12.5.3-alpha.7 → 12.5.3-muiv6
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 +3 -12
- 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 +22 -106
- package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +18 -1
- 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 +1 -129
- package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +5 -6
- package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +1 -134
- package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +5 -6
- 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 +2 -8
- package/data/docs/components.json +19 -25
- package/data/docs/llms-full.txt +44 -46
- package/data/docs/llms.txt +4 -4
- package/data/docs/patterns-catalog.md +25 -24
- 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 +21 -36
- package/data/patterns/stateful-single-datagrid-server-side.mdx +18 -46
- 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 { GridApiPro } from '@mui/x-data-grid-pro/models/gridApiPro';
|
|
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<GridApiPro>;
|
|
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-pro';
|
|
6
6
|
import { Row } from './data';
|
|
7
7
|
|
|
8
8
|
// -- Option constants -------------------------------------------------------
|
|
@@ -80,7 +80,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
80
80
|
field: 'Items',
|
|
81
81
|
headerName: 'Item',
|
|
82
82
|
flex: 1,
|
|
83
|
-
display: 'flex',
|
|
84
83
|
...createColumn('string'),
|
|
85
84
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value}</TextCell>,
|
|
86
85
|
},
|
|
@@ -89,7 +88,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
89
88
|
field: 'Category',
|
|
90
89
|
headerName: 'Category',
|
|
91
90
|
width: 120,
|
|
92
|
-
display: 'flex',
|
|
93
91
|
...createColumn('singleSelect'),
|
|
94
92
|
valueOptions: CATEGORY_OPTIONS,
|
|
95
93
|
renderCell: ({ value }: GridRenderCellParams) => <Pill color={categoryColor(value)}>{value}</Pill>,
|
|
@@ -99,7 +97,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
99
97
|
field: 'Paid',
|
|
100
98
|
headerName: 'Price',
|
|
101
99
|
width: 100,
|
|
102
|
-
display: 'flex',
|
|
103
100
|
...createColumn('number'),
|
|
104
101
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{formatCurrency(value as number)}</TextCell>,
|
|
105
102
|
},
|
|
@@ -108,9 +105,8 @@ export const columns: GridColDef<Row>[] = [
|
|
|
108
105
|
field: 'Date',
|
|
109
106
|
headerName: 'Date',
|
|
110
107
|
width: 140,
|
|
111
|
-
display: 'flex',
|
|
112
108
|
...createColumn('date'),
|
|
113
|
-
valueGetter: (
|
|
109
|
+
valueGetter: (params: any) => parseDate(params.value),
|
|
114
110
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDate(value as Date) : '—'}</TextCell>,
|
|
115
111
|
},
|
|
116
112
|
// DateTime
|
|
@@ -118,9 +114,8 @@ export const columns: GridColDef<Row>[] = [
|
|
|
118
114
|
field: 'DateTime',
|
|
119
115
|
headerName: 'Date & Time',
|
|
120
116
|
width: 180,
|
|
121
|
-
display: 'flex',
|
|
122
117
|
...createColumn('dateTime'),
|
|
123
|
-
valueGetter: (
|
|
118
|
+
valueGetter: (params: any) => parseDate(params.value),
|
|
124
119
|
renderCell: ({ value }: GridRenderCellParams) => <TextCell>{value ? formatDateTime(value as Date) : '—'}</TextCell>,
|
|
125
120
|
},
|
|
126
121
|
// Boolean — in stock
|
|
@@ -128,7 +123,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
128
123
|
field: 'InStock',
|
|
129
124
|
headerName: 'In Stock',
|
|
130
125
|
width: 90,
|
|
131
|
-
display: 'flex',
|
|
132
126
|
type: 'boolean',
|
|
133
127
|
renderCell: ({ value }: GridRenderCellParams) =>
|
|
134
128
|
value ? (
|
|
@@ -142,7 +136,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
142
136
|
field: 'Allergens',
|
|
143
137
|
headerName: 'Allergens',
|
|
144
138
|
flex: 1,
|
|
145
|
-
display: 'flex',
|
|
146
139
|
...createColumn('multiSelect'),
|
|
147
140
|
valueOptions: ALLERGEN_OPTIONS,
|
|
148
141
|
sortable: false,
|
|
@@ -165,7 +158,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
165
158
|
field: 'Tags',
|
|
166
159
|
headerName: 'Tags',
|
|
167
160
|
flex: 1,
|
|
168
|
-
display: 'flex',
|
|
169
161
|
...createColumn('tags'),
|
|
170
162
|
valueOptions: TAG_OPTIONS,
|
|
171
163
|
sortable: false,
|
|
@@ -188,7 +180,6 @@ export const columns: GridColDef<Row>[] = [
|
|
|
188
180
|
field: 'actions',
|
|
189
181
|
headerName: '',
|
|
190
182
|
width: 56,
|
|
191
|
-
display: 'flex',
|
|
192
183
|
hideable: false,
|
|
193
184
|
sortable: false,
|
|
194
185
|
filterable: false,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-
|
|
1
|
+
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-pro';
|
|
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
|
|
2
|
+
import { within, waitFor, userEvent } from '@storybook/testing-library';
|
|
3
3
|
import { expect } from '@storybook/jest';
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
@@ -366,19 +366,13 @@ 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
|
-
|
|
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
|
-
);
|
|
369
|
+
await waitFor(() => {
|
|
370
|
+
const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
|
|
371
|
+
expect(rows.length).toBeGreaterThan(rowIndex);
|
|
372
|
+
});
|
|
380
373
|
const rows = canvasElement.querySelectorAll('.MuiDataGrid-row');
|
|
381
|
-
const checkbox = rows[rowIndex].querySelector('input[type="checkbox"]')
|
|
374
|
+
const checkbox = rows[rowIndex].querySelector('input[type="checkbox"]');
|
|
375
|
+
if (!checkbox) throw new Error(`Could not find checkbox in row ${rowIndex}`);
|
|
382
376
|
await userEvent.click(checkbox);
|
|
383
377
|
// Wait for React and MUI DataGrid to process the selection change
|
|
384
378
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
@@ -952,39 +946,18 @@ export const waitForPaginationEnabled = async (canvasElement: HTMLElement, direc
|
|
|
952
946
|
|
|
953
947
|
/**
|
|
954
948
|
* Change the page size via the MUI pagination "Rows per page" select.
|
|
955
|
-
*
|
|
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.
|
|
949
|
+
* The dropdown menu renders as a portal on document.body.
|
|
962
950
|
*/
|
|
963
951
|
export const changePageSize = async (canvasElement: HTMLElement, newSize: number) => {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
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"]');
|
|
952
|
+
const select = canvasElement.querySelector('.MuiTablePagination-select') as HTMLElement | null;
|
|
953
|
+
if (!select) throw new Error('Could not find page size select');
|
|
954
|
+
await userEvent.click(select);
|
|
955
|
+
// The menu renders as a MUI Popper on document.body
|
|
956
|
+
await waitFor(() => {
|
|
957
|
+
const options = document.querySelectorAll('li[role="option"]');
|
|
958
|
+
expect(options.length).toBeGreaterThan(0);
|
|
959
|
+
});
|
|
960
|
+
const options = document.querySelectorAll('li[role="option"]');
|
|
988
961
|
const target = Array.from(options).find((opt) => opt.textContent === String(newSize));
|
|
989
962
|
if (!target) throw new Error(`Could not find page size option "${newSize}"`);
|
|
990
963
|
await userEvent.click(target);
|
|
@@ -1003,18 +976,17 @@ export const openColumnsPanel = async (canvasElement: HTMLElement) => {
|
|
|
1003
976
|
await userEvent.click(btn);
|
|
1004
977
|
// Wait for the panel to appear on document.body
|
|
1005
978
|
await waitFor(() => {
|
|
1006
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
979
|
+
const panel = document.querySelector('.MuiDataGrid-columnsPanel');
|
|
1007
980
|
expect(panel).toBeTruthy();
|
|
1008
981
|
});
|
|
1009
982
|
};
|
|
1010
983
|
|
|
1011
984
|
/** Toggle a column's visibility in the columns panel by its label text. */
|
|
1012
985
|
export const toggleColumnInPanel = async (fieldLabel: string) => {
|
|
1013
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
986
|
+
const panel = document.querySelector('.MuiDataGrid-columnsPanel');
|
|
1014
987
|
if (!panel) throw new Error('Columns panel is not open');
|
|
1015
|
-
|
|
1016
|
-
const
|
|
1017
|
-
const target = rows.find((row) => row.textContent?.includes(fieldLabel));
|
|
988
|
+
const labels = Array.from(panel.querySelectorAll('.MuiFormControlLabel-root'));
|
|
989
|
+
const target = labels.find((label) => label.textContent?.includes(fieldLabel));
|
|
1018
990
|
if (!target) throw new Error(`Could not find column "${fieldLabel}" in columns panel`);
|
|
1019
991
|
const checkbox = target.querySelector('input[type="checkbox"]') as HTMLElement | null;
|
|
1020
992
|
if (!checkbox) throw new Error(`Could not find checkbox for column "${fieldLabel}"`);
|
|
@@ -1026,7 +998,7 @@ export const closeColumnsPanel = async () => {
|
|
|
1026
998
|
// Press Escape to close the panel
|
|
1027
999
|
await userEvent.keyboard('{Escape}');
|
|
1028
1000
|
await waitFor(() => {
|
|
1029
|
-
const panel = document.querySelector('.MuiDataGrid-
|
|
1001
|
+
const panel = document.querySelector('.MuiDataGrid-columnsPanel');
|
|
1030
1002
|
expect(panel).toBeFalsy();
|
|
1031
1003
|
});
|
|
1032
1004
|
};
|
|
@@ -1218,12 +1190,6 @@ interface SyncAssertionOptions {
|
|
|
1218
1190
|
checkDensity?: boolean;
|
|
1219
1191
|
/** Whether to check column order sync */
|
|
1220
1192
|
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;
|
|
1227
1193
|
}
|
|
1228
1194
|
|
|
1229
1195
|
/**
|
|
@@ -1242,9 +1208,6 @@ export const assertAllStatesInSync = async ({
|
|
|
1242
1208
|
checkPagination = true,
|
|
1243
1209
|
checkDensity = true,
|
|
1244
1210
|
checkColumnOrder = false,
|
|
1245
|
-
checkRowGrouping = false,
|
|
1246
|
-
checkAggregation = false,
|
|
1247
|
-
checkPivot = false,
|
|
1248
1211
|
}: SyncAssertionOptions) => {
|
|
1249
1212
|
await waitFor(
|
|
1250
1213
|
() => {
|
|
@@ -1351,53 +1314,6 @@ export const assertAllStatesInSync = async ({
|
|
|
1351
1314
|
expect(urlColumnOrder).toBe(inner);
|
|
1352
1315
|
}
|
|
1353
1316
|
}
|
|
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
|
-
}
|
|
1401
1317
|
},
|
|
1402
1318
|
{ timeout: 5000 }
|
|
1403
1319
|
);
|
|
@@ -133,12 +133,15 @@ 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
|
+
//
|
|
136
139
|
// The client-side pattern uses Dashboard + WithFilters with crossfilter2.
|
|
137
140
|
// Each DataCard/Chart field has its own crossfilter dimension, and cross-
|
|
138
141
|
// filtered aggregates exclude the queried field's own filter.
|
|
139
142
|
// ---------------------------------------------------------------------------
|
|
140
143
|
|
|
141
|
-
export const
|
|
144
|
+
export const ComprehensiveToggleForward: Story = {
|
|
142
145
|
render: () => <Example />,
|
|
143
146
|
play: async ({ canvasElement }) => {
|
|
144
147
|
const canvas = within(canvasElement);
|
|
@@ -230,6 +233,20 @@ export const ComprehensiveToggleSequence: Story = {
|
|
|
230
233
|
// -- U8: -Seasonal (bar) → back to full dataset -------------------------
|
|
231
234
|
await clickBarChartBar(canvasElement, 'Seasonal');
|
|
232
235
|
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);
|
|
233
250
|
|
|
234
251
|
// == Reverse sequence (add filters in opposite order) ===================
|
|
235
252
|
|
|
@@ -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 30-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
|
|
5
|
+
import { BarChart, PieChart } 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-pro';
|
|
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: any) => {
|
|
215
|
+
const key = datum.data.key as string;
|
|
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: any) =>
|
|
224
|
+
itemsSelection.length === 0 || itemsSelection.includes(datum.data.key as string)
|
|
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 =
|
|
249
|
+
onBarClick={(datum: any) => {
|
|
250
|
+
const key = datum.data.key as string;
|
|
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(
|
|
258
|
+
isBarSelected={(datum: any) =>
|
|
259
|
+
tagsSelection.length === 0 || tagsSelection.includes(datum.data.key as string)
|
|
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-pro';
|
|
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-pro';
|
|
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-pro';
|
|
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
|
|
2
|
+
import { DataGrid } 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-pro';
|
|
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>([]);
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<div style={{ width: '100%' }}>
|
|
15
15
|
<Flexbox flexDirection="column" gap="0px">
|
|
16
16
|
<BulkActionBar
|
|
17
|
-
count={
|
|
17
|
+
count={selectionModel.length}
|
|
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-pro';
|
|
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
|
|
2
|
+
import { DataGrid } 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-pro';
|
|
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>([]);
|
|
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={
|
|
57
|
+
count={selectionModel.length}
|
|
58
58
|
onLog={() => console.log('Selected:', selectionModel)}
|
|
59
59
|
onDelete={() => console.log('Delete:', selectionModel)}
|
|
60
60
|
/>
|