UNPKG

@vaadin/hilla-react-crud

Version:

Hilla CRUD utils for React

200 lines 6.74 kB
import { useMemo, useState } from 'react'; import Direction from './types/org/springframework/data/domain/Sort/Direction.js'; import NullHandling from './types/org/springframework/data/domain/Sort/NullHandling.js'; function createSort(params) { return { orders: params.sortOrders .filter((order) => order.direction != null) .map((order) => ({ property: order.path, direction: order.direction === 'asc' ? Direction.ASC : Direction.DESC, ignoreCase: false, nullHandling: NullHandling.NATIVE, })), }; } export function isCountService(service) { return !!service.count; } export class DataProvider { service; loadTotalCount; afterLoadCallback; filter; totalCount; filteredCount; constructor(service, options = {}) { this.service = service; this.filter = options.initialFilter; this.loadTotalCount = options.loadTotalCount; this.afterLoadCallback = options.afterLoad; this.load = this.load.bind(this); } reset() { this.totalCount = undefined; this.filteredCount = undefined; } setFilter(filter) { this.reset(); this.filter = filter; } async load(params, callback) { const page = await this.fetchPage(params); this.filteredCount = await this.fetchFilteredCount(page); if (this.loadTotalCount) { this.totalCount = await this.fetchTotalCount(page); } callback(page.items, this.filteredCount); if (this.afterLoadCallback) { this.afterLoadCallback({ totalCount: this.totalCount, filteredCount: this.filteredCount, }); } } async fetchPage(params) { const sort = createSort(params); const pageNumber = params.page; const { pageSize } = params; const pageRequest = { pageNumber, pageSize, sort, }; const items = await this.service.list(pageRequest, this.filter); return { items, pageRequest }; } } export class AbstractComboBoxDataProvider { list; loadTotalCount; sort; totalCount; filteredCount; constructor(list, sort) { this.list = list; this.sort = sort; } reset() { this.totalCount = undefined; this.filteredCount = undefined; } load(params, callback) { this.fetchPage(params) .then(async (page) => { this.filteredCount = await this.fetchFilteredCount(page); if (this.loadTotalCount) { this.totalCount = await this.fetchTotalCount(page); } callback(page.items, this.filteredCount); }) .catch((error) => { throw error; }); } async fetchPage(params) { const pageNumber = params.page; const { pageSize } = params; const pageRequest = { pageNumber, pageSize, sort: this.sort ?? { orders: [] }, }; const items = await this.list(pageRequest, params.filter); return { items, pageRequest }; } } function determineInfiniteScrollingSize(page, lastKnownSize) { const { items, pageRequest } = page; const { pageNumber, pageSize } = pageRequest; let infiniteScrollingSize; if (items.length === pageSize) { infiniteScrollingSize = (pageNumber + 1) * pageSize + 1; if (lastKnownSize !== undefined && infiniteScrollingSize < lastKnownSize) { infiniteScrollingSize = lastKnownSize; } } else { infiniteScrollingSize = pageNumber * pageSize + items.length; } return infiniteScrollingSize; } export class InfiniteDataProvider extends DataProvider { fetchTotalCount() { return undefined; } fetchFilteredCount(page) { return determineInfiniteScrollingSize(page, this.filteredCount); } } export class InfiniteComboBoxDataProvider extends AbstractComboBoxDataProvider { fetchTotalCount() { return undefined; } fetchFilteredCount(page) { return determineInfiniteScrollingSize(page, this.filteredCount); } } export class FixedSizeDataProvider extends DataProvider { constructor(service, options = {}) { if (!isCountService(service)) { throw new Error('The provided service does not implement the CountService interface.'); } super(service, options); } async fetchTotalCount() { if (this.totalCount !== undefined) { return this.totalCount; } return this.service.count(undefined); } async fetchFilteredCount() { if (this.filteredCount !== undefined) { return this.filteredCount; } return this.service.count(this.filter); } } export function createDataProvider(service, options = {}) { if (isCountService(service)) { return new FixedSizeDataProvider(service, options); } return new InfiniteDataProvider(service, options); } export function useDataProvider(service, filter) { const [refreshCounter, setRefreshCounter] = useState(0); const dataProvider = useMemo(() => createDataProvider(service, { initialFilter: filter }), [service]); dataProvider.setFilter(filter); const dataProviderFn = useMemo(() => dataProvider.load.bind(dataProvider), [dataProvider, filter, refreshCounter]); return { dataProvider: dataProviderFn, refresh: () => { dataProvider.reset(); setRefreshCounter(refreshCounter + 1); }, }; } export function useGridDataProvider(fetch, dependencies) { const result = useDataProvider(useMemo(() => ({ list: async (pageable) => fetch(pageable), }), dependencies ?? [])); const dataProvider = result.dataProvider; dataProvider.refresh = result.refresh; return dataProvider; } function createComboBoxDataProvider(list, sort) { return new InfiniteComboBoxDataProvider(list, sort); } export function useComboBoxDataProvider(fetch, options, dependencies) { const [refreshCounter, setRefreshCounter] = useState(0); const dataProvider = useMemo(() => createComboBoxDataProvider(fetch, options?.sort), [options?.sort, ...(dependencies ?? [])]); return useMemo(() => { const dataProviderWithRefresh = (...args) => dataProvider.load(...args); dataProviderWithRefresh.refresh = () => { dataProvider.reset(); setRefreshCounter(refreshCounter + 1); }; return dataProviderWithRefresh; }, [dataProvider, refreshCounter]); } //# sourceMappingURL=data-provider.js.map