feat(Gridler): add isValuesInPages method and update state handling

* Introduce isValuesInPages method to check if values exist in paginated data.
* Update state management in GlidlerAPIAdaptorForGoLangv2 to clear values when no pages are found.
This commit is contained in:
Hein
2026-01-23 10:57:32 +02:00
parent 070e56e1af
commit ecb90c69aa
4 changed files with 39 additions and 66 deletions

View File

@@ -55,7 +55,6 @@
"devDependencies": { "devDependencies": {
"@changesets/cli": "^2.29.7", "@changesets/cli": "^2.29.7",
"@eslint/js": "^9.38.0", "@eslint/js": "^9.38.0",
"@storybook/react": "^10.2.0",
"@storybook/react-vite": "^9.1.15", "@storybook/react-vite": "^9.1.15",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0", "@testing-library/react": "^16.3.0",

59
pnpm-lock.yaml generated
View File

@@ -60,9 +60,6 @@ importers:
'@eslint/js': '@eslint/js':
specifier: ^9.38.0 specifier: ^9.38.0
version: 9.38.0 version: 9.38.0
'@storybook/react':
specifier: ^10.2.0
version: 10.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)
'@storybook/react-vite': '@storybook/react-vite':
specifier: ^9.1.15 specifier: ^9.1.15
version: 9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.50.2)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))) version: 9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.50.2)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6)))
@@ -929,13 +926,6 @@ packages:
'@storybook/global@5.0.0': '@storybook/global@5.0.0':
resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==}
'@storybook/react-dom-shim@10.2.0':
resolution: {integrity: sha512-PEQofiruE6dBGzUQPXZZREbuh1t62uRBWoUPRFNAZi79zddlk7+b9qu08VV9cvf68mwOqqT1+VJ1P+3ClD2ZVw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
storybook: ^10.2.0
'@storybook/react-dom-shim@9.1.15': '@storybook/react-dom-shim@9.1.15':
resolution: {integrity: sha512-l6smvNwxh6kp2U/BupzQ4/NSraTWysZcAe2x+GO5CiIIB8Jbi41XLu5XIHI/GQRnNqpXXE3uMImiHGOORmHEXA==} resolution: {integrity: sha512-l6smvNwxh6kp2U/BupzQ4/NSraTWysZcAe2x+GO5CiIIB8Jbi41XLu5XIHI/GQRnNqpXXE3uMImiHGOORmHEXA==}
peerDependencies: peerDependencies:
@@ -952,17 +942,6 @@ packages:
storybook: ^9.1.15 storybook: ^9.1.15
vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vite: ^5.0.0 || ^6.0.0 || ^7.0.0
'@storybook/react@10.2.0':
resolution: {integrity: sha512-ciJlh1UGm0GBXQgqrYFeLmiix+KGFB3v37OnAYjGghPS9OP6S99XyshxY/6p0sMOYtS+eWS2gPsOKNXNnLDGYw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
storybook: ^10.2.0
typescript: '>= 4.9.x'
peerDependenciesMeta:
typescript:
optional: true
'@storybook/react@9.1.15': '@storybook/react@9.1.15':
resolution: {integrity: sha512-tdd1Od3roaEQ2rjqk1L15yR/N2y/SLNcpPNp3n9AQT1eDPdbKzIzue7u1eW9KUFdwSF9S8xG35roDUkKwBJogQ==} resolution: {integrity: sha512-tdd1Od3roaEQ2rjqk1L15yR/N2y/SLNcpPNp3n9AQT1eDPdbKzIzue7u1eW9KUFdwSF9S8xG35roDUkKwBJogQ==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
@@ -2881,10 +2860,6 @@ packages:
resolution: {integrity: sha512-kQKsqPLplY3Hx4jGnM3jpQcG3FQDt7ySz32uTHt3C9HAe45kNXG+3o16Eqn3Fw1GtMfHoN3b4J/z2e6cZJCmqQ==} resolution: {integrity: sha512-kQKsqPLplY3Hx4jGnM3jpQcG3FQDt7ySz32uTHt3C9HAe45kNXG+3o16Eqn3Fw1GtMfHoN3b4J/z2e6cZJCmqQ==}
engines: {node: ^20.9.0 || >=22} engines: {node: ^20.9.0 || >=22}
react-docgen@8.0.2:
resolution: {integrity: sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==}
engines: {node: ^20.9.0 || >=22}
react-dom@19.2.0: react-dom@19.2.0:
resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==}
peerDependencies: peerDependencies:
@@ -4553,12 +4528,6 @@ snapshots:
'@storybook/global@5.0.0': {} '@storybook/global@5.0.0': {}
'@storybook/react-dom-shim@10.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))':
dependencies:
react: 19.2.0
react-dom: 19.2.0(react@19.2.0)
storybook: 9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6)))
'@storybook/react-dom-shim@9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))': '@storybook/react-dom-shim@9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))':
dependencies: dependencies:
react: 19.2.0 react: 19.2.0
@@ -4585,19 +4554,6 @@ snapshots:
- supports-color - supports-color
- typescript - typescript
'@storybook/react@10.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)':
dependencies:
'@storybook/global': 5.0.0
'@storybook/react-dom-shim': 10.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))
react: 19.2.0
react-docgen: 8.0.2
react-dom: 19.2.0(react@19.2.0)
storybook: 9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6)))
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@storybook/react@9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)': '@storybook/react@9.1.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.15(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.6))))(typescript@5.9.3)':
dependencies: dependencies:
'@storybook/global': 5.0.0 '@storybook/global': 5.0.0
@@ -6768,21 +6724,6 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
react-docgen@8.0.2:
dependencies:
'@babel/core': 7.28.4
'@babel/traverse': 7.28.4
'@babel/types': 7.28.4
'@types/babel__core': 7.20.5
'@types/babel__traverse': 7.28.0
'@types/doctrine': 0.0.9
'@types/resolve': 1.20.6
doctrine: 3.0.0
resolve: 1.22.10
strip-indent: 4.1.0
transitivePeerDependencies:
- supports-color
react-dom@19.2.0(react@19.2.0): react-dom@19.2.0(react@19.2.0):
dependencies: dependencies:
react: 19.2.0 react: 19.2.0

View File

@@ -162,6 +162,7 @@ export interface GridlerState {
hasLocalData: boolean; hasLocalData: boolean;
isEmpty: boolean; isEmpty: boolean;
isValuesInPages: () => boolean
loadingData?: boolean; loadingData?: boolean;
loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>; loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>;
mounted: boolean; mounted: boolean;
@@ -180,6 +181,7 @@ export interface GridlerState {
onHeaderClicked: (colIndex: number, event: HeaderClickedEventArgs) => void; onHeaderClicked: (colIndex: number, event: HeaderClickedEventArgs) => void;
onHeaderMenuClick: (col: number, screenPosition: Rectangle) => void; onHeaderMenuClick: (col: number, screenPosition: Rectangle) => void;
onItemHovered: (args: GridMouseEventArgs) => void; onItemHovered: (args: GridMouseEventArgs) => void;
onVisibleRegionChanged: ( onVisibleRegionChanged: (
r: Rectangle, r: Rectangle,
tx: number, tx: number,
@@ -189,14 +191,14 @@ export interface GridlerState {
freezeRegions?: readonly Rectangle[]; freezeRegions?: readonly Rectangle[];
selected?: Item; selected?: Item;
} }
) => void; ) => void;
pageSize: number; pageSize: number;
ready: boolean; ready: boolean;
refreshCells: (fromRow?: number, toRow?: number, col?: number) => void; refreshCells: (fromRow?: number, toRow?: number, col?: number) => void;
reload?: () => Promise<void>;
reload?: () => Promise<void>;
renderColumns?: GridlerColumns; renderColumns?: GridlerColumns;
setState: <K extends keyof GridlerStoreState>( setState: <K extends keyof GridlerStoreState>(
key: K, key: K,
@@ -378,6 +380,31 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
}, },
hasLocalData: false, hasLocalData: false,
isEmpty: true, isEmpty: true,
isValuesInPages: () => {
const state = get();
if (state.values && Object.keys(state._page_data).length > 0) {
let found = false;
for (const page in state._page_data) {
const pageData = state._page_data[Number(page)];
for (const row of pageData) {
const keyField = state.keyField ?? 'id';
const rowKey = row?.[keyField];
if (rowKey !== undefined) {
const match = state.values.find((v) => String(v?.[keyField]) === String(rowKey));
if (match) {
found = true;
break;
}
}
}
if (found) {
return true;
}
}
}
return false
},
keyField: 'id', keyField: 'id',
loadPage: async (pPage: number, clearMode?: 'all' | 'page') => { loadPage: async (pPage: number, clearMode?: 'all' | 'page') => {
const state = get(); const state = get();
@@ -511,6 +538,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
return { ...renderCols, [fromItem?.id]: to, [toItem?.id]: from }; return { ...renderCols, [fromItem?.id]: to, [toItem?.id]: from };
}); });
}, },
onColumnProposeMove: (startIndex: number, endIndex: number) => { onColumnProposeMove: (startIndex: number, endIndex: number) => {
const s = get(); const s = get();
const fromItem = s.renderColumns?.[startIndex]; const fromItem = s.renderColumns?.[startIndex];
@@ -520,7 +548,6 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
} }
return true; return true;
}, },
onColumnResize: ( onColumnResize: (
column: GridColumn, column: GridColumn,
newSize: number, newSize: number,
@@ -922,7 +949,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
} }
}, },
total_rows: 1000, total_rows: 1000,
uniqueid: getUUID(), uniqueid: getUUID()
}), }),
(props) => { (props) => {
const [setState, getState] = props.useStore((s) => [s.setState, s.getState]); const [setState, getState] = props.useStore((s) => [s.setState, s.getState]);

View File

@@ -272,8 +272,12 @@ function _GlidlerAPIAdaptorForGoLangv2<T = unknown>(props: GlidlerAPIAdaptorForG
useEffect(() => { useEffect(() => {
setState('useAPIQuery', useAPIQuery); setState('useAPIQuery', useAPIQuery);
setState('askAPIRowNumber', askAPIRowNumber); setState('askAPIRowNumber', askAPIRowNumber);
const isValuesInPages = getState('isValuesInPages');
const _refresh = getState('_refresh'); const _refresh = getState('_refresh');
if (!isValuesInPages) {
setState('values', []);
}
//Reset the loaded pages to new rules //Reset the loaded pages to new rules
_refresh?.().then(() => { _refresh?.().then(() => {
@@ -289,6 +293,8 @@ function _GlidlerAPIAdaptorForGoLangv2<T = unknown>(props: GlidlerAPIAdaptorForG
return <></>; return <></>;
} }
//The computer component does not need to be recalculated on every render, so we use React.memo to prevent unnecessary re-renders. //The computer component does not need to be recalculated on every render, so we use React.memo to prevent unnecessary re-renders.
export const GlidlerAPIAdaptorForGoLangv2 = React.memo(_GlidlerAPIAdaptorForGoLangv2); export const GlidlerAPIAdaptorForGoLangv2 = React.memo(_GlidlerAPIAdaptorForGoLangv2);