@redsift/ds-mcp-server 12.5.3-muiv7 → 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/consumer-instructions/redsift-design-system.instructions.md +82 -1
- package/data/demos/patterns/_shared/StateDebugPanel.tsx +2 -2
- package/data/demos/patterns/_shared/columns.tsx +3 -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 -36
- package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +4 -19
- package/data/demos/patterns/crossfiltered-datagrid-client-side/example.tsx +2 -2
- package/data/demos/patterns/crossfiltered-datagrid-server-side/CrossfilteredDatagridServerSide.interaction.stories.tsx +3 -3
- package/data/demos/patterns/crossfiltered-datagrid-server-side/example.tsx +5 -5
- package/data/demos/patterns/drilldowned-datagrid-client-side/DrilldownedDatagridClientSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/drilldowned-datagrid-client-side/example.tsx +1 -1
- package/data/demos/patterns/drilldowned-datagrid-server-side/DrilldownedDatagridServerSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/drilldowned-datagrid-server-side/example.tsx +5 -19
- package/data/demos/patterns/single-datagrid-client-side/SingleDatagridClientSide.interaction.stories.tsx +3 -3
- package/data/demos/patterns/single-datagrid-client-side/example.tsx +5 -5
- package/data/demos/patterns/single-datagrid-server-side/SingleDatagridServerSide.interaction.stories.tsx +3 -3
- package/data/demos/patterns/single-datagrid-server-side/example.tsx +5 -6
- package/data/demos/patterns/stateful-single-datagrid-client-side/StatefulSingleDatagridClientSide.interaction.stories.tsx +130 -3
- package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +6 -6
- package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +136 -6
- package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +6 -9
- package/data/demos/patterns/summary-dashboard/SummaryDashboard.interaction.stories.tsx +2 -2
- package/data/demos/patterns/tabbed-datagrid-client-side/TabbedDatagridClientSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/tabbed-datagrid-server-side/TabbedDatagridServerSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/tabbed-datagrid-server-side/example.tsx +1 -1
- package/data/docs/components/charts/Axis.json +6 -1
- package/data/docs/components/charts/BarChart.json +7 -1
- package/data/docs/components/charts/ChartContainerTitle.json +5 -1
- package/data/docs/components/charts/Legend.json +6 -1
- package/data/docs/components/charts/LineChart.json +7 -1
- package/data/docs/components/charts/PieChart.json +6 -1
- package/data/docs/components/charts/ScatterPlot.json +6 -1
- package/data/docs/components/dashboard/ChartEmptyState.json +8 -1
- package/data/docs/components/dashboard/Dashboard.json +8 -3
- package/data/docs/components/dashboard/DataCard.json +12 -0
- package/data/docs/components/dashboard/DataCardBody.json +4 -0
- package/data/docs/components/dashboard/DataCardHeader.json +4 -0
- package/data/docs/components/dashboard/DataCardListbox.json +5 -0
- package/data/docs/components/dashboard/DataRow.json +7 -1
- package/data/docs/components/dashboard/PdfExportButton.json +6 -1
- package/data/docs/components/dashboard/TimeSeriesBarChart.json +6 -1
- package/data/docs/components/dashboard/WithFilters.json +5 -1
- package/data/docs/components/design-system/Alert.json +8 -1
- package/data/docs/components/design-system/AppBar.json +6 -1
- package/data/docs/components/design-system/AppContent.json +4 -0
- package/data/docs/components/design-system/AppSidePanel.json +5 -0
- package/data/docs/components/design-system/Badge.json +6 -1
- package/data/docs/components/design-system/Breadcrumbs.json +4 -0
- package/data/docs/components/design-system/Button.json +5 -0
- package/data/docs/components/design-system/Card.json +9 -0
- package/data/docs/components/design-system/CardActions.json +4 -0
- package/data/docs/components/design-system/CardBody.json +3 -0
- package/data/docs/components/design-system/CardHeader.json +4 -0
- package/data/docs/components/design-system/DetailedCard.json +6 -0
- package/data/docs/components/design-system/Flexbox.json +14 -1
- package/data/docs/components/design-system/Grid.json +6 -1
- package/data/docs/components/design-system/Heading.json +11 -0
- package/data/docs/components/design-system/Icon.json +6 -1
- package/data/docs/components/design-system/IconButton.json +9 -0
- package/data/docs/components/design-system/Pill.json +10 -0
- package/data/docs/components/design-system/Skeleton.json +10 -1
- package/data/docs/components/design-system/SkeletonCircle.json +6 -1
- package/data/docs/components/design-system/SkeletonText.json +6 -1
- package/data/docs/components/design-system/Tab.json +4 -0
- package/data/docs/components/design-system/TabPanel.json +4 -0
- package/data/docs/components/design-system/Tabs.json +6 -0
- package/data/docs/components/design-system/Text.json +9 -0
- package/data/docs/components/design-system/TextField.json +6 -1
- package/data/docs/components/pickers/Combobox.json +6 -0
- package/data/docs/components/pickers/MenuButton.json +5 -0
- package/data/docs/components/pickers/Select.json +5 -0
- package/data/docs/components/popovers/Dialog.json +6 -0
- package/data/docs/components/popovers/Toggletip.json +5 -0
- package/data/docs/components/popovers/Tooltip.json +4 -0
- package/data/docs/components/table/DataGrid.json +12 -31
- package/data/docs/components/table/StatefulDataGrid.json +9 -31
- package/data/docs/components-index.json +343 -53
- package/data/docs/components.json +10 -64
- package/data/docs/llms-full.txt +291 -68
- package/data/docs/llms.txt +56 -6
- package/data/docs/patterns-catalog.md +215 -25
- package/data/docs/patterns.json +369 -31
- 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 +9 -9
- package/data/patterns/single-datagrid-server-side.mdx +4 -4
- package/data/patterns/stateful-single-datagrid-client-side.mdx +36 -20
- package/data/patterns/stateful-single-datagrid-server-side.mdx +46 -18
- package/data/patterns/tabbed-datagrid-server-side.mdx +1 -1
- package/data/prompts/ds-advisor.md +103 -0
- package/dist/data-store.d.ts +21 -1
- package/dist/data-store.d.ts.map +1 -1
- package/dist/data-store.js +65 -15
- package/dist/data-store.js.map +1 -1
- package/dist/pattern-store.d.ts +18 -1
- package/dist/pattern-store.d.ts.map +1 -1
- package/dist/pattern-store.js +64 -22
- package/dist/pattern-store.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +56 -27
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +26 -0
- package/dist/resources.js.map +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +12 -0
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -2
|
@@ -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
|
/>
|
|
@@ -22,8 +22,8 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
|
|
|
22
22
|
<DataGrid
|
|
23
23
|
autoHeight
|
|
24
24
|
pagination
|
|
25
|
+
density="compact"
|
|
25
26
|
initialState={{
|
|
26
|
-
density: 'compact',
|
|
27
27
|
filter: { filterModel: initialFilterModel ?? DEFAULT_FILTER_MODEL },
|
|
28
28
|
sorting: { sortModel: DEFAULT_SORT_MODEL },
|
|
29
29
|
pagination: { paginationModel: { page: 0, pageSize: 10 } },
|
|
@@ -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';
|
|
@@ -55,9 +55,9 @@ import {
|
|
|
55
55
|
TAGS_HASANYOF_LOCAL_NEW,
|
|
56
56
|
} from '../_shared/expected-values';
|
|
57
57
|
|
|
58
|
-
const meta: Meta
|
|
58
|
+
const meta: Meta = {
|
|
59
59
|
title: 'Patterns/Single Datagrid (Server)',
|
|
60
|
-
component: Example,
|
|
60
|
+
component: Example as any,
|
|
61
61
|
parameters: {
|
|
62
62
|
msw: { handlers: bakeryHandlers },
|
|
63
63
|
},
|
|
@@ -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
|
/>
|
|
@@ -62,7 +62,7 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
|
|
|
62
62
|
<DataGrid
|
|
63
63
|
autoHeight
|
|
64
64
|
pagination
|
|
65
|
-
|
|
65
|
+
density="compact"
|
|
66
66
|
paginationMode="server"
|
|
67
67
|
sortingMode="server"
|
|
68
68
|
filterMode="server"
|
|
@@ -74,7 +74,6 @@ export default ({ initialFilterModel }: { initialFilterModel?: GridFilterModel }
|
|
|
74
74
|
pageSizeOptions={[10, 25, 50]}
|
|
75
75
|
onPaginationModelChange={(model) => {
|
|
76
76
|
if (model.pageSize !== pageSize) {
|
|
77
|
-
setRows([]);
|
|
78
77
|
setPageSize(model.pageSize);
|
|
79
78
|
setPage(0);
|
|
80
79
|
} else {
|
|
@@ -2,8 +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, useGridApiRef } from '@mui/x-data-grid-
|
|
6
|
-
import type { GridApiPro } from '@mui/x-data-grid-pro';
|
|
5
|
+
import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-premium';
|
|
7
6
|
|
|
8
7
|
import Example from './example';
|
|
9
8
|
import WithLoadingExample from './with-loading';
|
|
@@ -627,12 +626,94 @@ export const SortingInteraction: Story = {
|
|
|
627
626
|
},
|
|
628
627
|
};
|
|
629
628
|
|
|
629
|
+
// ---------------------------------------------------------------------------
|
|
630
|
+
// Row Grouping — set via apiRef, assert URL
|
|
631
|
+
// ---------------------------------------------------------------------------
|
|
632
|
+
|
|
633
|
+
let _rowGroupingRouter: ReturnType<typeof createMockRouter>;
|
|
634
|
+
let _rowGroupingApiRef: ReturnType<typeof useGridApiRef>;
|
|
635
|
+
|
|
636
|
+
export const RowGroupingInteraction: Story = {
|
|
637
|
+
render: () => {
|
|
638
|
+
_rowGroupingRouter = usePersistentMockRouter();
|
|
639
|
+
_rowGroupingApiRef = useGridApiRef();
|
|
640
|
+
return <Example useRouter={_rowGroupingRouter.useRouter} apiRef={_rowGroupingApiRef} />;
|
|
641
|
+
},
|
|
642
|
+
play: async ({ canvasElement, step }) => {
|
|
643
|
+
const canvas = within(canvasElement);
|
|
644
|
+
const { getSearch } = _rowGroupingRouter;
|
|
645
|
+
|
|
646
|
+
await step('Wait for grid to load', async () => {
|
|
647
|
+
await waitForGridToLoad(canvas);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
await step('Set row grouping to Category', async () => {
|
|
651
|
+
_rowGroupingApiRef.current!.setRowGroupingModel(['Category']);
|
|
652
|
+
await waitFor(() => {
|
|
653
|
+
expect(getSearch()).toContain('_rowGrouping=Category');
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
await step('Assert sync', async () => {
|
|
658
|
+
await assertAllStatesInSync({ getSearch, checkRowGrouping: true });
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
await step('Clear row grouping', async () => {
|
|
662
|
+
_rowGroupingApiRef.current!.setRowGroupingModel([]);
|
|
663
|
+
await waitFor(() => {
|
|
664
|
+
expect(getSearch()).not.toContain('_rowGrouping');
|
|
665
|
+
});
|
|
666
|
+
});
|
|
667
|
+
},
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// ---------------------------------------------------------------------------
|
|
671
|
+
// Aggregation — set via apiRef, assert URL
|
|
672
|
+
// ---------------------------------------------------------------------------
|
|
673
|
+
|
|
674
|
+
let _aggregationRouter: ReturnType<typeof createMockRouter>;
|
|
675
|
+
let _aggregationApiRef: ReturnType<typeof useGridApiRef>;
|
|
676
|
+
|
|
677
|
+
export const AggregationInteraction: Story = {
|
|
678
|
+
render: () => {
|
|
679
|
+
_aggregationRouter = usePersistentMockRouter();
|
|
680
|
+
_aggregationApiRef = useGridApiRef();
|
|
681
|
+
return <Example useRouter={_aggregationRouter.useRouter} apiRef={_aggregationApiRef} />;
|
|
682
|
+
},
|
|
683
|
+
play: async ({ canvasElement, step }) => {
|
|
684
|
+
const canvas = within(canvasElement);
|
|
685
|
+
const { getSearch } = _aggregationRouter;
|
|
686
|
+
|
|
687
|
+
await step('Wait for grid to load', async () => {
|
|
688
|
+
await waitForGridToLoad(canvas);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
await step('Set aggregation Paid=sum', async () => {
|
|
692
|
+
_aggregationApiRef.current!.setAggregationModel({ Paid: 'sum' });
|
|
693
|
+
await waitFor(() => {
|
|
694
|
+
expect(getSearch()).toContain('_aggregation=Paid.sum');
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
await step('Assert sync', async () => {
|
|
699
|
+
await assertAllStatesInSync({ getSearch, checkAggregation: true });
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
await step('Clear aggregation', async () => {
|
|
703
|
+
_aggregationApiRef.current!.setAggregationModel({});
|
|
704
|
+
await waitFor(() => {
|
|
705
|
+
expect(getSearch()).not.toContain('_aggregation');
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
},
|
|
709
|
+
};
|
|
710
|
+
|
|
630
711
|
// ---------------------------------------------------------------------------
|
|
631
712
|
// Column Order — reorder via apiRef, assert URL
|
|
632
713
|
// ---------------------------------------------------------------------------
|
|
633
714
|
|
|
634
715
|
let _columnOrderRouter: ReturnType<typeof createMockRouter>;
|
|
635
|
-
let _columnOrderApiRef:
|
|
716
|
+
let _columnOrderApiRef: ReturnType<typeof useGridApiRef>;
|
|
636
717
|
|
|
637
718
|
export const ColumnOrderInteraction: Story = {
|
|
638
719
|
render: () => {
|
|
@@ -669,6 +750,52 @@ export const ColumnOrderInteraction: Story = {
|
|
|
669
750
|
},
|
|
670
751
|
};
|
|
671
752
|
|
|
753
|
+
// ---------------------------------------------------------------------------
|
|
754
|
+
// Pivot — activate via apiRef, assert URL
|
|
755
|
+
// ---------------------------------------------------------------------------
|
|
756
|
+
|
|
757
|
+
let _pivotRouter: ReturnType<typeof createMockRouter>;
|
|
758
|
+
let _pivotApiRef: ReturnType<typeof useGridApiRef>;
|
|
759
|
+
|
|
760
|
+
export const PivotInteraction: Story = {
|
|
761
|
+
render: () => {
|
|
762
|
+
_pivotRouter = usePersistentMockRouter();
|
|
763
|
+
_pivotApiRef = useGridApiRef();
|
|
764
|
+
return <Example useRouter={_pivotRouter.useRouter} apiRef={_pivotApiRef} />;
|
|
765
|
+
},
|
|
766
|
+
play: async ({ canvasElement, step }) => {
|
|
767
|
+
const canvas = within(canvasElement);
|
|
768
|
+
const { getSearch } = _pivotRouter;
|
|
769
|
+
|
|
770
|
+
await step('Wait for grid to load', async () => {
|
|
771
|
+
await waitForGridToLoad(canvas);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
await step('Activate pivot with Category columns, Items rows, Paid sum values', async () => {
|
|
775
|
+
_pivotApiRef.current!.setPivotModel({
|
|
776
|
+
columns: [{ field: 'Category' }],
|
|
777
|
+
rows: [{ field: 'Items' }],
|
|
778
|
+
values: [{ field: 'Paid', aggFunc: 'sum' }],
|
|
779
|
+
});
|
|
780
|
+
_pivotApiRef.current!.setPivotActive(true);
|
|
781
|
+
await waitFor(() => {
|
|
782
|
+
expect(getSearch()).toContain('_pivot=');
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
await step('Assert pivot params in URL', async () => {
|
|
787
|
+
const search = getSearch();
|
|
788
|
+
expect(search).toContain('cols:Category');
|
|
789
|
+
expect(search).toContain('rows:Items');
|
|
790
|
+
expect(search).toContain('vals:Paid.sum');
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
await step('Assert sync', async () => {
|
|
794
|
+
await assertAllStatesInSync({ getSearch, checkPivot: true });
|
|
795
|
+
});
|
|
796
|
+
},
|
|
797
|
+
};
|
|
798
|
+
|
|
672
799
|
// ---------------------------------------------------------------------------
|
|
673
800
|
// State variants — with interaction assertions
|
|
674
801
|
// ---------------------------------------------------------------------------
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { StatefulDataGrid } from '@redsift/table';
|
|
2
|
+
import { StatefulDataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
|
-
import { GridFilterModel, GridRowSelectionModel, useGridApiRef } from '@mui/x-data-grid-
|
|
5
|
-
import type {
|
|
4
|
+
import { GridFilterModel, GridRowSelectionModel, useGridApiRef } from '@mui/x-data-grid-premium';
|
|
5
|
+
import type { GridApiPremium } from '@mui/x-data-grid-premium';
|
|
6
6
|
import { rows } from '../_shared/data';
|
|
7
7
|
import { columns } from '../_shared/columns';
|
|
8
8
|
import { CustomToolbar, BulkActionBar } from '../_shared/helpers';
|
|
@@ -13,20 +13,20 @@ import { StateDebugPanel } from '../_shared/StateDebugPanel';
|
|
|
13
13
|
interface Props {
|
|
14
14
|
initialFilterModel?: GridFilterModel;
|
|
15
15
|
useRouter?: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
|
|
16
|
-
apiRef?: React.MutableRefObject<
|
|
16
|
+
apiRef?: React.MutableRefObject<GridApiPremium | null>;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: propsApiRef }: Props) => {
|
|
20
20
|
const internalApiRef = useGridApiRef();
|
|
21
21
|
const apiRef = propsApiRef ?? internalApiRef;
|
|
22
|
-
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(
|
|
22
|
+
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<div style={{ width: '100%' }}>
|
|
26
26
|
<StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
|
|
27
27
|
<Flexbox flexDirection="column" gap="0px">
|
|
28
28
|
<BulkActionBar
|
|
29
|
-
count={selectionModel
|
|
29
|
+
count={getSelectionCount(selectionModel)}
|
|
30
30
|
onLog={() => console.log('Selected:', selectionModel)}
|
|
31
31
|
onDelete={() => console.log('Delete:', selectionModel)}
|
|
32
32
|
/>
|
|
@@ -2,8 +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, useGridApiRef } from '@mui/x-data-grid-
|
|
6
|
-
import type { GridApiPro } from '@mui/x-data-grid-pro';
|
|
5
|
+
import { GridFilterModel, useGridApiRef } from '@mui/x-data-grid-premium';
|
|
7
6
|
|
|
8
7
|
import Example from './example';
|
|
9
8
|
import WithLoadingExample from './with-loading';
|
|
@@ -387,9 +386,7 @@ export const SelectionPersistsAcrossPages: Story = {
|
|
|
387
386
|
await waitForServerResponse(canvas);
|
|
388
387
|
await assertDisplayedRowsText(canvasElement, '11–20 of 14,075');
|
|
389
388
|
await assertBulkActionBarVisible(canvasElement, 2);
|
|
390
|
-
|
|
391
|
-
// No page-2 rows are selected, so the header is unchecked (not indeterminate).
|
|
392
|
-
await assertHeaderCheckboxState(canvasElement, 'unchecked');
|
|
389
|
+
await assertHeaderCheckboxState(canvasElement, 'indeterminate');
|
|
393
390
|
await assertRowCheckboxChecked(canvasElement, 0, false);
|
|
394
391
|
await assertAllStatesInSync({ getSearch });
|
|
395
392
|
});
|
|
@@ -648,12 +645,98 @@ export const SortingInteraction: Story = {
|
|
|
648
645
|
},
|
|
649
646
|
};
|
|
650
647
|
|
|
648
|
+
// ---------------------------------------------------------------------------
|
|
649
|
+
// Row Grouping — set via apiRef, assert URL
|
|
650
|
+
// ---------------------------------------------------------------------------
|
|
651
|
+
|
|
652
|
+
let _rowGroupingRouter: ReturnType<typeof createMockRouter>;
|
|
653
|
+
let _rowGroupingApiRef: ReturnType<typeof useGridApiRef>;
|
|
654
|
+
|
|
655
|
+
export const RowGroupingInteraction: Story = {
|
|
656
|
+
render: () => {
|
|
657
|
+
_rowGroupingRouter = usePersistentMockRouter();
|
|
658
|
+
_rowGroupingApiRef = useGridApiRef();
|
|
659
|
+
return <Example useRouter={_rowGroupingRouter.useRouter} apiRef={_rowGroupingApiRef} />;
|
|
660
|
+
},
|
|
661
|
+
play: async ({ canvasElement, step }) => {
|
|
662
|
+
const canvas = within(canvasElement);
|
|
663
|
+
const { getSearch } = _rowGroupingRouter;
|
|
664
|
+
|
|
665
|
+
await step('Wait for grid to load', async () => {
|
|
666
|
+
await waitForGridToLoad(canvas);
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
await step('Set row grouping to Category', async () => {
|
|
670
|
+
_rowGroupingApiRef.current!.setRowGroupingModel(['Category']);
|
|
671
|
+
await waitForServerResponse(canvas);
|
|
672
|
+
await waitFor(() => {
|
|
673
|
+
expect(getSearch()).toContain('_rowGrouping=Category');
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
await step('Assert sync', async () => {
|
|
678
|
+
await assertAllStatesInSync({ getSearch, checkRowGrouping: true });
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
await step('Clear row grouping', async () => {
|
|
682
|
+
_rowGroupingApiRef.current!.setRowGroupingModel([]);
|
|
683
|
+
await waitForServerResponse(canvas);
|
|
684
|
+
await waitFor(() => {
|
|
685
|
+
expect(getSearch()).not.toContain('_rowGrouping');
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
},
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
// ---------------------------------------------------------------------------
|
|
692
|
+
// Aggregation — set via apiRef, assert URL
|
|
693
|
+
// ---------------------------------------------------------------------------
|
|
694
|
+
|
|
695
|
+
let _aggregationRouter: ReturnType<typeof createMockRouter>;
|
|
696
|
+
let _aggregationApiRef: ReturnType<typeof useGridApiRef>;
|
|
697
|
+
|
|
698
|
+
export const AggregationInteraction: Story = {
|
|
699
|
+
render: () => {
|
|
700
|
+
_aggregationRouter = usePersistentMockRouter();
|
|
701
|
+
_aggregationApiRef = useGridApiRef();
|
|
702
|
+
return <Example useRouter={_aggregationRouter.useRouter} apiRef={_aggregationApiRef} />;
|
|
703
|
+
},
|
|
704
|
+
play: async ({ canvasElement, step }) => {
|
|
705
|
+
const canvas = within(canvasElement);
|
|
706
|
+
const { getSearch } = _aggregationRouter;
|
|
707
|
+
|
|
708
|
+
await step('Wait for grid to load', async () => {
|
|
709
|
+
await waitForGridToLoad(canvas);
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
await step('Set aggregation Paid=sum', async () => {
|
|
713
|
+
_aggregationApiRef.current!.setAggregationModel({ Paid: 'sum' });
|
|
714
|
+
await waitForServerResponse(canvas);
|
|
715
|
+
await waitFor(() => {
|
|
716
|
+
expect(getSearch()).toContain('_aggregation=Paid.sum');
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
await step('Assert sync', async () => {
|
|
721
|
+
await assertAllStatesInSync({ getSearch, checkAggregation: true });
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
await step('Clear aggregation', async () => {
|
|
725
|
+
_aggregationApiRef.current!.setAggregationModel({});
|
|
726
|
+
await waitForServerResponse(canvas);
|
|
727
|
+
await waitFor(() => {
|
|
728
|
+
expect(getSearch()).not.toContain('_aggregation');
|
|
729
|
+
});
|
|
730
|
+
});
|
|
731
|
+
},
|
|
732
|
+
};
|
|
733
|
+
|
|
651
734
|
// ---------------------------------------------------------------------------
|
|
652
735
|
// Column Order — reorder via apiRef, assert URL
|
|
653
736
|
// ---------------------------------------------------------------------------
|
|
654
737
|
|
|
655
738
|
let _columnOrderRouter: ReturnType<typeof createMockRouter>;
|
|
656
|
-
let _columnOrderApiRef:
|
|
739
|
+
let _columnOrderApiRef: ReturnType<typeof useGridApiRef>;
|
|
657
740
|
|
|
658
741
|
export const ColumnOrderInteraction: Story = {
|
|
659
742
|
render: () => {
|
|
@@ -690,6 +773,53 @@ export const ColumnOrderInteraction: Story = {
|
|
|
690
773
|
},
|
|
691
774
|
};
|
|
692
775
|
|
|
776
|
+
// ---------------------------------------------------------------------------
|
|
777
|
+
// Pivot — activate via apiRef, assert URL
|
|
778
|
+
// ---------------------------------------------------------------------------
|
|
779
|
+
|
|
780
|
+
let _pivotRouter: ReturnType<typeof createMockRouter>;
|
|
781
|
+
let _pivotApiRef: ReturnType<typeof useGridApiRef>;
|
|
782
|
+
|
|
783
|
+
export const PivotInteraction: Story = {
|
|
784
|
+
render: () => {
|
|
785
|
+
_pivotRouter = usePersistentMockRouter();
|
|
786
|
+
_pivotApiRef = useGridApiRef();
|
|
787
|
+
return <Example useRouter={_pivotRouter.useRouter} apiRef={_pivotApiRef} />;
|
|
788
|
+
},
|
|
789
|
+
play: async ({ canvasElement, step }) => {
|
|
790
|
+
const canvas = within(canvasElement);
|
|
791
|
+
const { getSearch } = _pivotRouter;
|
|
792
|
+
|
|
793
|
+
await step('Wait for grid to load', async () => {
|
|
794
|
+
await waitForGridToLoad(canvas);
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
await step('Activate pivot with Category columns, Items rows, Paid sum values', async () => {
|
|
798
|
+
_pivotApiRef.current!.setPivotModel({
|
|
799
|
+
columns: [{ field: 'Category' }],
|
|
800
|
+
rows: [{ field: 'Items' }],
|
|
801
|
+
values: [{ field: 'Paid', aggFunc: 'sum' }],
|
|
802
|
+
});
|
|
803
|
+
_pivotApiRef.current!.setPivotActive(true);
|
|
804
|
+
await waitForServerResponse(canvas);
|
|
805
|
+
await waitFor(() => {
|
|
806
|
+
expect(getSearch()).toContain('_pivot=');
|
|
807
|
+
});
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
await step('Assert pivot params in URL', async () => {
|
|
811
|
+
const search = getSearch();
|
|
812
|
+
expect(search).toContain('cols:Category');
|
|
813
|
+
expect(search).toContain('rows:Items');
|
|
814
|
+
expect(search).toContain('vals:Paid.sum');
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
await step('Assert sync', async () => {
|
|
818
|
+
await assertAllStatesInSync({ getSearch, checkPivot: true });
|
|
819
|
+
});
|
|
820
|
+
},
|
|
821
|
+
};
|
|
822
|
+
|
|
693
823
|
// ---------------------------------------------------------------------------
|
|
694
824
|
// State variants — with interaction assertions
|
|
695
825
|
// ---------------------------------------------------------------------------
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { StatefulDataGrid } from '@redsift/table';
|
|
2
|
+
import { StatefulDataGrid, EMPTY_ROW_SELECTION_MODEL, getSelectionCount } from '@redsift/table';
|
|
3
3
|
import { Flexbox } from '@redsift/design-system';
|
|
4
|
-
import { GridFilterModel, GridRowSelectionModel, GridSortModel, useGridApiRef } from '@mui/x-data-grid-
|
|
5
|
-
import type {
|
|
4
|
+
import { GridFilterModel, GridRowSelectionModel, GridSortModel, useGridApiRef } from '@mui/x-data-grid-premium';
|
|
5
|
+
import type { GridApiPremium } from '@mui/x-data-grid-premium';
|
|
6
6
|
import { Row } from '../_shared/data';
|
|
7
7
|
import { columns } from '../_shared/columns';
|
|
8
8
|
import { fetchBakeryData } from '../_shared/api-client';
|
|
@@ -14,7 +14,7 @@ import { StateDebugPanel } from '../_shared/StateDebugPanel';
|
|
|
14
14
|
interface Props {
|
|
15
15
|
initialFilterModel?: GridFilterModel;
|
|
16
16
|
useRouter?: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
|
|
17
|
-
apiRef?: React.MutableRefObject<
|
|
17
|
+
apiRef?: React.MutableRefObject<GridApiPremium | null>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: propsApiRef }: Props) => {
|
|
@@ -23,7 +23,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
|
|
|
23
23
|
const [rows, setRows] = useState<Row[]>([]);
|
|
24
24
|
const [totalRows, setTotalRows] = useState(0);
|
|
25
25
|
const [loading, setLoading] = useState(true);
|
|
26
|
-
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(
|
|
26
|
+
const [selectionModel, setSelectionModel] = useState<GridRowSelectionModel>(EMPTY_ROW_SELECTION_MODEL);
|
|
27
27
|
|
|
28
28
|
// Refs track the latest model values so fetchData() always reads current state.
|
|
29
29
|
// StatefulDataGrid manages filter/sort/pagination internally — we use callbacks
|
|
@@ -58,7 +58,7 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
|
|
|
58
58
|
<StateDebugPanel apiRef={apiRef} useRouter={useRouter} localStorageVersion={1} />
|
|
59
59
|
<Flexbox flexDirection="column" gap="0px">
|
|
60
60
|
<BulkActionBar
|
|
61
|
-
count={selectionModel
|
|
61
|
+
count={getSelectionCount(selectionModel)}
|
|
62
62
|
onLog={() => console.log('Selected:', selectionModel)}
|
|
63
63
|
onDelete={() => console.log('Delete:', selectionModel)}
|
|
64
64
|
/>
|
|
@@ -94,9 +94,6 @@ export default ({ initialFilterModel, useRouter = useRouterAdapter, apiRef: prop
|
|
|
94
94
|
fetchData();
|
|
95
95
|
}}
|
|
96
96
|
onPaginationModelChange={(model) => {
|
|
97
|
-
if (model.pageSize !== pageSizeRef.current) {
|
|
98
|
-
setRows([]);
|
|
99
|
-
}
|
|
100
97
|
pageRef.current = model.page;
|
|
101
98
|
pageSizeRef.current = model.pageSize;
|
|
102
99
|
fetchData();
|
|
@@ -24,9 +24,9 @@ import {
|
|
|
24
24
|
} from '../_shared/story-helpers';
|
|
25
25
|
import { AGG_CATEGORY, AGG_ALLERGENS, AGG_INSTOCK } from '../_shared/expected-values';
|
|
26
26
|
|
|
27
|
-
const meta: Meta
|
|
27
|
+
const meta: Meta = {
|
|
28
28
|
title: 'Patterns/Summary Dashboard',
|
|
29
|
-
component: Example,
|
|
29
|
+
component: Example as any,
|
|
30
30
|
};
|
|
31
31
|
export default meta;
|
|
32
32
|
type Story = StoryObj;
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
} from '../_shared/story-helpers';
|
|
18
18
|
import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
|
|
19
19
|
|
|
20
|
-
const meta: Meta
|
|
20
|
+
const meta: Meta = {
|
|
21
21
|
title: 'Patterns/Tabbed Datagrid (Client)',
|
|
22
|
-
component: Example,
|
|
22
|
+
component: Example as any,
|
|
23
23
|
};
|
|
24
24
|
export default meta;
|
|
25
25
|
type Story = StoryObj;
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
} from '../_shared/story-helpers';
|
|
20
20
|
import { TOTAL, CATEGORY_BAKERY, CATEGORY_BEVERAGE, CATEGORY_PASTRY, CATEGORY_OTHER } from '../_shared/expected-values';
|
|
21
21
|
|
|
22
|
-
const meta: Meta
|
|
22
|
+
const meta: Meta = {
|
|
23
23
|
title: 'Patterns/Tabbed Datagrid (Server)',
|
|
24
|
-
component: Example,
|
|
24
|
+
component: Example as any,
|
|
25
25
|
parameters: {
|
|
26
26
|
msw: { handlers: bakeryHandlers },
|
|
27
27
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { DataGrid } from '@redsift/table';
|
|
3
3
|
import { Flexbox, Pill, Number, Text, Tabs, Tab } from '@redsift/design-system';
|
|
4
|
-
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-
|
|
4
|
+
import { GridFilterModel, GridSortModel } from '@mui/x-data-grid-premium';
|
|
5
5
|
import { Row } from '../_shared/data';
|
|
6
6
|
import { columns, CATEGORY_OPTIONS } from '../_shared/columns';
|
|
7
7
|
import { fetchBakeryData } from '../_shared/api-client';
|