@redsift/ds-mcp-server 12.4.0 → 12.5.0-muiv7
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 +153 -0
- 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 +578 -14
- package/data/demos/patterns/_shared/use-router-adapter.ts +51 -0
- package/data/demos/patterns/crossfiltered-datagrid-client-side/CrossfilteredDatagridClientSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/crossfiltered-datagrid-client-side/example.tsx +2 -2
- package/data/demos/patterns/crossfiltered-datagrid-server-side/CrossfilteredDatagridServerSide.interaction.stories.tsx +2 -2
- package/data/demos/patterns/crossfiltered-datagrid-server-side/example.tsx +6 -6
- 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 +1 -1
- package/data/demos/patterns/single-datagrid-client-side/SingleDatagridClientSide.interaction.stories.tsx +382 -169
- package/data/demos/patterns/single-datagrid-client-side/example.tsx +6 -6
- package/data/demos/patterns/single-datagrid-client-side/with-empty-state.tsx +1 -1
- package/data/demos/patterns/single-datagrid-client-side/with-error.tsx +1 -1
- package/data/demos/patterns/single-datagrid-client-side/with-loading.tsx +1 -1
- package/data/demos/patterns/single-datagrid-server-side/SingleDatagridServerSide.interaction.stories.tsx +426 -54
- package/data/demos/patterns/single-datagrid-server-side/example.tsx +6 -5
- package/data/demos/patterns/stateful-single-datagrid-client-side/StatefulSingleDatagridClientSide.interaction.stories.tsx +671 -0
- package/data/demos/patterns/stateful-single-datagrid-client-side/example.tsx +55 -0
- package/data/demos/patterns/stateful-single-datagrid-client-side/with-empty-state.tsx +27 -0
- package/data/demos/patterns/stateful-single-datagrid-client-side/with-error.tsx +39 -0
- package/data/demos/patterns/stateful-single-datagrid-client-side/with-loading.tsx +25 -0
- package/data/demos/patterns/stateful-single-datagrid-server-side/StatefulSingleDatagridServerSide.interaction.stories.tsx +692 -0
- package/data/demos/patterns/stateful-single-datagrid-server-side/example.tsx +108 -0
- package/data/demos/patterns/stateful-single-datagrid-server-side/with-empty-state.tsx +31 -0
- package/data/demos/patterns/stateful-single-datagrid-server-side/with-error.tsx +43 -0
- package/data/demos/patterns/stateful-single-datagrid-server-side/with-loading.tsx +29 -0
- package/data/demos/patterns/summary-dashboard/SummaryDashboard.interaction.stories.tsx +44 -24
- package/data/demos/patterns/summary-dashboard/example.tsx +66 -28
- package/data/demos/patterns/summary-dashboard/with-loading.tsx +12 -3
- 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/dashboard/Dashboard.json +2 -2
- package/data/docs/components/table/DataGrid.json +30 -3
- package/data/docs/components/table/StatefulDataGrid.json +30 -3
- package/data/docs/components-index.json +2 -2
- package/data/docs/components.json +64 -10
- package/data/docs/llms-full.txt +799 -44
- package/data/docs/llms.txt +20 -6
- package/data/docs/patterns-catalog.md +25 -24
- package/data/docs/patterns.json +82 -8
- 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 +6 -6
- package/data/patterns/stateful-single-datagrid-client-side.mdx +304 -0
- package/data/patterns/stateful-single-datagrid-server-side.mdx +347 -0
- package/data/patterns/summary-dashboard.mdx +47 -7
- package/data/patterns/tabbed-datagrid-client-side.mdx +72 -2
- package/data/patterns/tabbed-datagrid-server-side.mdx +105 -2
- package/package.json +2 -2
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import type { GridApiPro } from '@mui/x-data-grid-pro/models/gridApiPro';
|
|
3
|
+
|
|
4
|
+
// localStorage key categories — must match @redsift/table internals
|
|
5
|
+
const LS_CATEGORIES = [
|
|
6
|
+
'paginationModel',
|
|
7
|
+
'searchModel',
|
|
8
|
+
'sortModel',
|
|
9
|
+
'visibilityModel',
|
|
10
|
+
'pinnedColumns',
|
|
11
|
+
'dimension',
|
|
12
|
+
'densityModel',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
interface StateDebugPanelProps {
|
|
16
|
+
apiRef: React.MutableRefObject<GridApiPro>;
|
|
17
|
+
useRouter: () => { pathname: string; search: string; historyReplace: (newSearch: string) => void };
|
|
18
|
+
localStorageVersion?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sectionStyle: React.CSSProperties = {
|
|
22
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
|
23
|
+
fontSize: '11px',
|
|
24
|
+
lineHeight: '1.4',
|
|
25
|
+
padding: '8px 12px',
|
|
26
|
+
borderRadius: '4px',
|
|
27
|
+
overflow: 'auto',
|
|
28
|
+
maxHeight: '200px',
|
|
29
|
+
whiteSpace: 'pre-wrap',
|
|
30
|
+
wordBreak: 'break-all',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const labelStyle: React.CSSProperties = {
|
|
34
|
+
fontFamily: 'inherit',
|
|
35
|
+
fontSize: '11px',
|
|
36
|
+
fontWeight: 600,
|
|
37
|
+
cursor: 'pointer',
|
|
38
|
+
userSelect: 'none',
|
|
39
|
+
display: 'flex',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
gap: '4px',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Reads the real DataGrid state from apiRef, URL from useRouter, and localStorage keys.
|
|
46
|
+
* Renders three collapsible JSON panels for debugging.
|
|
47
|
+
*/
|
|
48
|
+
export const StateDebugPanel: React.FC<StateDebugPanelProps> = ({ apiRef, useRouter, localStorageVersion = 1 }) => {
|
|
49
|
+
const { pathname, search } = useRouter();
|
|
50
|
+
const [_tick, setTick] = useState(0);
|
|
51
|
+
const rerender = useCallback(() => setTick((t) => t + 1), []);
|
|
52
|
+
|
|
53
|
+
// Subscribe to grid events so we re-read state after every change
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const api = apiRef.current;
|
|
56
|
+
if (!api?.subscribeEvent) return;
|
|
57
|
+
|
|
58
|
+
const unsubs = [
|
|
59
|
+
api.subscribeEvent('filterModelChange', rerender),
|
|
60
|
+
api.subscribeEvent('sortModelChange', rerender),
|
|
61
|
+
api.subscribeEvent('paginationModelChange', rerender),
|
|
62
|
+
api.subscribeEvent('columnVisibilityModelChange', rerender),
|
|
63
|
+
api.subscribeEvent('pinnedColumnsChange', rerender),
|
|
64
|
+
api.subscribeEvent('stateChange', rerender),
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
return () => unsubs.forEach((u) => u());
|
|
68
|
+
}, [apiRef, rerender]);
|
|
69
|
+
|
|
70
|
+
// Also update after URL changes (historyReplace doesn't trigger re-render)
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
rerender();
|
|
73
|
+
}, [search, rerender]);
|
|
74
|
+
|
|
75
|
+
// -- Read grid state from apiRef --
|
|
76
|
+
let gridState: Record<string, unknown> = {};
|
|
77
|
+
try {
|
|
78
|
+
const api = apiRef.current;
|
|
79
|
+
if (api?.state) {
|
|
80
|
+
gridState = {
|
|
81
|
+
filterModel: api.state.filter?.filterModel ?? null,
|
|
82
|
+
sortModel: api.state.sorting?.sortModel ?? null,
|
|
83
|
+
paginationModel: api.state.pagination?.paginationModel ?? null,
|
|
84
|
+
columnVisibilityModel: api.state.columns?.columnVisibilityModel ?? null,
|
|
85
|
+
pinnedColumns: api.state.pinnedColumns ?? null,
|
|
86
|
+
density: api.state.density ?? null,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
gridState = { error: 'Grid not yet initialized' };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -- Read URL query params --
|
|
94
|
+
const urlParams: Record<string, string> = {};
|
|
95
|
+
const sp = new URLSearchParams(search);
|
|
96
|
+
sp.forEach((v, k) => {
|
|
97
|
+
urlParams[k] = v;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// -- Read localStorage --
|
|
101
|
+
const lsState: Record<string, string | null> = {};
|
|
102
|
+
for (const cat of LS_CATEGORIES) {
|
|
103
|
+
const key = `${pathname}:${localStorageVersion}:${cat}`;
|
|
104
|
+
try {
|
|
105
|
+
const raw = localStorage.getItem(key);
|
|
106
|
+
lsState[cat] = raw;
|
|
107
|
+
} catch {
|
|
108
|
+
lsState[cat] = null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
data-testid="state-debug-panel"
|
|
115
|
+
style={{
|
|
116
|
+
border: '1px solid #e0e0e0',
|
|
117
|
+
borderRadius: '6px',
|
|
118
|
+
padding: '8px 12px',
|
|
119
|
+
marginBottom: '8px',
|
|
120
|
+
background: '#fafafa',
|
|
121
|
+
fontSize: '11px',
|
|
122
|
+
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
|
123
|
+
}}
|
|
124
|
+
>
|
|
125
|
+
<div style={{ fontWeight: 700, marginBottom: '6px', fontSize: '12px' }}>State Inspector</div>
|
|
126
|
+
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
|
127
|
+
<Section title="DataGrid State" data={gridState} bg="#f0f4ff" />
|
|
128
|
+
<Section
|
|
129
|
+
title="URL Query Params"
|
|
130
|
+
data={Object.keys(urlParams).length > 0 ? urlParams : '(empty)'}
|
|
131
|
+
bg="#f0fff4"
|
|
132
|
+
/>
|
|
133
|
+
<Section title="localStorage" data={lsState} bg="#fff8f0" />
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const Section: React.FC<{ title: string; data: unknown; bg: string }> = ({ title, data, bg }) => {
|
|
140
|
+
const [open, setOpen] = useState(true);
|
|
141
|
+
return (
|
|
142
|
+
<div style={{ flex: '1 1 280px', minWidth: '280px' }}>
|
|
143
|
+
<div style={labelStyle} onClick={() => setOpen((o) => !o)}>
|
|
144
|
+
<span>{open ? '▾' : '▸'}</span> {title}
|
|
145
|
+
</div>
|
|
146
|
+
{open && (
|
|
147
|
+
<pre style={{ ...sectionStyle, background: bg, margin: '4px 0 0' }}>
|
|
148
|
+
{typeof data === 'string' ? data : JSON.stringify(data, null, 2)}
|
|
149
|
+
</pre>
|
|
150
|
+
)}
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
};
|
|
@@ -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,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: (value:
|
|
113
|
+
valueGetter: (value: unknown) => 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: (value:
|
|
123
|
+
valueGetter: (value: unknown) => 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-pro';
|
|
2
2
|
import { Row, allRows } from './data';
|
|
3
3
|
import { Aggregates, computeAggregates, applyFilters } from './filter-helpers';
|
|
4
4
|
|