fix(Gridler): 🐛 improve state management and cleanup

* Update `askAPIRowNumber` to return `null` or `number` for better type safety.
* Refactor conditionals to ensure proper handling of row indices.
* Clean up console logs for improved readability and performance.
* Ensure consistent formatting across the codebase.
This commit is contained in:
Hein
2026-02-09 14:41:49 +02:00
parent 31e46e6bd2
commit 6cb50978d0
5 changed files with 41 additions and 38 deletions

View File

@@ -188,6 +188,7 @@ export const GridlerDataGrid = () => {
if (!refContextActivated.current) { if (!refContextActivated.current) {
refContextActivated.current = true; refContextActivated.current = true;
onContextClick('cell', event, cell[0], cell[1]); onContextClick('cell', event, cell[0], cell[1]);
setTimeout(() => { setTimeout(() => {
refContextActivated.current = false; refContextActivated.current = false;
}, 100); }, 100);
@@ -231,7 +232,7 @@ export const GridlerDataGrid = () => {
rows = rows.hasIndex(r) ? rows : rows.add(r); rows = rows.hasIndex(r) ? rows : rows.add(r);
} }
} }
console.log('Debug:onGridSelectionChange', currentSelection, selection); //console.log('Debug:onGridSelectionChange', currentSelection, selection);
if ( if (
JSON.stringify(currentSelection?.columns) !== JSON.stringify(selection.columns) || JSON.stringify(currentSelection?.columns) !== JSON.stringify(selection.columns) ||
JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows) || JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows) ||

View File

@@ -28,7 +28,7 @@ export const Computer = React.memo(() => {
selectFirstRowOnMount, selectFirstRowOnMount,
setState, setState,
setStateFN, setStateFN,
values values,
} = useGridlerStore((s) => ({ } = useGridlerStore((s) => ({
_glideref: s._glideref, _glideref: s._glideref,
_gridSelectionRows: s._gridSelectionRows, _gridSelectionRows: s._gridSelectionRows,
@@ -100,9 +100,12 @@ export const Computer = React.memo(() => {
break; break;
} }
} }
if (!(rowIndex >= 0)) {
if (rowIndex >= 0) {
rowIndexes.push(rowIndex);
} else {
const idx = await getRowIndexByKey(key); const idx = await getRowIndexByKey(key);
if (idx) { if (idx !== null) {
rowIndexes.push(idx); rowIndexes.push(idx);
} }
} }
@@ -115,7 +118,9 @@ export const Computer = React.memo(() => {
searchSelection().then((rowIndexes) => { searchSelection().then((rowIndexes) => {
let rows = CompactSelection.empty(); let rows = CompactSelection.empty();
rowIndexes.forEach((r) => { rowIndexes.forEach((r) => {
if (r !== undefined) {
rows = rows.add(r); rows = rows.add(r);
}
}); });
setStateFN('_gridSelectionRows', () => { setStateFN('_gridSelectionRows', () => {
@@ -276,10 +281,8 @@ export const Computer = React.memo(() => {
const ready = getState('ready'); const ready = getState('ready');
if (ready && selectFirstRowOnMount) { if (ready && selectFirstRowOnMount) {
const scrollToRowKey = getState('scrollToRowKey'); const scrollToRowKey = getState('scrollToRowKey');
if (scrollToRowKey && scrollToRowKey >= 0) { if (scrollToRowKey && scrollToRowKey >= 0) {
return; return;
} }
@@ -299,7 +302,6 @@ export const Computer = React.memo(() => {
) { ) {
const values = [firstBuffer, ...(currentValues as Array<Record<string, unknown>>)]; const values = [firstBuffer, ...(currentValues as Array<Record<string, unknown>>)];
const onChange = getState('onChange'); const onChange = getState('onChange');
//console.log('Selecting first row:', firstRow, firstBuffer, values); //console.log('Selecting first row:', firstRow, firstBuffer, values);
if (onChange) { if (onChange) {
@@ -348,9 +350,10 @@ export const Computer = React.memo(() => {
const key = selectedRowKey ?? scrollToRowKey; const key = selectedRowKey ?? scrollToRowKey;
if (key && ref && ready) { if (key && ref && ready) {
//console.log('Computer:Scrolling to key:', key);
getRowIndexByKey?.(key).then((r) => { getRowIndexByKey?.(key).then((r) => {
if (r !== undefined) { if (r !== undefined) {
//console.log('Scrolling to selected row:', r, selectedRowKey, scrollToRowKey); console.log('Scrolling to selected row:', r, selectedRowKey, scrollToRowKey);
if (selectedRowKey) { if (selectedRowKey) {
const onChange = getState('onChange'); const onChange = getState('onChange');

View File

@@ -140,7 +140,7 @@ export interface GridlerState {
_visibleArea: Rectangle; _visibleArea: Rectangle;
_visiblePages: Rectangle; _visiblePages: Rectangle;
addError: (err: string, ...args: Array<any>) => void; addError: (err: string, ...args: Array<any>) => void;
askAPIRowNumber?: (key: string) => Promise<number>; askAPIRowNumber?: (key: string) => Promise<null | number>;
colFilters?: Array<FilterOption>; colFilters?: Array<FilterOption>;
colOrder?: Record<string, number>; colOrder?: Record<string, number>;
colSize?: Record<string, number>; colSize?: Record<string, number>;
@@ -162,7 +162,7 @@ export interface GridlerState {
hasLocalData: boolean; hasLocalData: boolean;
isEmpty: boolean; isEmpty: boolean;
isValuesInPages: () => 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;
@@ -191,7 +191,6 @@ export interface GridlerState {
freezeRegions?: readonly Rectangle[]; freezeRegions?: readonly Rectangle[];
selected?: Item; selected?: Item;
} }
) => void; ) => void;
pageSize: number; pageSize: number;
@@ -200,10 +199,7 @@ export interface GridlerState {
reload?: () => Promise<void>; reload?: () => Promise<void>;
renderColumns?: GridlerColumns; renderColumns?: GridlerColumns;
setState: <K extends keyof GridlerStoreState>( setState: <K extends keyof GridlerStoreState>(key: K, value: GridlerStoreState[K]) => void;
key: K,
value: GridlerStoreState[K]
) => void;
setStateFN: <K extends keyof GridlerStoreState>( setStateFN: <K extends keyof GridlerStoreState>(
key: K, key: K,
value: (current: GridlerStoreState[K]) => Partial<GridlerStoreState[K]> value: (current: GridlerStoreState[K]) => Partial<GridlerStoreState[K]>
@@ -357,7 +353,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
} }
} }
if (rowIndex > 0) { if (rowIndex > 0) {
console.log('Local row index', rowIndex, key); //console.log('Local row index', rowIndex, key);
return rowIndex; return rowIndex;
} }
} }
@@ -366,8 +362,8 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
return rowIndex; return rowIndex;
} else if (typeof state.askAPIRowNumber === 'function') { } else if (typeof state.askAPIRowNumber === 'function') {
const rn = await state.askAPIRowNumber(String(key)); const rn = await state.askAPIRowNumber(String(key));
if (rn && rn >= 0) { if (rn && rn >= 0) {
console.log('Remote row index', rowIndex, key);
return rn; return rn;
} }
} }
@@ -403,7 +399,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
} }
} }
return false return false;
}, },
keyField: 'id', keyField: 'id',
loadPage: async (pPage: number, clearMode?: 'all' | 'page') => { loadPage: async (pPage: number, clearMode?: 'all' | 'page') => {
@@ -488,13 +484,16 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
onCellClicked: (cell: Item, event: CellClickedEventArgs) => { onCellClicked: (cell: Item, event: CellClickedEventArgs) => {
const state = get(); const state = get();
const [col, row] = cell; const [col, row] = cell;
const rowBuffer = state.getRowBuffer(row);
if (state.glideProps?.onCellClicked) { if (state.glideProps?.onCellClicked) {
state.glideProps?.onCellClicked?.(cell, event); state.glideProps?.onCellClicked?.(cell, event);
} }
if (state.values?.length) { if (state.values?.length && state.values?.length > 0) {
if (state.onChange) { if (state.onChange) {
state.onChange(state.values); state.onChange(state.values);
} }
} else if (rowBuffer && state.onChange) {
state.onChange([rowBuffer]);
} }
state._events.dispatchEvent( state._events.dispatchEvent(
@@ -949,7 +948,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

@@ -83,7 +83,7 @@ function _GlidlerAPIAdaptorForGoLangv2<T = unknown>(props: GlidlerAPIAdaptorForG
) )
?.forEach((filter: any) => { ?.forEach((filter: any) => {
ops.push({ ops.push({
name: `${filter.id ?? ""}`, name: `${filter.id ?? ''}`,
op: 'contains', op: 'contains',
type: 'searchor', type: 'searchor',
value: searchStr, value: searchStr,
@@ -202,11 +202,13 @@ function _GlidlerAPIAdaptorForGoLangv2<T = unknown>(props: GlidlerAPIAdaptorForG
] ]
); );
const askAPIRowNumber: (key: string) => Promise<number> = useCallback( const askAPIRowNumber: (key: string) => Promise<null | number> = useCallback(
async (key: string) => { async (key: string) => {
const colFilters = getState('colFilters'); const colFilters = getState('colFilters');
if (!key) {
//console.log('APIAdaptorGoLangv2', { _active_requests, index, pageSize, props }); return null;
}
//console.log('APIAdaptorGoLangv2', { key, props });
if (props && props.url) { if (props && props.url) {
const head = new Headers(); const head = new Headers();
const ops: FetchAPIOperation[] = [ const ops: FetchAPIOperation[] = [
@@ -250,7 +252,7 @@ function _GlidlerAPIAdaptorForGoLangv2<T = unknown>(props: GlidlerAPIAdaptorForG
const controller = new AbortController(); const controller = new AbortController();
const res = await fetch(`${props.url}?x-fetch-rownumber=${key}}`, { const res = await fetch(`${props.url}?x-fetch-rownumber=${key}`, {
headers: head, headers: head,
method: 'GET', method: 'GET',
signal: controller?.signal, signal: controller?.signal,
@@ -293,8 +295,6 @@ 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);

View File

@@ -61,7 +61,7 @@ export function GlidlerFormAdaptor(props: {
col?: GridlerColumn, col?: GridlerColumn,
defaultItems?: MantineBetterMenuInstanceItem[] defaultItems?: MantineBetterMenuInstanceItem[]
): MantineBetterMenuInstanceItem[] => { ): MantineBetterMenuInstanceItem[] => {
//console.log('GlidlerFormInterface getMenuItems', id); //console.log('GlidlerFormInterface getMenuItems', id, row, defaultItems);
if (id === 'header-menu') { if (id === 'header-menu') {
return defaultItems || []; return defaultItems || [];
@@ -88,7 +88,7 @@ export function GlidlerFormAdaptor(props: {
? props.descriptionField(row) ? props.descriptionField(row)
: undefined; : undefined;
if (id === 'other') { if (id === 'other' || (id === 'cell' && !row)) {
items.push({ items.push({
c: 'blue', c: 'blue',
label: 'Add', label: 'Add',