/* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useCallback, useEffect } from 'react'; import type { APIOptions } from '../../utils/types'; import type { GridlerColumn } from '../Column'; import { type FetchAPIOperation, GoAPIHeaders, type GoAPIOperation, } from '../../utils/golang-restapi-v2'; import { useGridlerStore } from '../GridlerStore'; export interface GlidlerAPIAdaptorForGoLangv2Props extends APIOptions { filter?: string; hotfields?: Array; initialData?: Array; options?: Array; } function _GlidlerAPIAdaptorForGoLangv2(props: GlidlerAPIAdaptorForGoLangv2Props) { const [setStateFN, setState, getState, addError, mounted] = useGridlerStore((s) => [ s.setStateFN, s.setState, s.getState, s.addError, s.mounted, ]); const useAPIQuery: (index: number) => Promise = useCallback( async (index: number) => { const columns = getState('columns'); const colSort = getState('colSort'); const pageSize = getState('pageSize'); const colFilters = getState('colFilters'); const searchStr = getState('searchStr'); const searchFields = getState('searchFields'); const _active_requests = getState('_active_requests'); setState('loadingData', true); try { //console.log('APIAdaptorGoLangv2', { _active_requests, index, pageSize, props }); if (props && props.url) { const head = new Headers(); head.set('Authorization', `Token ${props.authtoken}`); const ops: FetchAPIOperation[] = [ { type: 'limit', value: String(pageSize ?? 50) }, { type: 'offset', value: String((pageSize ?? 50) * index) }, ]; if (colSort?.length && colSort.length > 0) { ops.push({ type: 'sort', value: colSort ?.map((sort: any) => `${sort.id} ${sort.direction}`) .reduce((acc: any, val: any) => `${acc},${val}`), }); } colFilters ?.filter((f) => f.value?.length > 0) ?.forEach((filter: any) => { if (filter.value && filter.value !== '') { ops.push({ name: `${filter.id}`, op: filter.operator, type: 'searchop', value: filter.value, }); } }); if (searchStr && searchStr !== '') { columns ?.filter( (f) => !f.disableFilter && !f.disableSearch && !f.virtual && f.id && ((searchFields ?? []).length == 0 || searchFields?.includes(f.id)) ) ?.forEach((filter: any) => { ops.push({ name: `${filter.id ?? ""}`, op: 'contains', type: 'searchor', value: searchStr, }); }); } if (props.filter && props.filter !== '') { ops.push({ name: 'sql_filter', type: 'custom-sql-w', value: props.filter, }); } if ((props.options ?? []).length > 0) { ops.push(...(props.options ?? [])); } const col_ids = columns ?.filter((col) => !col.virtual) ?.map((col: GridlerColumn) => { return col.id; }) ?? []; if (props.hotfields && props.hotfields.length > 0) { col_ids?.push(props.hotfields.join(',')); } if (col_ids && col_ids.length > 0) { ops.push({ type: 'select-fields', value: col_ids.join(','), }); } if (ops && ops.length > 0) { const optionHeaders = GoAPIHeaders(ops); for (const oh in GoAPIHeaders(ops)) { head.set(oh, optionHeaders[oh]); } } const currentRequestIndex = _active_requests?.findIndex((f) => f.page === index) ?? -1; _active_requests?.forEach((r) => { if ((r.page >= 0 && r.page < index - 2) || (index >= 0 && r.page > index + 2)) { r.controller?.abort?.(); } }); if ( _active_requests && currentRequestIndex >= 0 && _active_requests[currentRequestIndex] ) { //console.log(`Already queued ${index}`, index, s._active_requests); setState('loadingData', false); return undefined; } const controller = new AbortController(); await setStateFN('_active_requests', (cv) => [ ...(cv ?? []), { controller, page: index }, ]); const res = await fetch( `${props.url}?x-limit=${String(pageSize ?? 50)}&x-offset=${String((pageSize ?? 50) * index)}`, { headers: head, method: 'GET', signal: controller?.signal, } ); if (res.ok) { const cr = res.headers.get('Content-Range')?.split('/'); if (cr?.[1] && parseInt(cr[1], 10) > 0) { setState('total_rows', parseInt(cr[1], 10)); } const data = await res.json(); setState('loadingData', false); return data ?? []; } addError(`${res.status} ${res.statusText}`, 'api', props.url); await setStateFN('_active_requests', (cv) => [ ...(cv ?? []).filter((f) => f.page !== index), ]); } // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (_e) { //console.log('APIAdaptorGoLangv2 error', e); //addError(`Error: ${e}`, 'api', props.url); } setState('loadingData', false); return []; }, [ getState, props.authtoken, props.url, props.filter, JSON.stringify(props.options), setState, setStateFN, addError, ] ); const askAPIRowNumber: (key: string) => Promise = useCallback( async (key: string) => { const colFilters = getState('colFilters'); //console.log('APIAdaptorGoLangv2', { _active_requests, index, pageSize, props }); if (props && props.url) { const head = new Headers(); const ops: FetchAPIOperation[] = [ { type: 'limit', value: String(10) }, { type: 'fetch-rownumber', value: key }, ]; head.set('Authorization', `Token ${props.authtoken}`); if (colFilters?.length && colFilters.length > 0) { colFilters ?.filter((f) => f.value?.length > 0) ?.forEach((filter: any) => { if (filter.value && filter.value !== '') { head.set(`x-searchop-${filter.operator}-${filter.id}`, `${filter.value}`); } }); } if (props.filter && props.filter !== '') { ops.push({ name: 'sql_filter', type: 'custom-sql-w', value: props.filter, }); } if (props.options && props.options.length > 0) { const optionHeaders = GoAPIHeaders(props.options); for (const oh in optionHeaders) { head.set(oh, optionHeaders[oh]); } } if (ops && ops.length > 0) { const optionHeaders = GoAPIHeaders(ops); for (const oh in GoAPIHeaders(ops)) { head.set(oh, optionHeaders[oh]); } } const controller = new AbortController(); const res = await fetch(`${props.url}?x-fetch-rownumber=${key}}`, { headers: head, method: 'GET', signal: controller?.signal, }); if (res.ok) { const data = await res.json(); return data?.[0]?._rownumber ?? data?._rownumber ?? 0; } addError(`${res.status} ${res.statusText}`, 'api', props.url); } return []; }, [props.url, props.authtoken, props.filter, props.options, getState, addError] ); //Reset the function in the store. useEffect(() => { setState('useAPIQuery', useAPIQuery); setState('askAPIRowNumber', askAPIRowNumber); const _refresh = getState('_refresh'); //Reset the loaded pages to new rules _refresh?.().then(() => { const onChange = getState('onChange'); const getGridSelectedRows = getState('getGridSelectedRows'); if (onChange && typeof onChange === 'function') { const buffers = getGridSelectedRows?.(); onChange(buffers); } }); }, [props.url, props.authtoken, props.filter, JSON.stringify(props.options), mounted, setState]); return <>; } //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); GlidlerAPIAdaptorForGoLangv2.displayName = 'Gridler-GlidlerAPIAdaptorForGoLangv2';