From 0c7696de3a2c2e994f470aad0e23d20aebfe72db Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 12 Sep 2023 08:37:18 +0300 Subject: [PATCH] Make it a component --- packages/ts/react-grid/src/autogrid.tsx | 116 ++++++++++-------- packages/ts/react-grid/src/crud.ts | 2 +- packages/ts/react-grid/test/autogrid.spec.tsx | 32 +++-- 3 files changed, 82 insertions(+), 68 deletions(-) diff --git a/packages/ts/react-grid/src/autogrid.tsx b/packages/ts/react-grid/src/autogrid.tsx index 00976b608d..a916ac0460 100644 --- a/packages/ts/react-grid/src/autogrid.tsx +++ b/packages/ts/react-grid/src/autogrid.tsx @@ -1,8 +1,14 @@ import type { ModelConstructor } from '@hilla/form'; -import type { GridDataProviderCallback, GridDataProviderParams, GridElement } from '@hilla/react-components/Grid.js'; +import { + Grid, + GridProps, + type GridDataProviderCallback, + type GridDataProviderParams, + type GridElement, +} from '@hilla/react-components/Grid.js'; import { GridSortColumn } from '@hilla/react-components/GridSortColumn.js'; import { useEffect, useRef } from 'react'; -import type { CrudEndpoint } from './crud'; +import type { CrudService } from './crud'; import { getProperties } from './modelutil.js'; // import Sort from "Frontend/generated/dev/hilla/mappedtypes/Sort"; @@ -13,54 +19,57 @@ enum Direction { DESC = 'DESC', } -export const useAutoGrid = (endpoint: CrudEndpoint, itemType: ModelConstructor) => { - const listMethod = endpoint.list; - const ref = useRef(null); - - useEffect(() => { - const grid = ref.current as any as GridElement; +export type _AutoGridProps = { + service: CrudService; + model: ModelConstructor; +}; +export type AutoGridProps = GridProps & _AutoGridProps; - let first = true; +const createDataProvider = (grid: GridElement, service: CrudService) => { + const listMethod = service.list; + let first = true; - grid.dataProvider = async (params: GridDataProviderParams, callback: GridDataProviderCallback) => { - const sort: Sort = { - orders: params.sortOrders.map((order) => ({ - property: order.path, - direction: order.direction == 'asc' ? Direction.ASC : Direction.DESC, - ignoreCase: false, - })), - }; + return async (params: GridDataProviderParams, callback: GridDataProviderCallback) => { + const sort: Sort = { + orders: params.sortOrders.map((order) => ({ + property: order.path, + direction: order.direction == 'asc' ? Direction.ASC : Direction.DESC, + ignoreCase: false, + })), + }; - const pageNumber = params.page; - const pageSize = params.pageSize; - const req = { - pageNumber, - pageSize, - sort, - }; + const pageNumber = params.page; + const pageSize = params.pageSize; + const req = { + pageNumber, + pageSize, + sort, + }; - const items = await listMethod(req); - let size; - if (items.length === pageSize) { - size = (pageNumber + 1) * pageSize + 1; - if (size < (grid as any)._cache.size) { - // Only allow size to grow here to avoid shrinking the size when scrolled down and sorting - size = undefined; - } - } else { - size = pageNumber * pageSize + items.length; + const items = await listMethod(req); + let size; + if (items.length === pageSize) { + size = (pageNumber + 1) * pageSize + 1; + if (size < (grid as any)._cache.size) { + // Only allow size to grow here to avoid shrinking the size when scrolled down and sorting + size = undefined; } - callback(items, size); - if (first) { - // Workaround for https://github.com/vaadin/react-components/issues/129 - first = false; - setTimeout(() => grid.recalculateColumnWidths(), 0); - } - }; - }, []); + } else { + size = pageNumber * pageSize + items.length; + } + callback(items, size); + if (first) { + // Workaround for https://github.com/vaadin/react-components/issues/129 + first = false; + setTimeout(() => grid.recalculateColumnWidths(), 0); + } + }; +}; - const properties = getProperties(itemType); - const children = properties.map((p) => { +const createColumns = (model: ModelConstructor) => { + const properties = getProperties(model); + + const columns = properties.map((p) => { let customProps: any = { autoWidth: true }; let column = ( @@ -69,9 +78,18 @@ export const useAutoGrid = (endpoint: CrudEndpoint, itemType: ModelConstr return column; }); - - return { - ref, - children: [...children], - }; + return columns; }; + +export function AutoGrid(props: AutoGridProps) { + const ref = useRef(null); + + useEffect(() => { + const grid = ref.current as any as GridElement; + grid.dataProvider = createDataProvider(grid, props.service); + }, []); + + const children = createColumns(props.model); + + return ; +} diff --git a/packages/ts/react-grid/src/crud.ts b/packages/ts/react-grid/src/crud.ts index 33b52f90cc..269de46203 100644 --- a/packages/ts/react-grid/src/crud.ts +++ b/packages/ts/react-grid/src/crud.ts @@ -1,6 +1,6 @@ import Pageable from './types/Pageable'; -export interface CrudEndpoint { +export interface CrudService { list: { (request: Pageable): Promise; }; diff --git a/packages/ts/react-grid/test/autogrid.spec.tsx b/packages/ts/react-grid/test/autogrid.spec.tsx index 7be8ecbd7b..f340876edc 100644 --- a/packages/ts/react-grid/test/autogrid.spec.tsx +++ b/packages/ts/react-grid/test/autogrid.spec.tsx @@ -1,17 +1,16 @@ import { expect, use } from '@esm-bundle/chai'; -import { Grid, GridElement } from '@hilla/react-components/Grid.js'; +import { GridElement } from '@hilla/react-components/Grid.js'; import { render } from '@testing-library/react'; -import sinon from 'sinon'; import sinonChai from 'sinon-chai'; -import { useAutoGrid as _useAutoGrid } from '../src/autogrid.js'; -import type { CrudEndpoint } from '../src/crud.js'; +import { AutoGrid } from '../src/autogrid.js'; +import type { CrudService } from '../src/crud.js'; import Pageable from '../src/types/Pageable.js'; import { Person, PersonModel } from './TestModels.js'; //@ts-ignore -import { getRowBodyCells, getBodyCellContent, getRows, getCellContent } from './grid-test-utils.js'; +import { getBodyCellContent } from './grid-test-utils.js'; use(sinonChai); -const fakeEndpoint: CrudEndpoint = { +const fakeService: CrudService = { list: async (request: Pageable): Promise => { const data: Person[] = [ { firstName: 'John', lastName: 'Dove' }, @@ -33,20 +32,20 @@ async function sleep(ms: number) { ); } describe('@hilla/react-grid', () => { - type UseAutoGridSpy = sinon.SinonSpy, ReturnType>; - const useAutoGrid = sinon.spy(_useAutoGrid) as typeof _useAutoGrid; + // type UseAutoGridSpy = sinon.SinonSpy, ReturnType>; + // const useAutoGrid = sinon.spy(_useAutoGrid) as typeof _useAutoGrid; beforeEach(() => { - (useAutoGrid as UseAutoGridSpy).resetHistory(); + // (useAutoGrid as UseAutoGridSpy).resetHistory(); }); - function AutoGrid() { - const autoGrid = useAutoGrid(fakeEndpoint, PersonModel); - return ; + function TestAutoGrid() { + // const autoGrid = useAutoGrid(fakeEndpoint, PersonModel); + return ; } describe('useAutoGrid', () => { it('creates columns based on model', async () => { - const result = render(); + const result = render(); const columns = result.container.querySelectorAll('vaadin-grid-sort-column'); expect(columns.length).to.equal(2); expect(columns[0].path).to.equal('firstName'); @@ -55,12 +54,12 @@ describe('@hilla/react-grid', () => { expect(columns[1].header).to.equal('Last name'); }); it('sets a data provider', async () => { - const result = render(); + const result = render(); const grid = result.container.querySelector('vaadin-grid'); expect(grid?.dataProvider).to.not.be.undefined; }); it('data provider provides data', async () => { - const result = render(); + const result = render(); const grid: GridElement = result.container.querySelector('vaadin-grid')!; grid.requestContentUpdate(); await sleep(1); @@ -72,6 +71,3 @@ describe('@hilla/react-grid', () => { }); }); }); -function getBodyCellText(grid: GridElement, row: number, col: number): any { - return getCellContent(getRowBodyCells(getRows(grid.shadowRoot)[row])[col]).innerText; -}