/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import { t } from '@apache-superset/core/translation'; import { SupersetClient } from '@superset-ui/core'; import rison from 'rison'; import { Dispatch, SetStateAction } from 'react'; interface FetchPaginatedOptions { endpoint: string; pageSize?: number; setData: (data: any[]) => void; setLoadingState: Dispatch>; filters?: SupersetFilter[]; orderBy?: { column: string; direction: 'asc' | 'desc' }; loadingKey: string; addDangerToast: (message: string) => void; errorMessage?: string; mapResult?: (item: any) => any; } interface QueryObj { page_size: number; page: number; filters?: SupersetFilter[]; order_column?: string; order_direction?: 'asc' | 'desc'; } interface SupersetFilter { col: string; opr: string; value: string | number | (string | number)[]; } export const fetchPaginatedData = async ({ endpoint, pageSize = 100, setData, filters, orderBy, setLoadingState, loadingKey, addDangerToast, errorMessage = 'Error while fetching data', mapResult = (item: any) => item, }: FetchPaginatedOptions) => { try { const fetchPage = async (pageIndex: number) => { const queryObj: QueryObj = { page_size: pageSize, page: pageIndex, }; if (filters) { queryObj.filters = filters; } if (orderBy) { queryObj.order_column = orderBy.column; queryObj.order_direction = orderBy.direction; } const encodedQuery = rison.encode(queryObj); const response = await SupersetClient.get({ endpoint: `${endpoint}?q=${encodedQuery}`, }); return { count: response.json.count, results: response.json.result.map(mapResult), }; }; const initialResponse = await fetchPage(0); const totalItems = initialResponse.count; const firstPageResults = initialResponse.results; if (pageSize >= totalItems) { setData(firstPageResults); return; } const totalPages = Math.ceil(totalItems / pageSize); const requests = Array.from({ length: totalPages - 1 }, (_, i) => fetchPage(i + 1), ); const remainingResults = await Promise.all(requests); setData([ ...firstPageResults, ...remainingResults.flatMap(res => res.results), ]); } catch (err) { addDangerToast(t(errorMessage)); } finally { setLoadingState((prev: boolean | Record) => { if (typeof prev === 'boolean') { return false; } return { ...prev, [loadingKey]: false, }; }); } };